2830d39ef4
Because the tr.Tr.Get() family of methods insert arguments into printf(3)-style format strings after translating the format string, we can in a few cases drop a surrounding call to fmt.Sprintf() or a similar method, as those now take no arguments and so are redundant. Moreover, this will help us avoid situations where either the translated string or the argument values interpolated by tr.Tr.Get() produce an output string which itself happens to contain character sequences that resemble Go format specifiers (e.g., "%s", "%d", etc.) In such cases passing the string at runtime to a method such as fmt.Fprintf() will result in the output containing a warning such as "%!s(MISSING)", which is not ideal. Note that in one case, in lfs/attribute.go, we can now also simplify the format string to use standard format specifiers instead of double-escaped ones (e.g., "%%q") since we can just allow tr.Tr.Get() to do the interpolation. We also take the opportunity to remove explicit leading or trailing newlines from translation messages wherever it is possible to convert the surrounding call to fmt.Print(), fmt.Fprint(), fmt.Println(), or fmt.Fprintln(). Finally, in the commands/run.go file, we can replace two calls to fmt.Fprintf() with fmt.Println() because they are just printing output to os.Stdout, not os.Stderr, and in the lfs/extension.go file, we can make better use of fmt.Errorf(). Note that at least one of these messages is not yet actually passed as a translation string, but we will address that issue in a subsequent commit.
179 lines
4.3 KiB
Go
179 lines
4.3 KiB
Go
package commands
|
|
|
|
import (
|
|
"bytes"
|
|
"crypto/sha256"
|
|
"encoding/hex"
|
|
"errors"
|
|
"fmt"
|
|
"io"
|
|
"io/ioutil"
|
|
"os"
|
|
|
|
"github.com/git-lfs/git-lfs/v3/git"
|
|
"github.com/git-lfs/git-lfs/v3/lfs"
|
|
"github.com/git-lfs/git-lfs/v3/tr"
|
|
"github.com/spf13/cobra"
|
|
)
|
|
|
|
var (
|
|
pointerFile string
|
|
pointerCompare string
|
|
pointerStdin bool
|
|
pointerCheck bool
|
|
pointerStrict bool
|
|
pointerNoStrict bool
|
|
)
|
|
|
|
func pointerCommand(cmd *cobra.Command, args []string) {
|
|
comparing := false
|
|
something := false
|
|
buildOid := ""
|
|
compareOid := ""
|
|
|
|
if pointerCheck {
|
|
var r io.ReadCloser
|
|
var err error
|
|
|
|
if pointerStrict && pointerNoStrict {
|
|
ExitWithError(errors.New(tr.Tr.Get("Cannot combine --strict with --no-strict")))
|
|
}
|
|
|
|
if len(pointerCompare) > 0 {
|
|
ExitWithError(errors.New(tr.Tr.Get("Cannot combine --check with --compare")))
|
|
}
|
|
|
|
if len(pointerFile) > 0 {
|
|
if pointerStdin {
|
|
ExitWithError(errors.New(tr.Tr.Get("With --check, --file cannot be combined with --stdin")))
|
|
}
|
|
r, err = os.Open(pointerFile)
|
|
if err != nil {
|
|
ExitWithError(err)
|
|
}
|
|
} else if pointerStdin {
|
|
r = ioutil.NopCloser(os.Stdin)
|
|
} else {
|
|
ExitWithError(errors.New(tr.Tr.Get("Must specify either --file or --stdin with --compare")))
|
|
}
|
|
|
|
p, err := lfs.DecodePointer(r)
|
|
if err != nil {
|
|
os.Exit(1)
|
|
}
|
|
if pointerStrict && !p.Canonical {
|
|
os.Exit(2)
|
|
}
|
|
r.Close()
|
|
return
|
|
}
|
|
|
|
if len(pointerCompare) > 0 || pointerStdin {
|
|
comparing = true
|
|
}
|
|
|
|
if len(pointerFile) > 0 {
|
|
something = true
|
|
buildFile, err := os.Open(pointerFile)
|
|
if err != nil {
|
|
Error(err.Error())
|
|
os.Exit(1)
|
|
}
|
|
|
|
oidHash := sha256.New()
|
|
size, err := io.Copy(oidHash, buildFile)
|
|
buildFile.Close()
|
|
|
|
if err != nil {
|
|
Error(err.Error())
|
|
os.Exit(1)
|
|
}
|
|
|
|
ptr := lfs.NewPointer(hex.EncodeToString(oidHash.Sum(nil)), size, nil)
|
|
fmt.Fprint(os.Stderr, tr.Tr.Get("Git LFS pointer for %s", pointerFile), "\n\n")
|
|
buf := &bytes.Buffer{}
|
|
lfs.EncodePointer(io.MultiWriter(os.Stdout, buf), ptr)
|
|
|
|
if comparing {
|
|
buildOid, err = git.HashObject(bytes.NewReader(buf.Bytes()))
|
|
if err != nil {
|
|
Error(err.Error())
|
|
os.Exit(1)
|
|
}
|
|
fmt.Fprint(os.Stderr, "\n", tr.Tr.Get("Git blob OID: %s", buildOid), "\n\n")
|
|
}
|
|
} else {
|
|
comparing = false
|
|
}
|
|
|
|
if len(pointerCompare) > 0 || pointerStdin {
|
|
something = true
|
|
compFile, err := pointerReader()
|
|
if err != nil {
|
|
Error(err.Error())
|
|
os.Exit(1)
|
|
}
|
|
|
|
buf := &bytes.Buffer{}
|
|
tee := io.TeeReader(compFile, buf)
|
|
_, err = lfs.DecodePointer(tee)
|
|
compFile.Close()
|
|
|
|
pointerName := "STDIN"
|
|
if !pointerStdin {
|
|
pointerName = pointerCompare
|
|
}
|
|
fmt.Fprint(os.Stderr, tr.Tr.Get("Pointer from %s", pointerName), "\n\n")
|
|
|
|
if err != nil {
|
|
Error(err.Error())
|
|
os.Exit(1)
|
|
}
|
|
|
|
fmt.Fprintf(os.Stderr, buf.String())
|
|
if comparing {
|
|
compareOid, err = git.HashObject(bytes.NewReader(buf.Bytes()))
|
|
if err != nil {
|
|
Error(err.Error())
|
|
os.Exit(1)
|
|
}
|
|
fmt.Fprint(os.Stderr, "\n", tr.Tr.Get("Git blob OID: %s", compareOid), "\n")
|
|
}
|
|
}
|
|
|
|
if comparing && buildOid != compareOid {
|
|
fmt.Fprint(os.Stderr, "\n", tr.Tr.Get("Pointers do not match"), "\n")
|
|
os.Exit(1)
|
|
}
|
|
|
|
if !something {
|
|
Error(tr.Tr.Get("Nothing to do!"))
|
|
os.Exit(1)
|
|
}
|
|
}
|
|
|
|
func pointerReader() (io.ReadCloser, error) {
|
|
if len(pointerCompare) > 0 {
|
|
if pointerStdin {
|
|
return nil, errors.New(tr.Tr.Get("cannot read from STDIN and --pointer"))
|
|
}
|
|
|
|
return os.Open(pointerCompare)
|
|
}
|
|
|
|
requireStdin(tr.Tr.Get("The --stdin flag expects a pointer file from STDIN."))
|
|
|
|
return os.Stdin, nil
|
|
}
|
|
|
|
func init() {
|
|
RegisterCommand("pointer", pointerCommand, func(cmd *cobra.Command) {
|
|
cmd.Flags().StringVarP(&pointerFile, "file", "f", "", "Path to a local file to generate the pointer from.")
|
|
cmd.Flags().StringVarP(&pointerCompare, "pointer", "p", "", "Path to a local file containing a pointer built by another Git LFS implementation.")
|
|
cmd.Flags().BoolVarP(&pointerStdin, "stdin", "", false, "Read a pointer built by another Git LFS implementation through STDIN.")
|
|
cmd.Flags().BoolVarP(&pointerCheck, "check", "", false, "Check whether the given file is a Git LFS pointer.")
|
|
cmd.Flags().BoolVarP(&pointerStrict, "strict", "", false, "Check whether the given Git LFS pointer is canonical.")
|
|
cmd.Flags().BoolVarP(&pointerNoStrict, "no-strict", "", false, "Don't check whether the given Git LFS pointer is canonical.")
|
|
})
|
|
}
|