Merge branch 'master' into batch-retry-eof
This commit is contained in:
commit
d78f32a39a
@ -8,8 +8,8 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
|
||||||
|
|
||||||
|
"github.com/git-lfs/git-lfs/git"
|
||||||
"github.com/git-lfs/git-lfs/lfs"
|
"github.com/git-lfs/git-lfs/lfs"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
@ -53,7 +53,11 @@ func pointerCommand(cmd *cobra.Command, args []string) {
|
|||||||
lfs.EncodePointer(io.MultiWriter(os.Stdout, buf), ptr)
|
lfs.EncodePointer(io.MultiWriter(os.Stdout, buf), ptr)
|
||||||
|
|
||||||
if comparing {
|
if comparing {
|
||||||
buildOid = gitHashObject(buf.Bytes())
|
buildOid, err = git.HashObject(bytes.NewReader(buf.Bytes()))
|
||||||
|
if err != nil {
|
||||||
|
Error(err.Error())
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
fmt.Fprintf(os.Stderr, "\nGit blob OID: %s\n\n", buildOid)
|
fmt.Fprintf(os.Stderr, "\nGit blob OID: %s\n\n", buildOid)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -86,7 +90,11 @@ func pointerCommand(cmd *cobra.Command, args []string) {
|
|||||||
|
|
||||||
fmt.Fprintf(os.Stderr, buf.String())
|
fmt.Fprintf(os.Stderr, buf.String())
|
||||||
if comparing {
|
if comparing {
|
||||||
compareOid = gitHashObject(buf.Bytes())
|
compareOid, err = git.HashObject(bytes.NewReader(buf.Bytes()))
|
||||||
|
if err != nil {
|
||||||
|
Error(err.Error())
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
fmt.Fprintf(os.Stderr, "\nGit blob OID: %s\n", compareOid)
|
fmt.Fprintf(os.Stderr, "\nGit blob OID: %s\n", compareOid)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -116,18 +124,6 @@ func pointerReader() (io.ReadCloser, error) {
|
|||||||
return os.Stdin, nil
|
return os.Stdin, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func gitHashObject(by []byte) string {
|
|
||||||
cmd := exec.Command("git", "hash-object", "--stdin")
|
|
||||||
cmd.Stdin = bytes.NewReader(by)
|
|
||||||
out, err := cmd.Output()
|
|
||||||
if err != nil {
|
|
||||||
Error("Error building Git blob OID: %s", err)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
return string(bytes.TrimSpace(out))
|
|
||||||
}
|
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
RegisterCommand("pointer", pointerCommand, func(cmd *cobra.Command) {
|
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(&pointerFile, "file", "f", "", "Path to a local file to generate the pointer from.")
|
||||||
|
@ -5,11 +5,12 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/git-lfs/git-lfs/errors"
|
"github.com/git-lfs/git-lfs/errors"
|
||||||
|
"github.com/git-lfs/git-lfs/git"
|
||||||
"github.com/git-lfs/git-lfs/lfs"
|
"github.com/git-lfs/git-lfs/lfs"
|
||||||
|
"github.com/git-lfs/git-lfs/subprocess"
|
||||||
"github.com/git-lfs/git-lfs/tq"
|
"github.com/git-lfs/git-lfs/tq"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -85,7 +86,7 @@ func (c *singleCheckout) Close() {
|
|||||||
// which can trigger entire working copy to be re-examined, which triggers clean filters
|
// which can trigger entire working copy to be re-examined, which triggers clean filters
|
||||||
// and which has unexpected side effects (e.g. downloading filtered-out files)
|
// and which has unexpected side effects (e.g. downloading filtered-out files)
|
||||||
type gitIndexer struct {
|
type gitIndexer struct {
|
||||||
cmd *exec.Cmd
|
cmd *subprocess.Cmd
|
||||||
input io.WriteCloser
|
input io.WriteCloser
|
||||||
output bytes.Buffer
|
output bytes.Buffer
|
||||||
mu sync.Mutex
|
mu sync.Mutex
|
||||||
@ -97,14 +98,7 @@ func (i *gitIndexer) Add(path string) error {
|
|||||||
|
|
||||||
if i.cmd == nil {
|
if i.cmd == nil {
|
||||||
// Fire up the update-index command
|
// Fire up the update-index command
|
||||||
i.cmd = exec.Command("git", "update-index", "-q", "--refresh", "--stdin")
|
stdin, err := git.StartUpdateIndexFromStdin(&i.output)
|
||||||
i.cmd.Stdout = &i.output
|
|
||||||
i.cmd.Stderr = &i.output
|
|
||||||
stdin, err := i.cmd.StdinPipe()
|
|
||||||
if err == nil {
|
|
||||||
err = i.cmd.Start()
|
|
||||||
}
|
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
201
git/git.go
201
git/git.go
@ -8,6 +8,7 @@ import (
|
|||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net/url"
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
@ -84,19 +85,116 @@ type CommitSummary struct {
|
|||||||
Subject string
|
Subject string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Prepend Git config instructions to disable Git LFS filter
|
||||||
|
func gitConfigNoLFS(args ...string) []string {
|
||||||
|
// Before git 2.8, setting filters to blank causes lots of warnings, so use cat instead (slightly slower)
|
||||||
|
// Also pre 2.2 it failed completely. We used to use it anyway in git 2.2-2.7 and
|
||||||
|
// suppress the messages in stderr, but doing that with standard StderrPipe suppresses
|
||||||
|
// the git clone output (git thinks it's not a terminal) and makes it look like it's
|
||||||
|
// not working. You can get around that with https://github.com/kr/pty but that
|
||||||
|
// causes difficult issues with passing through Stdin for login prompts
|
||||||
|
// This way is simpler & more practical.
|
||||||
|
filterOverride := ""
|
||||||
|
if !Config.IsGitVersionAtLeast("2.8.0") {
|
||||||
|
filterOverride = "cat"
|
||||||
|
}
|
||||||
|
|
||||||
|
return append([]string{
|
||||||
|
"-c", fmt.Sprintf("filter.lfs.smudge=%v", filterOverride),
|
||||||
|
"-c", fmt.Sprintf("filter.lfs.clean=%v", filterOverride),
|
||||||
|
"-c", "filter.lfs.process=",
|
||||||
|
"-c", "filter.lfs.required=false",
|
||||||
|
}, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Invoke Git with disabled LFS filters
|
||||||
|
func gitNoLFS(args ...string) *subprocess.Cmd {
|
||||||
|
return subprocess.ExecCommand("git", gitConfigNoLFS(args...)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func gitNoLFSSimple(args ...string) (string, error) {
|
||||||
|
return subprocess.SimpleExec("git", gitConfigNoLFS(args...)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func gitNoLFSBuffered(args ...string) (*subprocess.BufferedCmd, error) {
|
||||||
|
return subprocess.BufferedExec("git", gitConfigNoLFS(args...)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Invoke Git with enabled LFS filters
|
||||||
|
func git(args ...string) *subprocess.Cmd {
|
||||||
|
return subprocess.ExecCommand("git", args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func gitSimple(args ...string) (string, error) {
|
||||||
|
return subprocess.SimpleExec("git", args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func gitBuffered(args ...string) (*subprocess.BufferedCmd, error) {
|
||||||
|
return subprocess.BufferedExec("git", args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func CatFile() (*subprocess.BufferedCmd, error) {
|
||||||
|
return gitNoLFSBuffered("cat-file", "--batch-check")
|
||||||
|
}
|
||||||
|
|
||||||
|
func DiffIndex(ref string, cached bool) (*bufio.Scanner, error) {
|
||||||
|
args := []string{"diff-index", "-M"}
|
||||||
|
if cached {
|
||||||
|
args = append(args, "--cached")
|
||||||
|
}
|
||||||
|
args = append(args, ref)
|
||||||
|
|
||||||
|
cmd, err := gitBuffered(args...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if err = cmd.Stdin.Close(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return bufio.NewScanner(cmd.Stdout), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func HashObject(r io.Reader) (string, error) {
|
||||||
|
cmd := gitNoLFS("hash-object", "--stdin")
|
||||||
|
cmd.Stdin = r
|
||||||
|
out, err := cmd.Output()
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("Error building Git blob OID: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return string(bytes.TrimSpace(out)), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func Log(args ...string) (*subprocess.BufferedCmd, error) {
|
||||||
|
logArgs := append([]string{"log"}, args...)
|
||||||
|
return gitNoLFSBuffered(logArgs...)
|
||||||
|
}
|
||||||
|
|
||||||
func LsRemote(remote, remoteRef string) (string, error) {
|
func LsRemote(remote, remoteRef string) (string, error) {
|
||||||
if remote == "" {
|
if remote == "" {
|
||||||
return "", errors.New("remote required")
|
return "", errors.New("remote required")
|
||||||
}
|
}
|
||||||
if remoteRef == "" {
|
if remoteRef == "" {
|
||||||
return subprocess.SimpleExec("git", "ls-remote", remote)
|
return gitNoLFSSimple("ls-remote", remote)
|
||||||
|
|
||||||
}
|
}
|
||||||
return subprocess.SimpleExec("git", "ls-remote", remote, remoteRef)
|
return gitNoLFSSimple("ls-remote", remote, remoteRef)
|
||||||
|
}
|
||||||
|
|
||||||
|
func LsTree(ref string) (*subprocess.BufferedCmd, error) {
|
||||||
|
return gitNoLFSBuffered(
|
||||||
|
"ls-tree",
|
||||||
|
"-r", // recurse
|
||||||
|
"-l", // report object size (we'll need this)
|
||||||
|
"-z", // null line termination
|
||||||
|
"--full-tree", // start at the root regardless of where we are in it
|
||||||
|
ref,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
func ResolveRef(ref string) (*Ref, error) {
|
func ResolveRef(ref string) (*Ref, error) {
|
||||||
outp, err := subprocess.SimpleExec("git", "rev-parse", ref, "--symbolic-full-name", ref)
|
outp, err := gitNoLFSSimple("rev-parse", ref, "--symbolic-full-name", ref)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("Git can't resolve ref: %q", ref)
|
return nil, fmt.Errorf("Git can't resolve ref: %q", ref)
|
||||||
}
|
}
|
||||||
@ -199,7 +297,7 @@ func RemoteBranchForLocalBranch(localBranch string) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func RemoteList() ([]string, error) {
|
func RemoteList() ([]string, error) {
|
||||||
cmd := subprocess.ExecCommand("git", "remote")
|
cmd := gitNoLFS("remote")
|
||||||
|
|
||||||
outp, err := cmd.StdoutPipe()
|
outp, err := cmd.StdoutPipe()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -221,7 +319,7 @@ func RemoteList() ([]string, error) {
|
|||||||
// Refs returns all of the local and remote branches and tags for the current
|
// Refs returns all of the local and remote branches and tags for the current
|
||||||
// repository. Other refs (HEAD, refs/stash, git notes) are ignored.
|
// repository. Other refs (HEAD, refs/stash, git notes) are ignored.
|
||||||
func LocalRefs() ([]*Ref, error) {
|
func LocalRefs() ([]*Ref, error) {
|
||||||
cmd := subprocess.ExecCommand("git", "show-ref", "--heads", "--tags")
|
cmd := gitNoLFS("show-ref", "--heads", "--tags")
|
||||||
|
|
||||||
outp, err := cmd.StdoutPipe()
|
outp, err := cmd.StdoutPipe()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -277,7 +375,7 @@ func UpdateRefIn(wd string, ref *Ref, to []byte, reason string) error {
|
|||||||
args = append(args, "-m", reason)
|
args = append(args, "-m", reason)
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd := subprocess.ExecCommand("git", args...)
|
cmd := gitNoLFS(args...)
|
||||||
cmd.Dir = wd
|
cmd.Dir = wd
|
||||||
|
|
||||||
return cmd.Run()
|
return cmd.Run()
|
||||||
@ -360,9 +458,16 @@ func DefaultRemote() (string, error) {
|
|||||||
return "", errors.New("Unable to pick default remote, too ambiguous")
|
return "", errors.New("Unable to pick default remote, too ambiguous")
|
||||||
}
|
}
|
||||||
|
|
||||||
func UpdateIndex(file string) error {
|
func StartUpdateIndexFromStdin(w io.Writer) (io.WriteCloser, error) {
|
||||||
_, err := subprocess.SimpleExec("git", "update-index", "-q", "--refresh", file)
|
cmd := gitNoLFS("update-index", "-q", "--refresh", "--stdin")
|
||||||
return err
|
cmd.Stdout = w
|
||||||
|
cmd.Stderr = w
|
||||||
|
stdin, err := cmd.StdinPipe()
|
||||||
|
if err == nil {
|
||||||
|
err = cmd.Start()
|
||||||
|
}
|
||||||
|
|
||||||
|
return stdin, err
|
||||||
}
|
}
|
||||||
|
|
||||||
type gitConfig struct {
|
type gitConfig struct {
|
||||||
@ -374,61 +479,61 @@ var Config = &gitConfig{}
|
|||||||
|
|
||||||
// Find returns the git config value for the key
|
// Find returns the git config value for the key
|
||||||
func (c *gitConfig) Find(val string) string {
|
func (c *gitConfig) Find(val string) string {
|
||||||
output, _ := subprocess.SimpleExec("git", "config", val)
|
output, _ := gitSimple("config", val)
|
||||||
return output
|
return output
|
||||||
}
|
}
|
||||||
|
|
||||||
// FindGlobal returns the git config value global scope for the key
|
// FindGlobal returns the git config value global scope for the key
|
||||||
func (c *gitConfig) FindGlobal(val string) string {
|
func (c *gitConfig) FindGlobal(val string) string {
|
||||||
output, _ := subprocess.SimpleExec("git", "config", "--global", val)
|
output, _ := gitSimple("config", "--global", val)
|
||||||
return output
|
return output
|
||||||
}
|
}
|
||||||
|
|
||||||
// FindSystem returns the git config value in system scope for the key
|
// FindSystem returns the git config value in system scope for the key
|
||||||
func (c *gitConfig) FindSystem(val string) string {
|
func (c *gitConfig) FindSystem(val string) string {
|
||||||
output, _ := subprocess.SimpleExec("git", "config", "--system", val)
|
output, _ := gitSimple("config", "--system", val)
|
||||||
return output
|
return output
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find returns the git config value for the key
|
// Find returns the git config value for the key
|
||||||
func (c *gitConfig) FindLocal(val string) string {
|
func (c *gitConfig) FindLocal(val string) string {
|
||||||
output, _ := subprocess.SimpleExec("git", "config", "--local", val)
|
output, _ := gitSimple("config", "--local", val)
|
||||||
return output
|
return output
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetGlobal sets the git config value for the key in the global config
|
// SetGlobal sets the git config value for the key in the global config
|
||||||
func (c *gitConfig) SetGlobal(key, val string) (string, error) {
|
func (c *gitConfig) SetGlobal(key, val string) (string, error) {
|
||||||
return subprocess.SimpleExec("git", "config", "--global", key, val)
|
return gitSimple("config", "--global", key, val)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetSystem sets the git config value for the key in the system config
|
// SetSystem sets the git config value for the key in the system config
|
||||||
func (c *gitConfig) SetSystem(key, val string) (string, error) {
|
func (c *gitConfig) SetSystem(key, val string) (string, error) {
|
||||||
return subprocess.SimpleExec("git", "config", "--system", key, val)
|
return gitSimple("config", "--system", key, val)
|
||||||
}
|
}
|
||||||
|
|
||||||
// UnsetGlobal removes the git config value for the key from the global config
|
// UnsetGlobal removes the git config value for the key from the global config
|
||||||
func (c *gitConfig) UnsetGlobal(key string) (string, error) {
|
func (c *gitConfig) UnsetGlobal(key string) (string, error) {
|
||||||
return subprocess.SimpleExec("git", "config", "--global", "--unset", key)
|
return gitSimple("config", "--global", "--unset", key)
|
||||||
}
|
}
|
||||||
|
|
||||||
// UnsetSystem removes the git config value for the key from the system config
|
// UnsetSystem removes the git config value for the key from the system config
|
||||||
func (c *gitConfig) UnsetSystem(key string) (string, error) {
|
func (c *gitConfig) UnsetSystem(key string) (string, error) {
|
||||||
return subprocess.SimpleExec("git", "config", "--system", "--unset", key)
|
return gitSimple("config", "--system", "--unset", key)
|
||||||
}
|
}
|
||||||
|
|
||||||
// UnsetGlobalSection removes the entire named section from the global config
|
// UnsetGlobalSection removes the entire named section from the global config
|
||||||
func (c *gitConfig) UnsetGlobalSection(key string) (string, error) {
|
func (c *gitConfig) UnsetGlobalSection(key string) (string, error) {
|
||||||
return subprocess.SimpleExec("git", "config", "--global", "--remove-section", key)
|
return gitSimple("config", "--global", "--remove-section", key)
|
||||||
}
|
}
|
||||||
|
|
||||||
// UnsetSystemSection removes the entire named section from the system config
|
// UnsetSystemSection removes the entire named section from the system config
|
||||||
func (c *gitConfig) UnsetSystemSection(key string) (string, error) {
|
func (c *gitConfig) UnsetSystemSection(key string) (string, error) {
|
||||||
return subprocess.SimpleExec("git", "config", "--system", "--remove-section", key)
|
return gitSimple("config", "--system", "--remove-section", key)
|
||||||
}
|
}
|
||||||
|
|
||||||
// UnsetLocalSection removes the entire named section from the system config
|
// UnsetLocalSection removes the entire named section from the system config
|
||||||
func (c *gitConfig) UnsetLocalSection(key string) (string, error) {
|
func (c *gitConfig) UnsetLocalSection(key string) (string, error) {
|
||||||
return subprocess.SimpleExec("git", "config", "--local", "--remove-section", key)
|
return gitSimple("config", "--local", "--remove-section", key)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetLocal sets the git config value for the key in the specified config file
|
// SetLocal sets the git config value for the key in the specified config file
|
||||||
@ -439,7 +544,7 @@ func (c *gitConfig) SetLocal(file, key, val string) (string, error) {
|
|||||||
args = append(args, "--file", file)
|
args = append(args, "--file", file)
|
||||||
}
|
}
|
||||||
args = append(args, key, val)
|
args = append(args, key, val)
|
||||||
return subprocess.SimpleExec("git", args...)
|
return gitSimple(args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// UnsetLocalKey removes the git config value for the key from the specified config file
|
// UnsetLocalKey removes the git config value for the key from the specified config file
|
||||||
@ -450,17 +555,17 @@ func (c *gitConfig) UnsetLocalKey(file, key string) (string, error) {
|
|||||||
args = append(args, "--file", file)
|
args = append(args, "--file", file)
|
||||||
}
|
}
|
||||||
args = append(args, "--unset", key)
|
args = append(args, "--unset", key)
|
||||||
return subprocess.SimpleExec("git", args...)
|
return gitSimple(args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// List lists all of the git config values
|
// List lists all of the git config values
|
||||||
func (c *gitConfig) List() (string, error) {
|
func (c *gitConfig) List() (string, error) {
|
||||||
return subprocess.SimpleExec("git", "config", "-l")
|
return gitSimple("config", "-l")
|
||||||
}
|
}
|
||||||
|
|
||||||
// ListFromFile lists all of the git config values in the given config file
|
// ListFromFile lists all of the git config values in the given config file
|
||||||
func (c *gitConfig) ListFromFile(f string) (string, error) {
|
func (c *gitConfig) ListFromFile(f string) (string, error) {
|
||||||
return subprocess.SimpleExec("git", "config", "-l", "-f", f)
|
return gitSimple("config", "-l", "-f", f)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Version returns the git version
|
// Version returns the git version
|
||||||
@ -469,7 +574,7 @@ func (c *gitConfig) Version() (string, error) {
|
|||||||
defer c.mu.Unlock()
|
defer c.mu.Unlock()
|
||||||
|
|
||||||
if len(c.gitVersion) == 0 {
|
if len(c.gitVersion) == 0 {
|
||||||
v, err := subprocess.SimpleExec("git", "version")
|
v, err := gitSimple("version")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return v, err
|
return v, err
|
||||||
}
|
}
|
||||||
@ -496,7 +601,7 @@ func (c *gitConfig) IsGitVersionAtLeast(ver string) bool {
|
|||||||
// includeRemoteBranches: true to include refs on remote branches
|
// includeRemoteBranches: true to include refs on remote branches
|
||||||
// onlyRemote: set to non-blank to only include remote branches on a single remote
|
// onlyRemote: set to non-blank to only include remote branches on a single remote
|
||||||
func RecentBranches(since time.Time, includeRemoteBranches bool, onlyRemote string) ([]*Ref, error) {
|
func RecentBranches(since time.Time, includeRemoteBranches bool, onlyRemote string) ([]*Ref, error) {
|
||||||
cmd := subprocess.ExecCommand("git", "for-each-ref",
|
cmd := gitNoLFS("for-each-ref",
|
||||||
`--sort=-committerdate`,
|
`--sort=-committerdate`,
|
||||||
`--format=%(refname) %(objectname) %(committerdate:iso)`,
|
`--format=%(refname) %(objectname) %(committerdate:iso)`,
|
||||||
"refs")
|
"refs")
|
||||||
@ -599,7 +704,7 @@ func FormatGitDate(tm time.Time) string {
|
|||||||
|
|
||||||
// Get summary information about a commit
|
// Get summary information about a commit
|
||||||
func GetCommitSummary(commit string) (*CommitSummary, error) {
|
func GetCommitSummary(commit string) (*CommitSummary, error) {
|
||||||
cmd := subprocess.ExecCommand("git", "show", "-s",
|
cmd := gitNoLFS("show", "-s",
|
||||||
`--format=%H|%h|%P|%ai|%ci|%ae|%an|%ce|%cn|%s`, commit)
|
`--format=%H|%h|%P|%ai|%ci|%ae|%an|%ce|%cn|%s`, commit)
|
||||||
|
|
||||||
out, err := cmd.CombinedOutput()
|
out, err := cmd.CombinedOutput()
|
||||||
@ -634,7 +739,7 @@ func GetCommitSummary(commit string) (*CommitSummary, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func GitAndRootDirs() (string, string, error) {
|
func GitAndRootDirs() (string, string, error) {
|
||||||
cmd := subprocess.ExecCommand("git", "rev-parse", "--git-dir", "--show-toplevel")
|
cmd := gitNoLFS("rev-parse", "--git-dir", "--show-toplevel")
|
||||||
buf := &bytes.Buffer{}
|
buf := &bytes.Buffer{}
|
||||||
cmd.Stderr = buf
|
cmd.Stderr = buf
|
||||||
|
|
||||||
@ -669,7 +774,7 @@ func GitAndRootDirs() (string, string, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func RootDir() (string, error) {
|
func RootDir() (string, error) {
|
||||||
cmd := subprocess.ExecCommand("git", "rev-parse", "--show-toplevel")
|
cmd := gitNoLFS("rev-parse", "--show-toplevel")
|
||||||
out, err := cmd.Output()
|
out, err := cmd.Output()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", fmt.Errorf("Failed to call git rev-parse --show-toplevel: %v %v", err, string(out))
|
return "", fmt.Errorf("Failed to call git rev-parse --show-toplevel: %v %v", err, string(out))
|
||||||
@ -685,7 +790,7 @@ func RootDir() (string, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func GitDir() (string, error) {
|
func GitDir() (string, error) {
|
||||||
cmd := subprocess.ExecCommand("git", "rev-parse", "--git-dir")
|
cmd := gitNoLFS("rev-parse", "--git-dir")
|
||||||
out, err := cmd.Output()
|
out, err := cmd.Output()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", fmt.Errorf("Failed to call git rev-parse --git-dir: %v %v", err, string(out))
|
return "", fmt.Errorf("Failed to call git rev-parse --git-dir: %v %v", err, string(out))
|
||||||
@ -886,25 +991,7 @@ type CloneFlags struct {
|
|||||||
// so that files in the working copy will be pointers and not real LFS data
|
// so that files in the working copy will be pointers and not real LFS data
|
||||||
func CloneWithoutFilters(flags CloneFlags, args []string) error {
|
func CloneWithoutFilters(flags CloneFlags, args []string) error {
|
||||||
|
|
||||||
// Before git 2.8, setting filters to blank causes lots of warnings, so use cat instead (slightly slower)
|
cmdargs := []string{"clone"}
|
||||||
// Also pre 2.2 it failed completely. We used to use it anyway in git 2.2-2.7 and
|
|
||||||
// suppress the messages in stderr, but doing that with standard StderrPipe suppresses
|
|
||||||
// the git clone output (git thinks it's not a terminal) and makes it look like it's
|
|
||||||
// not working. You can get around that with https://github.com/kr/pty but that
|
|
||||||
// causes difficult issues with passing through Stdin for login prompts
|
|
||||||
// This way is simpler & more practical.
|
|
||||||
filterOverride := ""
|
|
||||||
if !Config.IsGitVersionAtLeast("2.8.0") {
|
|
||||||
filterOverride = "cat"
|
|
||||||
}
|
|
||||||
// Disable the LFS filters while cloning to speed things up
|
|
||||||
// this is especially effective on Windows where even calling git-lfs at all
|
|
||||||
// with --skip-smudge is costly across many files in a checkout
|
|
||||||
cmdargs := []string{
|
|
||||||
"-c", fmt.Sprintf("filter.lfs.smudge=%v", filterOverride),
|
|
||||||
"-c", "filter.lfs.process=",
|
|
||||||
"-c", "filter.lfs.required=false",
|
|
||||||
"clone"}
|
|
||||||
|
|
||||||
// flags
|
// flags
|
||||||
if flags.Bare {
|
if flags.Bare {
|
||||||
@ -1000,7 +1087,7 @@ func CloneWithoutFilters(flags CloneFlags, args []string) error {
|
|||||||
|
|
||||||
// Now args
|
// Now args
|
||||||
cmdargs = append(cmdargs, args...)
|
cmdargs = append(cmdargs, args...)
|
||||||
cmd := subprocess.ExecCommand("git", cmdargs...)
|
cmd := gitNoLFS(cmdargs...)
|
||||||
|
|
||||||
// Assign all streams direct
|
// Assign all streams direct
|
||||||
cmd.Stdout = os.Stdout
|
cmd.Stdout = os.Stdout
|
||||||
@ -1039,7 +1126,7 @@ func Checkout(treeish string, paths []string, force bool) error {
|
|||||||
args = append(args, append([]string{"--"}, paths...)...)
|
args = append(args, append([]string{"--"}, paths...)...)
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err := subprocess.SimpleExec("git", args...)
|
_, err := gitNoLFSSimple(args...)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1047,7 +1134,7 @@ func Checkout(treeish string, paths []string, force bool) error {
|
|||||||
// currently cached locally. No remote request is made to verify them.
|
// currently cached locally. No remote request is made to verify them.
|
||||||
func CachedRemoteRefs(remoteName string) ([]*Ref, error) {
|
func CachedRemoteRefs(remoteName string) ([]*Ref, error) {
|
||||||
var ret []*Ref
|
var ret []*Ref
|
||||||
cmd := subprocess.ExecCommand("git", "show-ref")
|
cmd := gitNoLFS("show-ref")
|
||||||
|
|
||||||
outp, err := cmd.StdoutPipe()
|
outp, err := cmd.StdoutPipe()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -1076,7 +1163,7 @@ func CachedRemoteRefs(remoteName string) ([]*Ref, error) {
|
|||||||
// accessing the remote vir git ls-remote
|
// accessing the remote vir git ls-remote
|
||||||
func RemoteRefs(remoteName string) ([]*Ref, error) {
|
func RemoteRefs(remoteName string) ([]*Ref, error) {
|
||||||
var ret []*Ref
|
var ret []*Ref
|
||||||
cmd := subprocess.ExecCommand("git", "ls-remote", "--heads", "--tags", "-q", remoteName)
|
cmd := gitNoLFS("ls-remote", "--heads", "--tags", "-q", remoteName)
|
||||||
|
|
||||||
outp, err := cmd.StdoutPipe()
|
outp, err := cmd.StdoutPipe()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -1115,7 +1202,7 @@ func AllRefs() ([]*Ref, error) {
|
|||||||
// the given working directory "wd", or an error if those references could not
|
// the given working directory "wd", or an error if those references could not
|
||||||
// be loaded.
|
// be loaded.
|
||||||
func AllRefsIn(wd string) ([]*Ref, error) {
|
func AllRefsIn(wd string) ([]*Ref, error) {
|
||||||
cmd := subprocess.ExecCommand("git",
|
cmd := gitNoLFS(
|
||||||
"for-each-ref", "--format=%(objectname)%00%(refname)")
|
"for-each-ref", "--format=%(objectname)%00%(refname)")
|
||||||
cmd.Dir = wd
|
cmd.Dir = wd
|
||||||
|
|
||||||
@ -1161,7 +1248,7 @@ func GetTrackedFiles(pattern string) ([]string, error) {
|
|||||||
rootWildcard := len(safePattern) < len(pattern) && strings.ContainsRune(safePattern, '*')
|
rootWildcard := len(safePattern) < len(pattern) && strings.ContainsRune(safePattern, '*')
|
||||||
|
|
||||||
var ret []string
|
var ret []string
|
||||||
cmd := subprocess.ExecCommand("git",
|
cmd := gitNoLFS(
|
||||||
"-c", "core.quotepath=false", // handle special chars in filenames
|
"-c", "core.quotepath=false", // handle special chars in filenames
|
||||||
"ls-files",
|
"ls-files",
|
||||||
"--cached", // include things which are staged but not committed right now
|
"--cached", // include things which are staged but not committed right now
|
||||||
@ -1220,7 +1307,7 @@ func GetFilesChanged(from, to string) ([]string, error) {
|
|||||||
}
|
}
|
||||||
args = append(args, "--") // no ambiguous patterns
|
args = append(args, "--") // no ambiguous patterns
|
||||||
|
|
||||||
cmd := subprocess.ExecCommand("git", args...)
|
cmd := gitNoLFS(args...)
|
||||||
outp, err := cmd.StdoutPipe()
|
outp, err := cmd.StdoutPipe()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("Failed to call git diff: %v", err)
|
return nil, fmt.Errorf("Failed to call git diff: %v", err)
|
||||||
@ -1251,7 +1338,7 @@ func IsFileModified(filepath string) (bool, error) {
|
|||||||
"--", // separator in case filename ambiguous
|
"--", // separator in case filename ambiguous
|
||||||
filepath,
|
filepath,
|
||||||
}
|
}
|
||||||
cmd := subprocess.ExecCommand("git", args...)
|
cmd := git(args...)
|
||||||
outp, err := cmd.StdoutPipe()
|
outp, err := cmd.StdoutPipe()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, lfserrors.Wrap(err, "Failed to call git status")
|
return false, lfserrors.Wrap(err, "Failed to call git status")
|
||||||
|
@ -6,7 +6,6 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os/exec"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
"github.com/git-lfs/git-lfs/errors"
|
"github.com/git-lfs/git-lfs/errors"
|
||||||
@ -53,7 +52,7 @@ type ObjectScanner struct {
|
|||||||
//
|
//
|
||||||
// Otherwise, an `*ObjectScanner` is returned with no error.
|
// Otherwise, an `*ObjectScanner` is returned with no error.
|
||||||
func NewObjectScanner() (*ObjectScanner, error) {
|
func NewObjectScanner() (*ObjectScanner, error) {
|
||||||
cmd := exec.Command("git", "cat-file", "--batch")
|
cmd := gitNoLFS("cat-file", "--batch")
|
||||||
stdout, err := cmd.StdoutPipe()
|
stdout, err := cmd.StdoutPipe()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrap(err, "open stdout")
|
return nil, errors.Wrap(err, "open stdout")
|
||||||
|
@ -6,7 +6,6 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os/exec"
|
|
||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
@ -173,7 +172,7 @@ func NewRevListScanner(include, excluded []string, opt *ScanRefsOptions) (*RevLi
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd := exec.Command("git", args...)
|
cmd := gitNoLFS(args...).Cmd
|
||||||
if len(opt.WorkingDir) > 0 {
|
if len(opt.WorkingDir) > 0 {
|
||||||
cmd.Dir = opt.WorkingDir
|
cmd.Dir = opt.WorkingDir
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/git-lfs/git-lfs/errors"
|
"github.com/git-lfs/git-lfs/errors"
|
||||||
|
"github.com/git-lfs/git-lfs/git"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Status represents the status of a file that appears in the output of `git
|
// Status represents the status of a file that appears in the output of `git
|
||||||
@ -122,32 +123,15 @@ type DiffIndexScanner struct {
|
|||||||
// that error will be returned immediately. Otherwise, a `*DiffIndexScanner`
|
// that error will be returned immediately. Otherwise, a `*DiffIndexScanner`
|
||||||
// will be returned with a `nil` error.
|
// will be returned with a `nil` error.
|
||||||
func NewDiffIndexScanner(ref string, cached bool) (*DiffIndexScanner, error) {
|
func NewDiffIndexScanner(ref string, cached bool) (*DiffIndexScanner, error) {
|
||||||
cmd, err := startCommand("git", diffIndexCmdArgs(ref, cached)...)
|
scanner, err := git.DiffIndex(ref, cached)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = cmd.Stdin.Close(); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return &DiffIndexScanner{
|
return &DiffIndexScanner{
|
||||||
from: bufio.NewScanner(cmd.Stdout),
|
from: scanner,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// diffIndexCmdArgs returns a string slice containing the arguments necessary
|
|
||||||
// to run the diff-index command.
|
|
||||||
func diffIndexCmdArgs(ref string, cached bool) []string {
|
|
||||||
args := []string{"diff-index", "-M"}
|
|
||||||
if cached {
|
|
||||||
args = append(args, "--cached")
|
|
||||||
}
|
|
||||||
args = append(args, ref)
|
|
||||||
|
|
||||||
return args
|
|
||||||
}
|
|
||||||
|
|
||||||
// Scan advances the scan line and yields either a new value for Entry(), or an
|
// Scan advances the scan line and yields either a new value for Entry(), or an
|
||||||
// Err(). It returns true or false, whether or not it can continue scanning for
|
// Err(). It returns true or false, whether or not it can continue scanning for
|
||||||
// more entries.
|
// more entries.
|
||||||
|
@ -5,6 +5,8 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
|
"github.com/git-lfs/git-lfs/git"
|
||||||
)
|
)
|
||||||
|
|
||||||
// runCatFileBatchCheck uses 'git cat-file --batch-check' to get the type and
|
// runCatFileBatchCheck uses 'git cat-file --batch-check' to get the type and
|
||||||
@ -13,7 +15,7 @@ import (
|
|||||||
// over which strings containing git sha1s will be sent. It returns a channel
|
// over which strings containing git sha1s will be sent. It returns a channel
|
||||||
// from which sha1 strings can be read.
|
// from which sha1 strings can be read.
|
||||||
func runCatFileBatchCheck(smallRevCh chan string, lockableCh chan string, lockableSet *lockableNameSet, revs *StringChannelWrapper, errCh chan error) error {
|
func runCatFileBatchCheck(smallRevCh chan string, lockableCh chan string, lockableSet *lockableNameSet, revs *StringChannelWrapper, errCh chan error) error {
|
||||||
cmd, err := startCommand("git", "cat-file", "--batch-check")
|
cmd, err := git.CatFile()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -1,49 +0,0 @@
|
|||||||
package lfs
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bufio"
|
|
||||||
"io"
|
|
||||||
"os/exec"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/rubyist/tracerx"
|
|
||||||
)
|
|
||||||
|
|
||||||
type wrappedCmd struct {
|
|
||||||
Stdin io.WriteCloser
|
|
||||||
Stdout *bufio.Reader
|
|
||||||
Stderr *bufio.Reader
|
|
||||||
*exec.Cmd
|
|
||||||
}
|
|
||||||
|
|
||||||
// startCommand starts up a command and creates a stdin pipe and a buffered
|
|
||||||
// stdout & stderr pipes, wrapped in a wrappedCmd. The stdout buffer will be of stdoutBufSize
|
|
||||||
// bytes.
|
|
||||||
func startCommand(command string, args ...string) (*wrappedCmd, error) {
|
|
||||||
cmd := exec.Command(command, args...)
|
|
||||||
stdout, err := cmd.StdoutPipe()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
stderr, err := cmd.StderrPipe()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
stdin, err := cmd.StdinPipe()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
tracerx.Printf("run_command: %s %s", command, strings.Join(args, " "))
|
|
||||||
if err := cmd.Start(); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return &wrappedCmd{
|
|
||||||
stdin,
|
|
||||||
bufio.NewReaderSize(stdout, stdoutBufSize),
|
|
||||||
bufio.NewReaderSize(stderr, stdoutBufSize),
|
|
||||||
cmd,
|
|
||||||
}, nil
|
|
||||||
}
|
|
@ -11,6 +11,7 @@ import (
|
|||||||
|
|
||||||
"github.com/git-lfs/git-lfs/filepathfilter"
|
"github.com/git-lfs/git-lfs/filepathfilter"
|
||||||
"github.com/git-lfs/git-lfs/git"
|
"github.com/git-lfs/git-lfs/git"
|
||||||
|
"github.com/git-lfs/git-lfs/subprocess"
|
||||||
"github.com/rubyist/tracerx"
|
"github.com/rubyist/tracerx"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -40,7 +41,7 @@ type gitscannerResult struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func scanUnpushed(cb GitScannerFoundPointer, remote string) error {
|
func scanUnpushed(cb GitScannerFoundPointer, remote string) error {
|
||||||
logArgs := []string{"log",
|
logArgs := []string{
|
||||||
"--branches", "--tags", // include all locally referenced commits
|
"--branches", "--tags", // include all locally referenced commits
|
||||||
"--not"} // but exclude everything that comes after
|
"--not"} // but exclude everything that comes after
|
||||||
|
|
||||||
@ -53,7 +54,7 @@ func scanUnpushed(cb GitScannerFoundPointer, remote string) error {
|
|||||||
// Add standard search args to find lfs references
|
// Add standard search args to find lfs references
|
||||||
logArgs = append(logArgs, logLfsSearchArgs...)
|
logArgs = append(logArgs, logLfsSearchArgs...)
|
||||||
|
|
||||||
cmd, err := startCommand("git", logArgs...)
|
cmd, err := git.Log(logArgs...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -62,7 +63,7 @@ func scanUnpushed(cb GitScannerFoundPointer, remote string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseScannerLogOutput(cb GitScannerFoundPointer, direction LogDiffDirection, cmd *wrappedCmd) {
|
func parseScannerLogOutput(cb GitScannerFoundPointer, direction LogDiffDirection, cmd *subprocess.BufferedCmd) {
|
||||||
ch := make(chan gitscannerResult, chanBufSize)
|
ch := make(chan gitscannerResult, chanBufSize)
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
@ -89,7 +90,7 @@ func parseScannerLogOutput(cb GitScannerFoundPointer, direction LogDiffDirection
|
|||||||
// logPreviousVersions scans history for all previous versions of LFS pointers
|
// logPreviousVersions scans history for all previous versions of LFS pointers
|
||||||
// from 'since' up to (but not including) the final state at ref
|
// from 'since' up to (but not including) the final state at ref
|
||||||
func logPreviousSHAs(cb GitScannerFoundPointer, ref string, since time.Time) error {
|
func logPreviousSHAs(cb GitScannerFoundPointer, ref string, since time.Time) error {
|
||||||
logArgs := []string{"log",
|
logArgs := []string{
|
||||||
fmt.Sprintf("--since=%v", git.FormatGitDate(since)),
|
fmt.Sprintf("--since=%v", git.FormatGitDate(since)),
|
||||||
}
|
}
|
||||||
// Add standard search args to find lfs references
|
// Add standard search args to find lfs references
|
||||||
@ -97,7 +98,7 @@ func logPreviousSHAs(cb GitScannerFoundPointer, ref string, since time.Time) err
|
|||||||
// ending at ref
|
// ending at ref
|
||||||
logArgs = append(logArgs, ref)
|
logArgs = append(logArgs, ref)
|
||||||
|
|
||||||
cmd, err := startCommand("git", logArgs...)
|
cmd, err := git.Log(logArgs...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/git-lfs/git-lfs/filepathfilter"
|
"github.com/git-lfs/git-lfs/filepathfilter"
|
||||||
|
"github.com/git-lfs/git-lfs/git"
|
||||||
)
|
)
|
||||||
|
|
||||||
// An entry from ls-tree or rev-list including a blob sha and tree path
|
// An entry from ls-tree or rev-list including a blob sha and tree path
|
||||||
@ -94,14 +95,7 @@ func catFileBatchTree(treeblobs *TreeBlobChannelWrapper) (*PointerChannelWrapper
|
|||||||
// The returned channel will be sent these blobs which should be sent to catFileBatchTree
|
// The returned channel will be sent these blobs which should be sent to catFileBatchTree
|
||||||
// for final check & conversion to Pointer
|
// for final check & conversion to Pointer
|
||||||
func lsTreeBlobs(ref string, filter *filepathfilter.Filter) (*TreeBlobChannelWrapper, error) {
|
func lsTreeBlobs(ref string, filter *filepathfilter.Filter) (*TreeBlobChannelWrapper, error) {
|
||||||
cmd, err := startCommand("git", "ls-tree",
|
cmd, err := git.LsTree(ref)
|
||||||
"-r", // recurse
|
|
||||||
"-l", // report object size (we'll need this)
|
|
||||||
"-z", // null line termination
|
|
||||||
"--full-tree", // start at the root regardless of where we are in it
|
|
||||||
ref,
|
|
||||||
)
|
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
19
subprocess/buffered_cmd.go
Normal file
19
subprocess/buffered_cmd.go
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
package subprocess
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"io"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// stdoutBufSize is the size of the buffers given to a sub-process stdout
|
||||||
|
stdoutBufSize = 16384
|
||||||
|
)
|
||||||
|
|
||||||
|
type BufferedCmd struct {
|
||||||
|
*Cmd
|
||||||
|
|
||||||
|
Stdin io.WriteCloser
|
||||||
|
Stdout *bufio.Reader
|
||||||
|
Stderr *bufio.Reader
|
||||||
|
}
|
@ -3,6 +3,7 @@
|
|||||||
package subprocess
|
package subprocess
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bufio"
|
||||||
"bytes"
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
@ -13,6 +14,37 @@ import (
|
|||||||
"github.com/rubyist/tracerx"
|
"github.com/rubyist/tracerx"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// BufferedExec starts up a command and creates a stdin pipe and a buffered
|
||||||
|
// stdout & stderr pipes, wrapped in a BufferedCmd. The stdout buffer will be
|
||||||
|
// of stdoutBufSize bytes.
|
||||||
|
func BufferedExec(name string, args ...string) (*BufferedCmd, error) {
|
||||||
|
cmd := ExecCommand(name, args...)
|
||||||
|
stdout, err := cmd.StdoutPipe()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
stderr, err := cmd.StderrPipe()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
stdin, err := cmd.StdinPipe()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := cmd.Start(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &BufferedCmd{
|
||||||
|
cmd,
|
||||||
|
stdin,
|
||||||
|
bufio.NewReaderSize(stdout, stdoutBufSize),
|
||||||
|
bufio.NewReaderSize(stderr, stdoutBufSize),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
// SimpleExec is a small wrapper around os/exec.Command.
|
// SimpleExec is a small wrapper around os/exec.Command.
|
||||||
func SimpleExec(name string, args ...string) (string, error) {
|
func SimpleExec(name string, args ...string) (string, error) {
|
||||||
tracerx.Printf("run_command: '%s' %s", name, strings.Join(args, " "))
|
tracerx.Printf("run_command: '%s' %s", name, strings.Join(args, " "))
|
||||||
|
@ -69,21 +69,21 @@ begin_test "post-checkout"
|
|||||||
[ ! -e file5.dat ]
|
[ ! -e file5.dat ]
|
||||||
[ ! -e file6.big ]
|
[ ! -e file6.big ]
|
||||||
# without the post-checkout hook, any changed files would now be writeable
|
# without the post-checkout hook, any changed files would now be writeable
|
||||||
refute_file_writable file1.dat
|
refute_file_writeable file1.dat
|
||||||
refute_file_writable file2.dat
|
refute_file_writeable file2.dat
|
||||||
assert_file_writable file3.big
|
assert_file_writeable file3.big
|
||||||
assert_file_writable file4.big
|
assert_file_writeable file4.big
|
||||||
|
|
||||||
# checkout branch
|
# checkout branch
|
||||||
git checkout branch2
|
git checkout branch2
|
||||||
[ -e file5.dat ]
|
[ -e file5.dat ]
|
||||||
[ -e file6.big ]
|
[ -e file6.big ]
|
||||||
refute_file_writable file1.dat
|
refute_file_writeable file1.dat
|
||||||
refute_file_writable file2.dat
|
refute_file_writeable file2.dat
|
||||||
refute_file_writable file5.dat
|
refute_file_writeable file5.dat
|
||||||
assert_file_writable file3.big
|
assert_file_writeable file3.big
|
||||||
assert_file_writable file4.big
|
assert_file_writeable file4.big
|
||||||
assert_file_writable file6.big
|
assert_file_writeable file6.big
|
||||||
|
|
||||||
# Confirm that contents of existing files were updated even though were read-only
|
# Confirm that contents of existing files were updated even though were read-only
|
||||||
[ "$(cat file2.dat)" == "file 2 updated in branch2" ]
|
[ "$(cat file2.dat)" == "file 2 updated in branch2" ]
|
||||||
@ -99,20 +99,20 @@ begin_test "post-checkout"
|
|||||||
[ "$(cat file1.dat)" == "file 1 updated commit 2" ]
|
[ "$(cat file1.dat)" == "file 1 updated commit 2" ]
|
||||||
[ "$(cat file2.dat)" == "file 2 updated in branch2" ]
|
[ "$(cat file2.dat)" == "file 2 updated in branch2" ]
|
||||||
[ "$(cat file5.dat)" == "file 5 creation in branch2" ]
|
[ "$(cat file5.dat)" == "file 5 creation in branch2" ]
|
||||||
refute_file_writable file1.dat
|
refute_file_writeable file1.dat
|
||||||
refute_file_writable file2.dat
|
refute_file_writeable file2.dat
|
||||||
refute_file_writable file5.dat
|
refute_file_writeable file5.dat
|
||||||
|
|
||||||
# now lock files, then remove & restore
|
# now lock files, then remove & restore
|
||||||
git lfs lock file1.dat
|
git lfs lock file1.dat
|
||||||
git lfs lock file2.dat
|
git lfs lock file2.dat
|
||||||
assert_file_writable file1.dat
|
assert_file_writeable file1.dat
|
||||||
assert_file_writable file2.dat
|
assert_file_writeable file2.dat
|
||||||
rm -f *.dat
|
rm -f *.dat
|
||||||
git checkout file1.dat file2.dat file5.dat
|
git checkout file1.dat file2.dat file5.dat
|
||||||
assert_file_writable file1.dat
|
assert_file_writeable file1.dat
|
||||||
assert_file_writable file2.dat
|
assert_file_writeable file2.dat
|
||||||
refute_file_writable file5.dat
|
refute_file_writeable file5.dat
|
||||||
|
|
||||||
)
|
)
|
||||||
end_test
|
end_test
|
||||||
|
@ -25,10 +25,10 @@ begin_test "post-commit"
|
|||||||
git commit -m "Committed large files"
|
git commit -m "Committed large files"
|
||||||
|
|
||||||
# New lockable files should have been made read-only now since not locked
|
# New lockable files should have been made read-only now since not locked
|
||||||
refute_file_writable pcfile1.dat
|
refute_file_writeable pcfile1.dat
|
||||||
refute_file_writable pcfile2.dat
|
refute_file_writeable pcfile2.dat
|
||||||
assert_file_writable pcfile3.big
|
assert_file_writeable pcfile3.big
|
||||||
assert_file_writable pcfile4.big
|
assert_file_writeable pcfile4.big
|
||||||
|
|
||||||
git push -u origin master
|
git push -u origin master
|
||||||
|
|
||||||
@ -43,8 +43,8 @@ begin_test "post-commit"
|
|||||||
git commit -m "Updated"
|
git commit -m "Updated"
|
||||||
|
|
||||||
# files should remain writeable since locked
|
# files should remain writeable since locked
|
||||||
assert_file_writable pcfile1.dat
|
assert_file_writeable pcfile1.dat
|
||||||
assert_file_writable pcfile2.dat
|
assert_file_writeable pcfile2.dat
|
||||||
|
|
||||||
)
|
)
|
||||||
end_test
|
end_test
|
||||||
|
@ -70,25 +70,25 @@ begin_test "post-merge"
|
|||||||
[ ! -e file5.dat ]
|
[ ! -e file5.dat ]
|
||||||
[ ! -e file6.big ]
|
[ ! -e file6.big ]
|
||||||
# without the post-checkout hook, any changed files would now be writeable
|
# without the post-checkout hook, any changed files would now be writeable
|
||||||
refute_file_writable file1.dat
|
refute_file_writeable file1.dat
|
||||||
refute_file_writable file2.dat
|
refute_file_writeable file2.dat
|
||||||
assert_file_writable file3.big
|
assert_file_writeable file3.big
|
||||||
assert_file_writable file4.big
|
assert_file_writeable file4.big
|
||||||
|
|
||||||
# merge branch, with readonly option disabled to demonstrate what would happen
|
# merge branch, with readonly option disabled to demonstrate what would happen
|
||||||
GIT_LFS_SET_LOCKABLE_READONLY=0 git merge origin/branch2
|
GIT_LFS_SET_LOCKABLE_READONLY=0 git merge origin/branch2
|
||||||
# branch2 had hanges to file2.dat and file5.dat which were lockable
|
# branch2 had hanges to file2.dat and file5.dat which were lockable
|
||||||
# but because we disabled the readonly feature they will be writeable now
|
# but because we disabled the readonly feature they will be writeable now
|
||||||
assert_file_writable file2.dat
|
assert_file_writeable file2.dat
|
||||||
assert_file_writable file5.dat
|
assert_file_writeable file5.dat
|
||||||
|
|
||||||
# now let's do it again with the readonly option enabled
|
# now let's do it again with the readonly option enabled
|
||||||
git reset --hard HEAD^
|
git reset --hard HEAD^
|
||||||
git merge origin/branch2
|
git merge origin/branch2
|
||||||
|
|
||||||
# This time they should be read-only
|
# This time they should be read-only
|
||||||
refute_file_writable file2.dat
|
refute_file_writeable file2.dat
|
||||||
refute_file_writable file5.dat
|
refute_file_writeable file5.dat
|
||||||
|
|
||||||
# Confirm that contents of existing files were updated even though were read-only
|
# Confirm that contents of existing files were updated even though were read-only
|
||||||
[ "$(cat file2.dat)" == "file 2 updated in branch2" ]
|
[ "$(cat file2.dat)" == "file 2 updated in branch2" ]
|
||||||
|
@ -411,10 +411,10 @@ begin_test "track lockable read-only/read-write"
|
|||||||
echo "sub blah blah" > subfolder/test.bin
|
echo "sub blah blah" > subfolder/test.bin
|
||||||
echo "sub foo bar" > subfolder/test.dat
|
echo "sub foo bar" > subfolder/test.dat
|
||||||
# should start writeable
|
# should start writeable
|
||||||
assert_file_writable test.bin
|
assert_file_writeable test.bin
|
||||||
assert_file_writable test.dat
|
assert_file_writeable test.dat
|
||||||
assert_file_writable subfolder/test.bin
|
assert_file_writeable subfolder/test.bin
|
||||||
assert_file_writable subfolder/test.dat
|
assert_file_writeable subfolder/test.dat
|
||||||
|
|
||||||
# track *.bin, not lockable yet
|
# track *.bin, not lockable yet
|
||||||
git lfs track "*.bin" | grep "Tracking \"\*.bin\""
|
git lfs track "*.bin" | grep "Tracking \"\*.bin\""
|
||||||
@ -423,28 +423,28 @@ begin_test "track lockable read-only/read-write"
|
|||||||
|
|
||||||
# bin should remain writeable, dat should have been made read-only
|
# bin should remain writeable, dat should have been made read-only
|
||||||
|
|
||||||
assert_file_writable test.bin
|
assert_file_writeable test.bin
|
||||||
refute_file_writable test.dat
|
refute_file_writeable test.dat
|
||||||
assert_file_writable subfolder/test.bin
|
assert_file_writeable subfolder/test.bin
|
||||||
refute_file_writable subfolder/test.dat
|
refute_file_writeable subfolder/test.dat
|
||||||
|
|
||||||
git add .gitattributes test.bin test.dat
|
git add .gitattributes test.bin test.dat
|
||||||
git commit -m "First commit"
|
git commit -m "First commit"
|
||||||
|
|
||||||
# bin should still be writeable
|
# bin should still be writeable
|
||||||
assert_file_writable test.bin
|
assert_file_writeable test.bin
|
||||||
assert_file_writable subfolder/test.bin
|
assert_file_writeable subfolder/test.bin
|
||||||
# now make bin lockable
|
# now make bin lockable
|
||||||
git lfs track --lockable "*.bin" | grep "Tracking \"\*.bin\""
|
git lfs track --lockable "*.bin" | grep "Tracking \"\*.bin\""
|
||||||
# bin should now be read-only
|
# bin should now be read-only
|
||||||
refute_file_writable test.bin
|
refute_file_writeable test.bin
|
||||||
refute_file_writable subfolder/test.bin
|
refute_file_writeable subfolder/test.bin
|
||||||
|
|
||||||
# remove lockable again
|
# remove lockable again
|
||||||
git lfs track --not-lockable "*.bin" | grep "Tracking \"\*.bin\""
|
git lfs track --not-lockable "*.bin" | grep "Tracking \"\*.bin\""
|
||||||
# bin should now be writeable again
|
# bin should now be writeable again
|
||||||
assert_file_writable test.bin
|
assert_file_writeable test.bin
|
||||||
assert_file_writable subfolder/test.bin
|
assert_file_writeable subfolder/test.bin
|
||||||
)
|
)
|
||||||
end_test
|
end_test
|
||||||
|
|
||||||
|
@ -208,11 +208,11 @@ assert_attributes_count() {
|
|||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
assert_file_writable() {
|
assert_file_writeable() {
|
||||||
ls -l "$1" | grep -e "^-rw"
|
ls -l "$1" | grep -e "^-rw"
|
||||||
}
|
}
|
||||||
|
|
||||||
refute_file_writable() {
|
refute_file_writeable() {
|
||||||
ls -l "$1" | grep -e "^-r-"
|
ls -l "$1" | grep -e "^-r-"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user