File: ls_files.go

package info (click to toggle)
git-lfs 3.6.1-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 4,808 kB
  • sloc: sh: 21,256; makefile: 507; ruby: 417
file content (100 lines) | stat: -rw-r--r-- 2,126 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
package git

import (
	"bufio"
	"io"
	"path"
	"strings"

	"github.com/git-lfs/git-lfs/v3/errors"
	"github.com/git-lfs/git-lfs/v3/tools"
	"github.com/git-lfs/git-lfs/v3/tr"
	"github.com/rubyist/tracerx"
)

type lsFileInfo struct {
	BaseName string
	FullPath string
}
type LsFiles struct {
	Files       map[string]*lsFileInfo
	FilesByName map[string][]*lsFileInfo
}

func NewLsFiles(workingDir string, standardExclude bool, untracked bool) (*LsFiles, error) {

	args := []string{
		"ls-files",
		"-z", // Use a NUL separator. This also disables the escaping of special characters.
		"--cached",
	}

	if IsGitVersionAtLeast("2.35.0") {
		args = append(args, "--sparse")
	}

	if standardExclude {
		args = append(args, "--exclude-standard")
	}
	if untracked {
		args = append(args, "--others")
	}
	cmd, err := gitNoLFS(args...)
	if err != nil {
		return nil, err
	}
	cmd.Dir = workingDir

	tracerx.Printf("NewLsFiles: running in %s git %s",
		workingDir, strings.Join(args, " "))

	// Capture stdout and stderr
	stdout, err := cmd.StdoutPipe()
	if err != nil {
		return nil, err
	}
	stderr, err := cmd.StderrPipe()
	if err != nil {
		return nil, err
	}

	scanner := bufio.NewScanner(stdout)
	scanner.Split(tools.SplitOnNul)

	if err := cmd.Start(); err != nil {
		return nil, err
	}

	rv := &LsFiles{
		Files:       make(map[string]*lsFileInfo),
		FilesByName: make(map[string][]*lsFileInfo),
	}

	// Setup a goroutine to drain stderr as large amounts of error output may cause
	// the subprocess to block.
	errorMessages := make(chan []byte)
	go func() {
		msg, _ := io.ReadAll(stderr)
		errorMessages <- msg
	}()

	// Read all files
	for scanner.Scan() {
		base := path.Base(scanner.Text())
		finfo := &lsFileInfo{
			BaseName: base,
			FullPath: scanner.Text(),
		}
		rv.Files[scanner.Text()] = finfo
		rv.FilesByName[base] = append(rv.FilesByName[base], finfo)
	}

	// Check the output of the subprocess, output stderr if the command failed.
	msg := <-errorMessages
	if err := cmd.Wait(); err != nil {
		return nil, errors.New(tr.Tr.Get("Error in `git %s`: %v %s",
			strings.Join(args, " "), err, msg))
	}

	return rv, nil
}