forked from git-lfs/git-lfs
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcommand_smudge.go
186 lines (159 loc) · 5.65 KB
/
command_smudge.go
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
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
package commands
import (
"fmt"
"io"
"os"
"github.com/git-lfs/git-lfs/v3/errors"
"github.com/git-lfs/git-lfs/v3/filepathfilter"
"github.com/git-lfs/git-lfs/v3/git"
"github.com/git-lfs/git-lfs/v3/lfs"
"github.com/git-lfs/git-lfs/v3/tools"
"github.com/git-lfs/git-lfs/v3/tools/humanize"
"github.com/git-lfs/git-lfs/v3/tq"
"github.com/git-lfs/git-lfs/v3/tr"
"github.com/spf13/cobra"
)
var (
// smudgeSkip is a command-line flag belonging to the "git-lfs smudge"
// command specifying whether to skip the smudge process.
smudgeSkip = false
)
// delayedSmudge performs a 'delayed' smudge, adding the LFS pointer to the
// `*tq.TransferQueue` "q" if the file is not present locally, passes the given
// filepathfilter, and is not skipped. If the pointer is malformed, or already
// exists, it streams the contents to be written into the working copy to "to".
//
// delayedSmudge returns the number of bytes written, whether the checkout was
// delayed, the *lfs.Pointer that was smudged, and an error, if one occurred.
func delayedSmudge(gf *lfs.GitFilter, s *git.FilterProcessScanner, to io.Writer, from io.Reader, q *tq.TransferQueue, filename string, skip bool, filter *filepathfilter.Filter) (int64, bool, *lfs.Pointer, error) {
ptr, pbuf, perr := lfs.DecodeFrom(from)
if perr != nil {
// Write 'statusFromErr(nil)', even though 'perr != nil', since
// we are about to write non-delayed smudged contents to "to".
if err := s.WriteStatus(statusFromErr(nil)); err != nil {
return 0, false, nil, err
}
n, err := tools.Spool(to, pbuf, cfg.TempDir())
if err != nil {
return n, false, nil, errors.Wrap(err, perr.Error())
}
if n != 0 {
return 0, false, nil, errors.NewNotAPointerError(errors.Errorf(
tr.Tr.Get("Unable to parse pointer at: %q", filename),
))
}
return 0, false, nil, nil
}
lfs.LinkOrCopyFromReference(cfg, ptr.Oid, ptr.Size)
path, err := cfg.Filesystem().ObjectPath(ptr.Oid)
if err != nil {
return 0, false, nil, err
}
if !skip && filter.Allows(filename) {
if _, statErr := os.Stat(path); statErr != nil && ptr.Size != 0 {
q.Add(filename, path, ptr.Oid, ptr.Size, false, err)
return 0, true, ptr, nil
}
// Write 'statusFromErr(nil)', since the object is already
// present in the local cache, we will write the object's
// contents without delaying.
if err := s.WriteStatus(statusFromErr(nil)); err != nil {
return 0, false, nil, err
}
n, err := gf.Smudge(to, ptr, filename, false, nil, nil)
return n, false, ptr, err
}
if err := s.WriteStatus(statusFromErr(nil)); err != nil {
return 0, false, nil, err
}
n, err := ptr.Encode(to)
return int64(n), false, ptr, err
}
// smudge smudges the given `*lfs.Pointer`, "ptr", and writes its objects
// contents to the `io.Writer`, "to".
//
// If the encoded LFS pointer is not parse-able as a pointer, the contents of
// that file will instead be spooled to a temporary location on disk and then
// copied out back to Git. If the pointer file is empty, an empty file will be
// written with no error.
//
// If the smudged object did not "pass" the include and exclude filterset, it
// will not be downloaded, and the object will remain a pointer on disk, as if
// the smudge filter had not been applied at all.
//
// Any errors encountered along the way will be returned immediately if they
// were non-fatal, otherwise execution will halt and the process will be
// terminated by using the `commands.Panic()` func.
func smudge(gf *lfs.GitFilter, to io.Writer, from io.Reader, filename string, skip bool, filter *filepathfilter.Filter) (int64, error) {
ptr, pbuf, perr := lfs.DecodeFrom(from)
if perr != nil {
n, err := tools.Spool(to, pbuf, cfg.TempDir())
if err != nil {
return 0, errors.Wrap(err, perr.Error())
}
if n != 0 {
return 0, errors.NewNotAPointerError(errors.Errorf(
tr.Tr.Get("Unable to parse pointer at: %q", filename),
))
}
return 0, nil
}
lfs.LinkOrCopyFromReference(cfg, ptr.Oid, ptr.Size)
cb, file, err := gf.CopyCallbackFile("download", filename, 1, 1)
if err != nil {
return 0, err
}
if skip || !filter.Allows(filename) {
n, err := ptr.Encode(to)
return int64(n), err
}
n, err := gf.Smudge(to, ptr, filename, true, getTransferManifestOperationRemote("download", cfg.Remote()), cb)
if file != nil {
file.Close()
}
if err != nil {
ptr.Encode(to)
var oid string = ptr.Oid
if len(oid) >= 7 {
oid = oid[:7]
}
LoggedError(err, tr.Tr.Get("Error downloading object: %s (%s): %s", filename, oid, err))
if !cfg.SkipDownloadErrors() {
os.Exit(2)
}
}
return n, nil
}
func smudgeCommand(cmd *cobra.Command, args []string) {
requireStdin(tr.Tr.Get("This command should be run by the Git 'smudge' filter"))
setupRepository()
installHooks(false)
if !smudgeSkip && cfg.Os.Bool("GIT_LFS_SKIP_SMUDGE", false) {
smudgeSkip = true
}
filter := filepathfilter.New(cfg.FetchIncludePaths(), cfg.FetchExcludePaths(), filepathfilter.GitIgnore)
gitfilter := lfs.NewGitFilter(cfg)
if n, err := smudge(gitfilter, os.Stdout, os.Stdin, smudgeFilename(args), smudgeSkip, filter); err != nil {
if errors.IsNotAPointerError(err) {
fmt.Fprintln(os.Stderr, err.Error())
} else {
Error(err.Error())
}
} else if possiblyMalformedObjectSize(n) {
fmt.Fprintln(os.Stderr, tr.Tr.Get("Possibly malformed smudge on Windows: see `git lfs help smudge` for more info."))
}
}
func smudgeFilename(args []string) string {
if len(args) > 0 {
return args[0]
}
return fmt.Sprintf("<%s>", tr.Tr.Get("unknown file"))
}
func possiblyMalformedObjectSize(n int64) bool {
return n >= 4*humanize.Gibibyte
}
func init() {
RegisterCommand("smudge", smudgeCommand, func(cmd *cobra.Command) {
cmd.Flags().BoolVarP(&smudgeSkip, "skip", "s", false, "")
})
}