9a51ea0f46
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.
168 lines
4.1 KiB
Go
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")
|
|
})
|
|
}
|