From 44832addfe40f82dc3b1051d783bcf4966d6ccbc Mon Sep 17 00:00:00 2001 From: rick olson Date: Thu, 2 Nov 2017 12:33:57 -0600 Subject: [PATCH] commands: extract refUpdate type --- commands/command_pre_push.go | 34 ++++++++--- commands/command_push.go | 109 +++++++++++++++++++---------------- commands/refs.go | 53 +++++++++++++++++ commands/uploader.go | 21 ++----- 4 files changed, 140 insertions(+), 77 deletions(-) create mode 100644 commands/refs.go diff --git a/commands/command_pre_push.go b/commands/command_pre_push.go index 2ca034f5..5971a4b1 100644 --- a/commands/command_pre_push.go +++ b/commands/command_pre_push.go @@ -2,6 +2,7 @@ package commands import ( "bufio" + "io" "os" "strings" @@ -50,20 +51,38 @@ func prePushCommand(cmd *cobra.Command, args []string) { Exit("Invalid remote name %q: %s", args[0], err) } + updates := prePushRefs(os.Stdin) ctx := newUploadContext(prePushDryRun) - gitscanner, err := ctx.buildGitScanner() if err != nil { ExitWithError(err) } defer gitscanner.Close() - // We can be passed multiple lines of refs - scanner := bufio.NewScanner(os.Stdin) + for _, update := range updates { + if err := uploadLeftOrAll(gitscanner, ctx, update); err != nil { + Print("Error scanning for Git LFS files in %+v", update.Left()) + ExitWithError(err) + } + } + ctx.Await() +} + +// prePushRefs parses commit information that the pre-push git hook receives: +// +// +// +// Each line describes a proposed update of the remote ref at the remote sha to +// the local sha. Multiple updates can be received on multiple lines (such as +// from 'git push --all'). These updates are typically received over STDIN. +func prePushRefs(r io.Reader) []*refUpdate { + scanner := bufio.NewScanner(r) + refs := make([]*refUpdate, 0, 1) + + // We can be passed multiple lines of refs for scanner.Scan() { line := strings.TrimSpace(scanner.Text()) - if len(line) == 0 { continue } @@ -75,13 +94,10 @@ func prePushCommand(cmd *cobra.Command, args []string) { continue } - if err := uploadLeftOrAll(gitscanner, ctx, left, right); err != nil { - Print("Error scanning for Git LFS files in %+v", left) - ExitWithError(err) - } + refs = append(refs, newRefUpdate(cfg.Git, left, right)) } - ctx.Await() + return refs } // decodeRefs pulls the sha1s out of the line read from the pre-push diff --git a/commands/command_push.go b/commands/command_push.go index dce88bcf..c3f71fde 100644 --- a/commands/command_push.go +++ b/commands/command_push.go @@ -19,6 +19,46 @@ var ( // shares some global vars and functions with command_pre_push.go ) +// pushCommand pushes local objects to a Git LFS server. It takes two +// arguments: +// +// ` ` +// +// Remote must be a remote name, not a URL +// +// pushCommand calculates the git objects to send by comparing the range +// of commits between the local and remote git servers. +func pushCommand(cmd *cobra.Command, args []string) { + if len(args) == 0 { + Print("Specify a remote and a remote branch name (`git lfs push origin master`)") + os.Exit(1) + } + + requireGitVersion() + + // Remote is first arg + if err := cfg.SetValidRemote(args[0]); err != nil { + Exit("Invalid remote name %q: %s", args[0], err) + } + + ctx := newUploadContext(pushDryRun) + if pushObjectIDs { + if len(args) < 2 { + Print("Usage: git lfs push --object-id [lfs-object-id] ...") + return + } + + uploadsWithObjectIDs(ctx, args[1:]) + } else { + if len(args) < 1 { + Print("Usage: git lfs push --dry-run [ref]") + return + } + + uploadsBetweenRefAndRemote(ctx, args[1:]) + } +} + func uploadsBetweenRefAndRemote(ctx *uploadContext, refnames []string) { tracerx.Printf("Upload refs %v to remote %v", refnames, ctx.Remote) @@ -28,15 +68,15 @@ func uploadsBetweenRefAndRemote(ctx *uploadContext, refnames []string) { } defer gitscanner.Close() - refs, err := refsByNames(refnames) + updates, err := lfsPushRefs(refnames, pushAll) if err != nil { Error(err.Error()) Exit("Error getting local refs.") } - for _, ref := range refs { - if err = uploadLeftOrAll(gitscanner, ctx, ref, nil); err != nil { - Print("Error scanning for Git LFS files in the %q ref", ref.Name) + for _, update := range updates { + if err = uploadLeftOrAll(gitscanner, ctx, update); err != nil { + Print("Error scanning for Git LFS files in the %q ref", update.Left().Name) ExitWithError(err) } } @@ -68,14 +108,21 @@ func uploadsWithObjectIDs(ctx *uploadContext, oids []string) { ctx.Await() } -func refsByNames(refnames []string) ([]*git.Ref, error) { +// lfsPushRefs returns valid ref updates from the given ref and --all arguments. +// Either one or more refs can be explicitly specified, or --all indicates all +// local refs are pushed. +func lfsPushRefs(refnames []string, pushAll bool) ([]*refUpdate, error) { localrefs, err := git.LocalRefs() if err != nil { return nil, err } if pushAll && len(refnames) == 0 { - return localrefs, nil + refs := make([]*refUpdate, len(localrefs)) + for i, lr := range localrefs { + refs[i] = newRefUpdate(cfg.Git, lr, nil) + } + return refs, nil } reflookup := make(map[string]*git.Ref, len(localrefs)) @@ -83,59 +130,19 @@ func refsByNames(refnames []string) ([]*git.Ref, error) { reflookup[ref.Name] = ref } - refs := make([]*git.Ref, len(refnames)) + refs := make([]*refUpdate, len(refnames)) for i, name := range refnames { - if ref, ok := reflookup[name]; ok { - refs[i] = ref + if left, ok := reflookup[name]; ok { + refs[i] = newRefUpdate(cfg.Git, left, nil) } else { - refs[i] = &git.Ref{Name: name, Type: git.RefTypeOther, Sha: name} + left := &git.Ref{Name: name, Type: git.RefTypeOther, Sha: name} + refs[i] = newRefUpdate(cfg.Git, left, nil) } } return refs, nil } -// pushCommand pushes local objects to a Git LFS server. It takes two -// arguments: -// -// ` ` -// -// Remote must be a remote name, not a URL -// -// pushCommand calculates the git objects to send by comparing the range -// of commits between the local and remote git servers. -func pushCommand(cmd *cobra.Command, args []string) { - if len(args) == 0 { - Print("Specify a remote and a remote branch name (`git lfs push origin master`)") - os.Exit(1) - } - - requireGitVersion() - - // Remote is first arg - if err := cfg.SetValidRemote(args[0]); err != nil { - Exit("Invalid remote name %q: %s", args[0], err) - } - - ctx := newUploadContext(pushDryRun) - - if pushObjectIDs { - if len(args) < 2 { - Print("Usage: git lfs push --object-id [lfs-object-id] ...") - return - } - - uploadsWithObjectIDs(ctx, args[1:]) - } else { - if len(args) < 1 { - Print("Usage: git lfs push --dry-run [ref]") - return - } - - uploadsBetweenRefAndRemote(ctx, args[1:]) - } -} - func init() { RegisterCommand("push", pushCommand, func(cmd *cobra.Command) { cmd.Flags().BoolVarP(&pushDryRun, "dry-run", "d", false, "Do everything except actually send the updates") diff --git a/commands/refs.go b/commands/refs.go new file mode 100644 index 00000000..9c46c8c6 --- /dev/null +++ b/commands/refs.go @@ -0,0 +1,53 @@ +package commands + +import ( + "fmt" + + "github.com/git-lfs/git-lfs/config" + "github.com/git-lfs/git-lfs/git" +) + +type refUpdate struct { + git config.Environment + left *git.Ref + right *git.Ref +} + +func newRefUpdate(g config.Environment, l, r *git.Ref) *refUpdate { + return &refUpdate{ + git: g, + left: l, + right: r, + } +} + +func (u *refUpdate) Left() *git.Ref { + return u.left +} + +func (u *refUpdate) LeftCommitish() string { + return refCommitish(u.Left()) +} + +func (u *refUpdate) Right() *git.Ref { + if u.right == nil { + l := u.Left() + if merge, ok := u.git.Get(fmt.Sprintf("branch.%s.merge", l.Name)); ok { + u.right = git.ParseRef(merge, "") + } else { + u.right = &git.Ref{Name: l.Name} + } + } + return u.right +} + +func (u *refUpdate) RightCommitish() string { + return refCommitish(u.Right()) +} + +func refCommitish(r *git.Ref) string { + if len(r.Sha) > 0 { + return r.Sha + } + return r.Name +} diff --git a/commands/uploader.go b/commands/uploader.go index e275f027..a7616f28 100644 --- a/commands/uploader.go +++ b/commands/uploader.go @@ -9,7 +9,6 @@ import ( "sync" "github.com/git-lfs/git-lfs/errors" - "github.com/git-lfs/git-lfs/git" "github.com/git-lfs/git-lfs/lfs" "github.com/git-lfs/git-lfs/progress" "github.com/git-lfs/git-lfs/tools" @@ -17,26 +16,14 @@ import ( "github.com/rubyist/tracerx" ) -func uploadLeftOrAll(g *lfs.GitScanner, ctx *uploadContext, left, right *git.Ref) error { - leftName := left.Name - if len(left.Sha) > 0 { - leftName = left.Sha - } - +func uploadLeftOrAll(g *lfs.GitScanner, ctx *uploadContext, update *refUpdate) error { if pushAll { - if err := g.ScanRefWithDeleted(leftName, nil); err != nil { + if err := g.ScanRefWithDeleted(update.LeftCommitish(), nil); err != nil { return err } } else { - if right == nil { - if merge, ok := cfg.Git.Get(fmt.Sprintf("branch.%s.merge", left.Name)); ok { - right = git.ParseRef(merge, "") - } else { - right = &git.Ref{Name: left.Name} - } - } - tracerx.Printf("DEBUG LEFT to RIGHT: %+v => %+v", left, right) - if err := g.ScanLeftToRemote(leftName, nil); err != nil { + tracerx.Printf("DEBUG LEFT to RIGHT: %+v => %+v", update.Left(), update.Right()) + if err := g.ScanLeftToRemote(update.LeftCommitish(), nil); err != nil { return err } }