git-lfs/commands/command_ls_files.go
brian m. carlson 9a51ea0f46
Pass environment variables into object scanner
We're going to need the environment variables in the object scanner, so
pass the appropriate Environment instance down into the object scanner.
Use an interface to avoid an import loop between the git and config
packages.

Note that the environment is not yet used, but will be in a future
commit.
2019-08-15 17:39:32 +00:00

168 lines
4.1 KiB
Go

package commands
import (
"os"
"strings"
"github.com/git-lfs/git-lfs/git"
"github.com/git-lfs/git-lfs/lfs"
"github.com/git-lfs/git-lfs/tools/humanize"
"github.com/spf13/cobra"
)
var (
longOIDs = false
lsFilesScanAll = false
lsFilesScanDeleted = false
lsFilesShowSize = false
lsFilesShowNameOnly = false
debug = false
)
func lsFilesCommand(cmd *cobra.Command, args []string) {
requireInRepo()
var ref string
var otherRef string
var scanRange = false
if len(args) > 0 {
if lsFilesScanAll {
Exit("fatal: cannot use --all with explicit reference")
} else if args[0] == "--all" {
// Since --all is a valid argument to "git rev-parse",
// if we try to give it to git.ResolveRef below, we'll
// get an unexpected result.
//
// So, let's check early that the caller invoked the
// command correctly.
Exit("fatal: did you mean \"git lfs ls-files --all --\" ?")
}
ref = args[0]
if len(args) > 1 {
if lsFilesScanDeleted {
Exit("fatal: cannot use --deleted with reference range")
}
otherRef = args[1]
scanRange = true
}
} else {
fullref, err := git.CurrentRef()
if err != nil {
ref = git.RefBeforeFirstCommit
} else {
ref = fullref.Sha
}
}
showOidLen := 10
if longOIDs {
showOidLen = 64
}
seen := make(map[string]struct{})
gitscanner := lfs.NewGitScanner(cfg, func(p *lfs.WrappedPointer, err error) {
if err != nil {
Exit("Could not scan for Git LFS tree: %s", err)
return
}
if !lsFilesScanAll && !scanRange {
if _, ok := seen[p.Name]; ok {
return
}
}
if debug {
Print(
"filepath: %s\n"+
" size: %d\n"+
"checkout: %v\n"+
"download: %v\n"+
" oid: %s %s\n"+
" version: %s\n",
p.Name,
p.Size,
fileExistsOfSize(p),
cfg.LFSObjectExists(p.Oid, p.Size),
p.OidType,
p.Oid,
p.Version)
} else {
msg := []string{p.Oid[:showOidLen], lsFilesMarker(p), p.Name}
if lsFilesShowNameOnly {
msg = []string{p.Name}
}
if lsFilesShowSize {
size := humanize.FormatBytes(uint64(p.Size))
msg = append(msg, "("+size+")")
}
Print(strings.Join(msg, " "))
}
seen[p.Name] = struct{}{}
})
defer gitscanner.Close()
includeArg, excludeArg := getIncludeExcludeArgs(cmd)
gitscanner.Filter = buildFilepathFilter(cfg, includeArg, excludeArg)
if len(args) == 0 {
// Only scan the index when "git lfs ls-files" was invoked with
// no arguments.
//
// Do so to avoid showing "mixed" results, e.g., ls-files output
// from a specific historical revision, and the index.
if err := gitscanner.ScanIndex(ref, nil); err != nil {
Exit("Could not scan for Git LFS index: %s", err)
}
}
if lsFilesScanAll {
if err := gitscanner.ScanAll(nil); err != nil {
Exit("Could not scan for Git LFS history: %s", err)
}
} else {
var err error
if lsFilesScanDeleted {
err = gitscanner.ScanRefWithDeleted(ref, nil)
} else if scanRange {
err = gitscanner.ScanRefRange(otherRef, ref, nil)
} else {
err = gitscanner.ScanTree(ref)
}
if err != nil {
Exit("Could not scan for Git LFS tree: %s", err)
}
}
}
// Returns true if a pointer appears to be properly smudge on checkout
func fileExistsOfSize(p *lfs.WrappedPointer) bool {
path := cfg.Filesystem().DecodePathname(p.Name)
info, err := os.Stat(path)
return err == nil && info.Size() == p.Size
}
func lsFilesMarker(p *lfs.WrappedPointer) string {
if fileExistsOfSize(p) {
return "*"
}
return "-"
}
func init() {
RegisterCommand("ls-files", lsFilesCommand, func(cmd *cobra.Command) {
cmd.Flags().BoolVarP(&longOIDs, "long", "l", false, "")
cmd.Flags().BoolVarP(&lsFilesShowSize, "size", "s", false, "")
cmd.Flags().BoolVarP(&lsFilesShowNameOnly, "name-only", "n", false, "")
cmd.Flags().BoolVarP(&debug, "debug", "d", false, "")
cmd.Flags().BoolVarP(&lsFilesScanAll, "all", "a", false, "")
cmd.Flags().BoolVar(&lsFilesScanDeleted, "deleted", false, "")
cmd.Flags().StringVarP(&includeArg, "include", "I", "", "Include a list of paths")
cmd.Flags().StringVarP(&excludeArg, "exclude", "X", "", "Exclude a list of paths")
})
}