2014-06-03 15:08:58 +00:00
|
|
|
package commands
|
2013-09-22 23:04:06 +00:00
|
|
|
|
|
|
|
import (
|
2014-06-05 18:19:30 +00:00
|
|
|
"bytes"
|
|
|
|
"fmt"
|
|
|
|
"io"
|
|
|
|
"log"
|
2017-09-11 09:42:47 +00:00
|
|
|
"net"
|
2013-09-22 23:04:06 +00:00
|
|
|
"os"
|
2013-09-27 14:39:45 +00:00
|
|
|
"path/filepath"
|
2014-06-05 18:19:30 +00:00
|
|
|
"strings"
|
2017-01-04 23:10:30 +00:00
|
|
|
"sync"
|
2014-06-05 18:19:30 +00:00
|
|
|
"time"
|
2015-05-13 19:43:41 +00:00
|
|
|
|
2021-09-01 19:41:10 +00:00
|
|
|
"github.com/git-lfs/git-lfs/v3/config"
|
|
|
|
"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/lfsapi"
|
|
|
|
"github.com/git-lfs/git-lfs/v3/locking"
|
|
|
|
"github.com/git-lfs/git-lfs/v3/subprocess"
|
|
|
|
"github.com/git-lfs/git-lfs/v3/tools"
|
|
|
|
"github.com/git-lfs/git-lfs/v3/tq"
|
2022-01-28 05:49:32 +00:00
|
|
|
"github.com/git-lfs/git-lfs/v3/tr"
|
2013-09-22 23:04:06 +00:00
|
|
|
)
|
|
|
|
|
2015-09-14 11:33:59 +00:00
|
|
|
// Populate man pages
|
|
|
|
//go:generate go run ../docs/man/mangen.go
|
|
|
|
|
2014-06-05 18:19:30 +00:00
|
|
|
var (
|
2016-09-01 14:46:26 +00:00
|
|
|
Debugging = false
|
|
|
|
ErrorBuffer = &bytes.Buffer{}
|
2018-11-03 15:15:59 +00:00
|
|
|
ErrorWriter = newMultiWriter(os.Stderr, ErrorBuffer)
|
|
|
|
OutputWriter = newMultiWriter(os.Stdout, ErrorBuffer)
|
2016-09-01 14:46:26 +00:00
|
|
|
ManPages = make(map[string]string, 20)
|
2017-10-19 00:09:33 +00:00
|
|
|
tqManifest = make(map[string]*tq.Manifest)
|
2016-09-01 15:21:48 +00:00
|
|
|
|
2017-10-19 00:09:33 +00:00
|
|
|
cfg *config.Configuration
|
|
|
|
apiClient *lfsapi.Client
|
|
|
|
global sync.Mutex
|
2017-01-04 23:10:30 +00:00
|
|
|
|
2020-10-02 18:20:26 +00:00
|
|
|
oldEnv = make(map[string]string)
|
|
|
|
|
2016-08-10 15:33:25 +00:00
|
|
|
includeArg string
|
|
|
|
excludeArg string
|
|
|
|
)
|
|
|
|
|
2017-01-04 23:10:30 +00:00
|
|
|
// getTransferManifest builds a tq.Manifest from the global os and git
|
2017-01-03 23:01:45 +00:00
|
|
|
// environments.
|
2017-01-04 23:10:30 +00:00
|
|
|
func getTransferManifest() *tq.Manifest {
|
2017-09-17 10:43:35 +00:00
|
|
|
return getTransferManifestOperationRemote("", "")
|
|
|
|
}
|
|
|
|
|
|
|
|
// getTransferManifestOperationRemote builds a tq.Manifest from the global os
|
|
|
|
// and git environments and operation-specific and remote-specific settings.
|
|
|
|
// Operation must be "download", "upload", or the empty string.
|
|
|
|
func getTransferManifestOperationRemote(operation, remote string) *tq.Manifest {
|
2017-01-04 23:10:30 +00:00
|
|
|
c := getAPIClient()
|
|
|
|
|
|
|
|
global.Lock()
|
|
|
|
defer global.Unlock()
|
|
|
|
|
2017-09-17 10:43:35 +00:00
|
|
|
k := fmt.Sprintf("%s.%s", operation, remote)
|
|
|
|
if tqManifest[k] == nil {
|
2017-10-25 17:46:37 +00:00
|
|
|
tqManifest[k] = tq.NewManifest(cfg.Filesystem(), c, operation, remote)
|
2017-01-04 23:10:30 +00:00
|
|
|
}
|
|
|
|
|
2017-09-17 10:43:35 +00:00
|
|
|
return tqManifest[k]
|
2017-01-03 23:07:57 +00:00
|
|
|
}
|
|
|
|
|
2017-01-04 23:10:30 +00:00
|
|
|
func getAPIClient() *lfsapi.Client {
|
|
|
|
global.Lock()
|
|
|
|
defer global.Unlock()
|
|
|
|
|
|
|
|
if apiClient == nil {
|
2017-10-25 21:33:20 +00:00
|
|
|
c, err := lfsapi.NewClient(cfg)
|
2017-01-04 23:10:30 +00:00
|
|
|
if err != nil {
|
|
|
|
ExitWithError(err)
|
|
|
|
}
|
|
|
|
apiClient = c
|
2016-12-22 23:59:54 +00:00
|
|
|
}
|
2017-01-04 23:10:30 +00:00
|
|
|
return apiClient
|
2016-12-22 23:59:54 +00:00
|
|
|
}
|
|
|
|
|
2017-09-29 17:46:13 +00:00
|
|
|
func closeAPIClient() error {
|
|
|
|
global.Lock()
|
|
|
|
defer global.Unlock()
|
|
|
|
if apiClient == nil {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
return apiClient.Close()
|
|
|
|
}
|
|
|
|
|
2017-10-27 21:07:32 +00:00
|
|
|
func newLockClient() *locking.Client {
|
2018-12-05 16:15:52 +00:00
|
|
|
lockClient, err := locking.NewClient(cfg.PushRemote(), getAPIClient(), cfg)
|
2017-01-03 21:13:59 +00:00
|
|
|
if err == nil {
|
2018-12-05 16:15:52 +00:00
|
|
|
tools.MkdirAll(cfg.LFSStorageDir(), cfg)
|
2017-10-24 21:58:42 +00:00
|
|
|
err = lockClient.SetupFileCache(cfg.LFSStorageDir())
|
2017-01-03 21:13:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if err != nil {
|
2022-01-28 05:49:32 +00:00
|
|
|
Exit(tr.Tr.Get("Unable to create lock system: %v", err.Error()))
|
2017-01-03 21:13:59 +00:00
|
|
|
}
|
|
|
|
|
2017-01-16 14:59:55 +00:00
|
|
|
// Configure dirs
|
2017-10-19 00:09:33 +00:00
|
|
|
lockClient.LocalWorkingDir = cfg.LocalWorkingDir()
|
|
|
|
lockClient.LocalGitDir = cfg.LocalGitDir()
|
2017-08-18 00:00:58 +00:00
|
|
|
lockClient.SetLockableFilesReadOnly = cfg.SetLockableFilesReadOnly()
|
2017-01-16 14:59:55 +00:00
|
|
|
|
2017-01-03 21:13:59 +00:00
|
|
|
return lockClient
|
|
|
|
}
|
|
|
|
|
2016-12-13 20:58:09 +00:00
|
|
|
// newDownloadCheckQueue builds a checking queue, checks that objects are there but doesn't download
|
2017-01-04 21:46:30 +00:00
|
|
|
func newDownloadCheckQueue(manifest *tq.Manifest, remote string, options ...tq.Option) *tq.TransferQueue {
|
2018-01-05 18:12:57 +00:00
|
|
|
return newDownloadQueue(manifest, remote, append(options,
|
|
|
|
tq.DryRun(true),
|
|
|
|
)...)
|
2016-12-13 20:58:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// newDownloadQueue builds a DownloadQueue, allowing concurrent downloads.
|
2017-01-04 21:46:30 +00:00
|
|
|
func newDownloadQueue(manifest *tq.Manifest, remote string, options ...tq.Option) *tq.TransferQueue {
|
2018-01-05 18:12:57 +00:00
|
|
|
return tq.NewTransferQueue(tq.Download, manifest, remote, append(options,
|
|
|
|
tq.RemoteRef(currentRemoteRef()),
|
|
|
|
)...)
|
|
|
|
}
|
|
|
|
|
|
|
|
func currentRemoteRef() *git.Ref {
|
commands,git,lfs: rename left/right RefUpdate vars
Since at least PR #2706, and indeed earlier, the local and remote
refs which are part of the RefUpdate structure have been referred
to as the "left" and "right" refs, terminology which stems from
the origin of this structure in the "git lfs pre-push" hook command,
where each line of input contains commit information in the form:
<local ref> <local sha1> <remote ref> <remote sha1>
However, outside of this context, "left" and "right" are ambiguous
terms, and may potentially be confused with the left and right
refs specified in a Git-style two-dot range notation. We therefore
replace these terms with "local" and "remote", which should help
clarify their purpose throughout the codebase.
2022-02-07 03:09:53 +00:00
|
|
|
return git.NewRefUpdate(cfg.Git, cfg.PushRemote(), cfg.CurrentRef(), nil).RemoteRef()
|
2016-12-13 20:58:09 +00:00
|
|
|
}
|
|
|
|
|
2020-03-27 19:02:58 +00:00
|
|
|
func buildFilepathFilter(config *config.Configuration, includeArg, excludeArg *string, useFetchOptions bool) *filepathfilter.Filter {
|
commands,t: gitattributes migrate filepath parsing
The --include and --exclude (-I and -X) options to the
"git lfs migrate" command allow the user to specify filepath
filters which select matching files to migrate and which are
also used to populate any .gitattributes files written by the
import or export operations.
This latter functionality implies that we need to parse
any filepath patterns supplied by these options using
gitattributes(5) rules, since the patterns will be copied
directly into .gitattributes files. (See the use of the
trackedFromFilter() and trackedFromExportFilter() functions
in particular.)
However, all other Git LFS commands which parse --include
and --exclude options, such as "git lfs fetch" and
"git lfs ls-files", expect to treat any supplied patterns
according to gitignore(5) rules. (This aligns with, for
instance, how the -x option to "git ls-files" works.)
We therefore introduce a buildFilepathFilterWithPatternType()
function which the "git lfs migrate" command can use to
specify the filepathfilter.GitAttributes parsing mode for
its filter, while the other commands continue to use the
filepathfilter.GitIgnore mode.
Note that this change change will have several consequences.
On one hand, patterns such as "*.bin" will only match against
files, not directories, which will restore the behaviour of
"git lfs migrate" in this regard prior to v3.0.0 and the
changes from PR #4556.
On the other hand, patterns such as "foo" will no longer
recursively match everything inside a directory, and "foo/**"
must be used instead. This is in line with how Git's native
gitattributes(5) matching works.
We therefore adjust one existing test to use a directory
match of the form "foo/**" instead of "foo", and add one new
test which confirms that only files named "*.txt" match a
pattern of that form, instead of all files in any directory
whose name has that form, such as a file like "foo.txt/bar.md".
This new test fails without the changes to the "git lfs migrate"
command introduced in this commit.
2021-12-03 00:09:35 +00:00
|
|
|
return buildFilepathFilterWithPatternType(config, includeArg, excludeArg, useFetchOptions, filepathfilter.GitIgnore)
|
|
|
|
}
|
|
|
|
|
|
|
|
func buildFilepathFilterWithPatternType(config *config.Configuration, includeArg, excludeArg *string, useFetchOptions bool, patternType filepathfilter.PatternType) *filepathfilter.Filter {
|
2020-03-27 19:02:58 +00:00
|
|
|
inc, exc := determineIncludeExcludePaths(config, includeArg, excludeArg, useFetchOptions)
|
commands,t: gitattributes migrate filepath parsing
The --include and --exclude (-I and -X) options to the
"git lfs migrate" command allow the user to specify filepath
filters which select matching files to migrate and which are
also used to populate any .gitattributes files written by the
import or export operations.
This latter functionality implies that we need to parse
any filepath patterns supplied by these options using
gitattributes(5) rules, since the patterns will be copied
directly into .gitattributes files. (See the use of the
trackedFromFilter() and trackedFromExportFilter() functions
in particular.)
However, all other Git LFS commands which parse --include
and --exclude options, such as "git lfs fetch" and
"git lfs ls-files", expect to treat any supplied patterns
according to gitignore(5) rules. (This aligns with, for
instance, how the -x option to "git ls-files" works.)
We therefore introduce a buildFilepathFilterWithPatternType()
function which the "git lfs migrate" command can use to
specify the filepathfilter.GitAttributes parsing mode for
its filter, while the other commands continue to use the
filepathfilter.GitIgnore mode.
Note that this change change will have several consequences.
On one hand, patterns such as "*.bin" will only match against
files, not directories, which will restore the behaviour of
"git lfs migrate" in this regard prior to v3.0.0 and the
changes from PR #4556.
On the other hand, patterns such as "foo" will no longer
recursively match everything inside a directory, and "foo/**"
must be used instead. This is in line with how Git's native
gitattributes(5) matching works.
We therefore adjust one existing test to use a directory
match of the form "foo/**" instead of "foo", and add one new
test which confirms that only files named "*.txt" match a
pattern of that form, instead of all files in any directory
whose name has that form, such as a file like "foo.txt/bar.md".
This new test fails without the changes to the "git lfs migrate"
command introduced in this commit.
2021-12-03 00:09:35 +00:00
|
|
|
return filepathfilter.New(inc, exc, patternType)
|
2016-08-10 16:08:08 +00:00
|
|
|
}
|
2014-06-05 18:19:30 +00:00
|
|
|
|
2020-02-10 15:52:15 +00:00
|
|
|
func downloadTransfer(p *lfs.WrappedPointer) (name, path, oid string, size int64, missing bool, err error) {
|
|
|
|
path, err = cfg.Filesystem().ObjectPath(p.Oid)
|
|
|
|
return p.Name, path, p.Oid, p.Size, false, err
|
2016-12-15 20:20:41 +00:00
|
|
|
}
|
|
|
|
|
2017-10-18 21:42:00 +00:00
|
|
|
// Get user-readable manual install steps for hooks
|
|
|
|
func getHookInstallSteps() string {
|
commands,config: permit (*configuration).HookDir() to error
In preparation for (*configuration).HookDir() to perform home-directory
path expansion (e.g., expanding "~" to "/home/ttaylorr"), let's permit
this function to return an error, should the path expansion fail.
Path expansion can fail in any number of ways: either the current user
does not have a home directory, the named user (e.g., "~user") does not
have a home directory, or the named user does not exist.
Instead of either (1) throwing the error from such a case away, or (2)
rolling that error up into a panic(), let's allow ourselves a space to
propagate it outwards.
Since we do not yet support path expansion, let's always return "nil"
for now, and update the call-sites to support non-nil return values,
too.
2018-08-30 19:27:05 +00:00
|
|
|
hookDir, err := cfg.HookDir()
|
|
|
|
if err != nil {
|
|
|
|
ExitWithError(err)
|
|
|
|
}
|
2018-12-05 16:15:52 +00:00
|
|
|
hooks := lfs.LoadHooks(hookDir, cfg)
|
2017-10-18 21:42:00 +00:00
|
|
|
steps := make([]string, 0, len(hooks))
|
|
|
|
for _, h := range hooks {
|
2022-01-28 05:49:32 +00:00
|
|
|
steps = append(steps, fmt.Sprintf("%s\n\n%s",
|
|
|
|
tr.Tr.Get("Add the following to '.git/hooks/%s':", h.Type),
|
|
|
|
tools.Indent(h.Contents)))
|
2017-10-18 21:42:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return strings.Join(steps, "\n\n")
|
|
|
|
}
|
|
|
|
|
|
|
|
func installHooks(force bool) error {
|
commands,config: permit (*configuration).HookDir() to error
In preparation for (*configuration).HookDir() to perform home-directory
path expansion (e.g., expanding "~" to "/home/ttaylorr"), let's permit
this function to return an error, should the path expansion fail.
Path expansion can fail in any number of ways: either the current user
does not have a home directory, the named user (e.g., "~user") does not
have a home directory, or the named user does not exist.
Instead of either (1) throwing the error from such a case away, or (2)
rolling that error up into a panic(), let's allow ourselves a space to
propagate it outwards.
Since we do not yet support path expansion, let's always return "nil"
for now, and update the call-sites to support non-nil return values,
too.
2018-08-30 19:27:05 +00:00
|
|
|
hookDir, err := cfg.HookDir()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2018-12-05 16:15:52 +00:00
|
|
|
hooks := lfs.LoadHooks(hookDir, cfg)
|
2017-10-18 21:42:00 +00:00
|
|
|
for _, h := range hooks {
|
|
|
|
if err := h.Install(force); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// uninstallHooks removes all hooks in range of the `hooks` var.
|
|
|
|
func uninstallHooks() error {
|
2017-10-19 00:25:41 +00:00
|
|
|
if !cfg.InRepo() {
|
2022-01-28 05:49:32 +00:00
|
|
|
return errors.New(tr.Tr.Get("Not in a git repository"))
|
2017-10-19 00:25:41 +00:00
|
|
|
}
|
|
|
|
|
commands,config: permit (*configuration).HookDir() to error
In preparation for (*configuration).HookDir() to perform home-directory
path expansion (e.g., expanding "~" to "/home/ttaylorr"), let's permit
this function to return an error, should the path expansion fail.
Path expansion can fail in any number of ways: either the current user
does not have a home directory, the named user (e.g., "~user") does not
have a home directory, or the named user does not exist.
Instead of either (1) throwing the error from such a case away, or (2)
rolling that error up into a panic(), let's allow ourselves a space to
propagate it outwards.
Since we do not yet support path expansion, let's always return "nil"
for now, and update the call-sites to support non-nil return values,
too.
2018-08-30 19:27:05 +00:00
|
|
|
hookDir, err := cfg.HookDir()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2018-12-05 16:15:52 +00:00
|
|
|
hooks := lfs.LoadHooks(hookDir, cfg)
|
2017-10-18 21:42:00 +00:00
|
|
|
for _, h := range hooks {
|
|
|
|
if err := h.Uninstall(); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2014-06-05 18:19:30 +00:00
|
|
|
// Error prints a formatted message to Stderr. It also gets printed to the
|
|
|
|
// panic log if one is created for this command.
|
|
|
|
func Error(format string, args ...interface{}) {
|
2016-08-18 21:43:28 +00:00
|
|
|
if len(args) == 0 {
|
|
|
|
fmt.Fprintln(ErrorWriter, format)
|
|
|
|
return
|
2015-06-29 16:27:33 +00:00
|
|
|
}
|
2016-08-18 21:43:28 +00:00
|
|
|
fmt.Fprintf(ErrorWriter, format+"\n", args...)
|
2014-06-05 18:19:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Print prints a formatted message to Stdout. It also gets printed to the
|
|
|
|
// panic log if one is created for this command.
|
|
|
|
func Print(format string, args ...interface{}) {
|
2016-08-18 21:43:28 +00:00
|
|
|
if len(args) == 0 {
|
|
|
|
fmt.Fprintln(OutputWriter, format)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
fmt.Fprintf(OutputWriter, format+"\n", args...)
|
2014-06-05 18:19:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Exit prints a formatted message and exits.
|
|
|
|
func Exit(format string, args ...interface{}) {
|
|
|
|
Error(format, args...)
|
|
|
|
os.Exit(2)
|
|
|
|
}
|
|
|
|
|
2016-08-16 18:03:37 +00:00
|
|
|
// ExitWithError either panics with a full stack trace for fatal errors, or
|
|
|
|
// simply prints the error message and exits immediately.
|
2016-02-23 16:11:52 +00:00
|
|
|
func ExitWithError(err error) {
|
2016-08-16 18:03:37 +00:00
|
|
|
errorWith(err, Panic, Exit)
|
|
|
|
}
|
|
|
|
|
|
|
|
// FullError prints either a full stack trace for fatal errors, or just the
|
|
|
|
// error message.
|
|
|
|
func FullError(err error) {
|
|
|
|
errorWith(err, LoggedError, Error)
|
|
|
|
}
|
|
|
|
|
|
|
|
func errorWith(err error, fatalErrFn func(error, string, ...interface{}), errFn func(string, ...interface{})) {
|
2016-08-18 20:20:33 +00:00
|
|
|
if Debugging || errors.IsFatalError(err) {
|
2016-09-05 22:05:54 +00:00
|
|
|
fatalErrFn(err, "%s", err)
|
2016-08-18 21:43:28 +00:00
|
|
|
return
|
2016-02-23 16:11:52 +00:00
|
|
|
}
|
2016-08-18 21:43:28 +00:00
|
|
|
|
|
|
|
errFn("%s", err)
|
2016-08-17 22:13:36 +00:00
|
|
|
}
|
2016-02-23 16:11:52 +00:00
|
|
|
|
2014-06-05 18:19:30 +00:00
|
|
|
// Debug prints a formatted message if debugging is enabled. The formatted
|
|
|
|
// message also shows up in the panic log, if created.
|
|
|
|
func Debug(format string, args ...interface{}) {
|
|
|
|
if !Debugging {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
log.Printf(format, args...)
|
|
|
|
}
|
|
|
|
|
2016-09-05 22:05:54 +00:00
|
|
|
// LoggedError prints the given message formatted with its arguments (if any) to
|
2017-09-11 09:39:23 +00:00
|
|
|
// Stderr. If an empty string is passed as the "format" argument, only the
|
2016-09-06 16:58:35 +00:00
|
|
|
// standard error logging message will be printed, and the error's body will be
|
|
|
|
// omitted.
|
|
|
|
//
|
|
|
|
// It also writes a stack trace for the error to a log file without exiting.
|
2014-08-07 21:33:29 +00:00
|
|
|
func LoggedError(err error, format string, args ...interface{}) {
|
2016-08-18 21:43:28 +00:00
|
|
|
if len(format) > 0 {
|
|
|
|
Error(format, args...)
|
|
|
|
}
|
2014-06-05 18:19:30 +00:00
|
|
|
file := handlePanic(err)
|
|
|
|
|
|
|
|
if len(file) > 0 {
|
2022-01-28 05:49:32 +00:00
|
|
|
fmt.Fprintf(os.Stderr, "\n%s\n", tr.Tr.Get("Errors logged to '%s'.\nUse `git lfs logs last` to view the log.", file))
|
2014-06-05 18:19:30 +00:00
|
|
|
}
|
2014-08-07 21:33:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Panic prints a formatted message, and writes a stack trace for the error to
|
|
|
|
// a log file before exiting.
|
|
|
|
func Panic(err error, format string, args ...interface{}) {
|
|
|
|
LoggedError(err, format, args...)
|
2014-06-05 18:19:30 +00:00
|
|
|
os.Exit(2)
|
|
|
|
}
|
2013-09-23 00:39:26 +00:00
|
|
|
|
2016-07-22 00:07:23 +00:00
|
|
|
func Cleanup() {
|
2017-10-25 01:16:14 +00:00
|
|
|
if err := cfg.Cleanup(); err != nil {
|
2022-01-28 05:49:32 +00:00
|
|
|
fmt.Fprintln(os.Stderr, tr.Tr.Get("Error clearing old temporary files: %s", err))
|
2016-07-22 00:07:23 +00:00
|
|
|
}
|
2013-09-22 23:04:06 +00:00
|
|
|
}
|
|
|
|
|
2013-10-04 14:44:23 +00:00
|
|
|
func PipeMediaCommand(name string, args ...string) error {
|
|
|
|
return PipeCommand("bin/"+name, args...)
|
|
|
|
}
|
|
|
|
|
2013-10-04 14:42:47 +00:00
|
|
|
func PipeCommand(name string, args ...string) error {
|
2020-12-21 21:08:17 +00:00
|
|
|
cmd := subprocess.ExecCommand(name, args...)
|
2013-10-04 14:42:47 +00:00
|
|
|
cmd.Stdin = os.Stdin
|
|
|
|
cmd.Stderr = os.Stderr
|
|
|
|
cmd.Stdout = os.Stdout
|
|
|
|
return cmd.Run()
|
|
|
|
}
|
|
|
|
|
2015-04-24 20:24:32 +00:00
|
|
|
func requireStdin(msg string) {
|
2016-07-04 23:46:35 +00:00
|
|
|
var out string
|
|
|
|
|
|
|
|
stat, err := os.Stdin.Stat()
|
|
|
|
if err != nil {
|
2022-01-28 05:49:32 +00:00
|
|
|
out = tr.Tr.Get("Cannot read from STDIN: %s (%s)", msg, err)
|
2016-07-04 23:46:35 +00:00
|
|
|
} else if (stat.Mode() & os.ModeCharDevice) != 0 {
|
2022-01-28 05:49:32 +00:00
|
|
|
out = tr.Tr.Get("Cannot read from STDIN: %s", msg)
|
2016-07-04 23:46:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if len(out) > 0 {
|
|
|
|
Error(out)
|
2015-04-24 20:24:32 +00:00
|
|
|
os.Exit(1)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-09-08 16:23:27 +00:00
|
|
|
func requireInRepo() {
|
2017-10-19 00:25:41 +00:00
|
|
|
if !cfg.InRepo() {
|
2022-01-28 05:49:32 +00:00
|
|
|
Print(tr.Tr.Get("Not in a Git repository."))
|
2015-09-08 16:23:27 +00:00
|
|
|
os.Exit(128)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-11-13 18:33:48 +00:00
|
|
|
// requireWorkingCopy requires that the working directory be a work tree, i.e.,
|
|
|
|
// that it not be bare. If it is bare (or the state of the repository could not
|
|
|
|
// be determined), this function will terminate the program.
|
|
|
|
func requireWorkingCopy() {
|
commands: make sure we're in the working tree
In the normal case, Git commands perform repository autodiscovery based
on the current working directory. However, in some cases, it's possible
to specify a Git working tree unrelated to the current working directory
by using GIT_WORK_TREE. In such a case, we want to make sure that we
change into the working tree such that our working directory is always
within the working tree, if one exists. This is what Git does, and it
means that when we write files into the repository, such as a
.gitattributes file, we write them into the proper place.
Note also that we adjust the code to require that the working directory
be non-empty when we require a working copy instead of that the
repository be non-bare. That's because we don't want people to be
working inside of the Git directory in such situations, where the
repository would be non-bare but would not have a working tree.
We add tests for this case for track and untrack, which require a
working tree, and for checkout, which requires only a repository. This
means that we can verify the behavior of the functions we've added
without needing to add tests for this case to each of the subcommands.
2020-10-02 19:03:55 +00:00
|
|
|
if cfg.LocalWorkingDir() == "" {
|
2022-01-28 05:49:32 +00:00
|
|
|
Print(tr.Tr.Get("This operation must be run in a work tree."))
|
commands: make sure we're in the working tree
In the normal case, Git commands perform repository autodiscovery based
on the current working directory. However, in some cases, it's possible
to specify a Git working tree unrelated to the current working directory
by using GIT_WORK_TREE. In such a case, we want to make sure that we
change into the working tree such that our working directory is always
within the working tree, if one exists. This is what Git does, and it
means that when we write files into the repository, such as a
.gitattributes file, we write them into the proper place.
Note also that we adjust the code to require that the working directory
be non-empty when we require a working copy instead of that the
repository be non-bare. That's because we don't want people to be
working inside of the Git directory in such situations, where the
repository would be non-bare but would not have a working tree.
We add tests for this case for track and untrack, which require a
working tree, and for checkout, which requires only a repository. This
means that we can verify the behavior of the functions we've added
without needing to add tests for this case to each of the subcommands.
2020-10-02 19:03:55 +00:00
|
|
|
os.Exit(128)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func setupRepository() {
|
|
|
|
requireInRepo()
|
2018-11-13 18:33:48 +00:00
|
|
|
bare, err := git.IsBare()
|
|
|
|
if err != nil {
|
|
|
|
ExitWithError(errors.Wrap(
|
2022-01-28 05:49:32 +00:00
|
|
|
err, tr.Tr.Get("Could not determine bareness")))
|
2018-11-13 18:33:48 +00:00
|
|
|
}
|
Add support for an LFS repository format version
We've had several proposals to change how data is stored on disk, such
as by compressing files when stored inside the .git directory.
Unfortunately, those proposals are incompatible with how data is stored
now and we would likely break older clients if we implemented them.
To make it possible for us to implement them in the future, let's do
what Git does and add support for a repository format version. We read
the configuration option lfs.repositoryFormatVersion from the local
configuration, and if it is nonzero, we exit with an error. We also
assume that if the value is not set, then it is implicitly 0 and set it
if possible. We ignore any errors when writing to allow working with
read-only repositories in the limited circumstances where that can be
valuable.
The plan in the future is to support repository format v1, which, like
Git's, will be the same but for a set of lfs.repositoryextension.* keys
which denote extensions. Such extensions will be ignored in v0, but
will be mandatory to understand in v1; unknown keys will cause Git LFS
to abort. The implementation of this functionality is left to the
future, however.
2021-06-22 19:51:52 +00:00
|
|
|
verifyRepositoryVersion()
|
2018-11-13 18:33:48 +00:00
|
|
|
|
commands: make sure we're in the working tree
In the normal case, Git commands perform repository autodiscovery based
on the current working directory. However, in some cases, it's possible
to specify a Git working tree unrelated to the current working directory
by using GIT_WORK_TREE. In such a case, we want to make sure that we
change into the working tree such that our working directory is always
within the working tree, if one exists. This is what Git does, and it
means that when we write files into the repository, such as a
.gitattributes file, we write them into the proper place.
Note also that we adjust the code to require that the working directory
be non-empty when we require a working copy instead of that the
repository be non-bare. That's because we don't want people to be
working inside of the Git directory in such situations, where the
repository would be non-bare but would not have a working tree.
We add tests for this case for track and untrack, which require a
working tree, and for checkout, which requires only a repository. This
means that we can verify the behavior of the functions we've added
without needing to add tests for this case to each of the subcommands.
2020-10-02 19:03:55 +00:00
|
|
|
if !bare {
|
|
|
|
changeToWorkingCopy()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
Add support for an LFS repository format version
We've had several proposals to change how data is stored on disk, such
as by compressing files when stored inside the .git directory.
Unfortunately, those proposals are incompatible with how data is stored
now and we would likely break older clients if we implemented them.
To make it possible for us to implement them in the future, let's do
what Git does and add support for a repository format version. We read
the configuration option lfs.repositoryFormatVersion from the local
configuration, and if it is nonzero, we exit with an error. We also
assume that if the value is not set, then it is implicitly 0 and set it
if possible. We ignore any errors when writing to allow working with
read-only repositories in the limited circumstances where that can be
valuable.
The plan in the future is to support repository format v1, which, like
Git's, will be the same but for a set of lfs.repositoryextension.* keys
which denote extensions. Such extensions will be ignored in v0, but
will be mandatory to understand in v1; unknown keys will cause Git LFS
to abort. The implementation of this functionality is left to the
future, however.
2021-06-22 19:51:52 +00:00
|
|
|
func verifyRepositoryVersion() {
|
|
|
|
key := "lfs.repositoryformatversion"
|
|
|
|
val := cfg.FindGitLocalKey(key)
|
|
|
|
if val == "" {
|
|
|
|
cfg.SetGitLocalKey(key, "0")
|
|
|
|
} else if val != "0" {
|
2022-01-28 05:49:32 +00:00
|
|
|
Print(tr.Tr.Get("Unknown repository format version: %s", val))
|
Add support for an LFS repository format version
We've had several proposals to change how data is stored on disk, such
as by compressing files when stored inside the .git directory.
Unfortunately, those proposals are incompatible with how data is stored
now and we would likely break older clients if we implemented them.
To make it possible for us to implement them in the future, let's do
what Git does and add support for a repository format version. We read
the configuration option lfs.repositoryFormatVersion from the local
configuration, and if it is nonzero, we exit with an error. We also
assume that if the value is not set, then it is implicitly 0 and set it
if possible. We ignore any errors when writing to allow working with
read-only repositories in the limited circumstances where that can be
valuable.
The plan in the future is to support repository format v1, which, like
Git's, will be the same but for a set of lfs.repositoryextension.* keys
which denote extensions. Such extensions will be ignored in v0, but
will be mandatory to understand in v1; unknown keys will cause Git LFS
to abort. The implementation of this functionality is left to the
future, however.
2021-06-22 19:51:52 +00:00
|
|
|
os.Exit(128)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
commands: make sure we're in the working tree
In the normal case, Git commands perform repository autodiscovery based
on the current working directory. However, in some cases, it's possible
to specify a Git working tree unrelated to the current working directory
by using GIT_WORK_TREE. In such a case, we want to make sure that we
change into the working tree such that our working directory is always
within the working tree, if one exists. This is what Git does, and it
means that when we write files into the repository, such as a
.gitattributes file, we write them into the proper place.
Note also that we adjust the code to require that the working directory
be non-empty when we require a working copy instead of that the
repository be non-bare. That's because we don't want people to be
working inside of the Git directory in such situations, where the
repository would be non-bare but would not have a working tree.
We add tests for this case for track and untrack, which require a
working tree, and for checkout, which requires only a repository. This
means that we can verify the behavior of the functions we've added
without needing to add tests for this case to each of the subcommands.
2020-10-02 19:03:55 +00:00
|
|
|
func setupWorkingCopy() {
|
|
|
|
requireInRepo()
|
|
|
|
requireWorkingCopy()
|
Add support for an LFS repository format version
We've had several proposals to change how data is stored on disk, such
as by compressing files when stored inside the .git directory.
Unfortunately, those proposals are incompatible with how data is stored
now and we would likely break older clients if we implemented them.
To make it possible for us to implement them in the future, let's do
what Git does and add support for a repository format version. We read
the configuration option lfs.repositoryFormatVersion from the local
configuration, and if it is nonzero, we exit with an error. We also
assume that if the value is not set, then it is implicitly 0 and set it
if possible. We ignore any errors when writing to allow working with
read-only repositories in the limited circumstances where that can be
valuable.
The plan in the future is to support repository format v1, which, like
Git's, will be the same but for a set of lfs.repositoryextension.* keys
which denote extensions. Such extensions will be ignored in v0, but
will be mandatory to understand in v1; unknown keys will cause Git LFS
to abort. The implementation of this functionality is left to the
future, however.
2021-06-22 19:51:52 +00:00
|
|
|
verifyRepositoryVersion()
|
commands: make sure we're in the working tree
In the normal case, Git commands perform repository autodiscovery based
on the current working directory. However, in some cases, it's possible
to specify a Git working tree unrelated to the current working directory
by using GIT_WORK_TREE. In such a case, we want to make sure that we
change into the working tree such that our working directory is always
within the working tree, if one exists. This is what Git does, and it
means that when we write files into the repository, such as a
.gitattributes file, we write them into the proper place.
Note also that we adjust the code to require that the working directory
be non-empty when we require a working copy instead of that the
repository be non-bare. That's because we don't want people to be
working inside of the Git directory in such situations, where the
repository would be non-bare but would not have a working tree.
We add tests for this case for track and untrack, which require a
working tree, and for checkout, which requires only a repository. This
means that we can verify the behavior of the functions we've added
without needing to add tests for this case to each of the subcommands.
2020-10-02 19:03:55 +00:00
|
|
|
changeToWorkingCopy()
|
|
|
|
}
|
|
|
|
|
|
|
|
func changeToWorkingCopy() {
|
|
|
|
workingDir := cfg.LocalWorkingDir()
|
|
|
|
cwd, err := tools.Getwd()
|
|
|
|
if err != nil {
|
|
|
|
ExitWithError(errors.Wrap(
|
2022-01-28 05:49:32 +00:00
|
|
|
err, tr.Tr.Get("Could not determine current working directory")))
|
commands: make sure we're in the working tree
In the normal case, Git commands perform repository autodiscovery based
on the current working directory. However, in some cases, it's possible
to specify a Git working tree unrelated to the current working directory
by using GIT_WORK_TREE. In such a case, we want to make sure that we
change into the working tree such that our working directory is always
within the working tree, if one exists. This is what Git does, and it
means that when we write files into the repository, such as a
.gitattributes file, we write them into the proper place.
Note also that we adjust the code to require that the working directory
be non-empty when we require a working copy instead of that the
repository be non-bare. That's because we don't want people to be
working inside of the Git directory in such situations, where the
repository would be non-bare but would not have a working tree.
We add tests for this case for track and untrack, which require a
working tree, and for checkout, which requires only a repository. This
means that we can verify the behavior of the functions we've added
without needing to add tests for this case to each of the subcommands.
2020-10-02 19:03:55 +00:00
|
|
|
}
|
2021-03-01 16:30:19 +00:00
|
|
|
cwd, err = tools.CanonicalizeSystemPath(cwd)
|
commands: make sure we're in the working tree
In the normal case, Git commands perform repository autodiscovery based
on the current working directory. However, in some cases, it's possible
to specify a Git working tree unrelated to the current working directory
by using GIT_WORK_TREE. In such a case, we want to make sure that we
change into the working tree such that our working directory is always
within the working tree, if one exists. This is what Git does, and it
means that when we write files into the repository, such as a
.gitattributes file, we write them into the proper place.
Note also that we adjust the code to require that the working directory
be non-empty when we require a working copy instead of that the
repository be non-bare. That's because we don't want people to be
working inside of the Git directory in such situations, where the
repository would be non-bare but would not have a working tree.
We add tests for this case for track and untrack, which require a
working tree, and for checkout, which requires only a repository. This
means that we can verify the behavior of the functions we've added
without needing to add tests for this case to each of the subcommands.
2020-10-02 19:03:55 +00:00
|
|
|
if err != nil {
|
|
|
|
ExitWithError(errors.Wrap(
|
2022-01-28 05:49:32 +00:00
|
|
|
err, tr.Tr.Get("Could not canonicalize current working directory")))
|
commands: make sure we're in the working tree
In the normal case, Git commands perform repository autodiscovery based
on the current working directory. However, in some cases, it's possible
to specify a Git working tree unrelated to the current working directory
by using GIT_WORK_TREE. In such a case, we want to make sure that we
change into the working tree such that our working directory is always
within the working tree, if one exists. This is what Git does, and it
means that when we write files into the repository, such as a
.gitattributes file, we write them into the proper place.
Note also that we adjust the code to require that the working directory
be non-empty when we require a working copy instead of that the
repository be non-bare. That's because we don't want people to be
working inside of the Git directory in such situations, where the
repository would be non-bare but would not have a working tree.
We add tests for this case for track and untrack, which require a
working tree, and for checkout, which requires only a repository. This
means that we can verify the behavior of the functions we've added
without needing to add tests for this case to each of the subcommands.
2020-10-02 19:03:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// If the current working directory is not within the repository's
|
|
|
|
// working directory, then let's change directories accordingly. This
|
|
|
|
// should only occur if GIT_WORK_TREE is set.
|
|
|
|
if !(strings.HasPrefix(cwd, workingDir) && (cwd == workingDir || (len(cwd) > len(workingDir) && cwd[len(workingDir)] == os.PathSeparator))) {
|
|
|
|
os.Chdir(workingDir)
|
2018-11-13 18:33:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-10-02 18:20:26 +00:00
|
|
|
func canonicalizeEnvironment() {
|
|
|
|
vars := []string{"GIT_INDEX_FILE", "GIT_OBJECT_DIRECTORY", "GIT_DIR", "GIT_WORK_TREE", "GIT_COMMON_DIR"}
|
|
|
|
for _, v := range vars {
|
|
|
|
val, ok := os.LookupEnv(v)
|
|
|
|
if ok {
|
|
|
|
path, err := tools.CanonicalizePath(val, true)
|
|
|
|
// We have existing code which relies on users being
|
|
|
|
// able to pass invalid paths, so don't fail if the path
|
|
|
|
// cannot be canonicalized.
|
|
|
|
if err == nil {
|
|
|
|
oldEnv[v] = val
|
|
|
|
os.Setenv(v, path)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
subprocess.ResetEnvironment()
|
|
|
|
}
|
|
|
|
|
2014-06-05 18:19:30 +00:00
|
|
|
func handlePanic(err error) string {
|
|
|
|
if err == nil {
|
|
|
|
return ""
|
|
|
|
}
|
|
|
|
|
2015-05-14 17:36:02 +00:00
|
|
|
return logPanic(err)
|
2014-06-05 18:19:30 +00:00
|
|
|
}
|
|
|
|
|
2015-05-14 17:36:02 +00:00
|
|
|
func logPanic(loggedError error) string {
|
2017-04-25 19:00:55 +00:00
|
|
|
var (
|
|
|
|
fmtWriter io.Writer = os.Stderr
|
|
|
|
lineEnding string = "\n"
|
|
|
|
)
|
2014-08-07 21:00:54 +00:00
|
|
|
|
2015-05-14 17:36:02 +00:00
|
|
|
now := time.Now()
|
|
|
|
name := now.Format("20060102T150405.999999999")
|
2017-10-19 00:09:33 +00:00
|
|
|
full := filepath.Join(cfg.LocalLogDir(), name+".log")
|
2015-05-14 17:36:02 +00:00
|
|
|
|
2018-12-05 16:15:52 +00:00
|
|
|
if err := tools.MkdirAll(cfg.LocalLogDir(), cfg); err != nil {
|
2015-05-14 17:39:03 +00:00
|
|
|
full = ""
|
2022-01-28 05:49:32 +00:00
|
|
|
fmt.Fprintf(fmtWriter, "%s\n\n", tr.Tr.Get("Unable to log panic to '%s': %s", cfg.LocalLogDir(), err.Error()))
|
2015-05-14 17:39:03 +00:00
|
|
|
} else if file, err := os.Create(full); err != nil {
|
2015-05-14 17:36:02 +00:00
|
|
|
filename := full
|
|
|
|
full = ""
|
|
|
|
defer func() {
|
2022-01-28 05:49:32 +00:00
|
|
|
fmt.Fprintf(fmtWriter, "%s\n\n", tr.Tr.Get("Unable to log panic to '%s'", filename))
|
2017-04-25 19:00:55 +00:00
|
|
|
logPanicToWriter(fmtWriter, err, lineEnding)
|
2015-05-14 17:36:02 +00:00
|
|
|
}()
|
|
|
|
} else {
|
|
|
|
fmtWriter = file
|
2017-04-25 19:00:55 +00:00
|
|
|
lineEnding = gitLineEnding(cfg.Git)
|
2015-05-14 17:36:02 +00:00
|
|
|
defer file.Close()
|
2014-06-05 18:19:30 +00:00
|
|
|
}
|
|
|
|
|
2017-04-25 19:00:55 +00:00
|
|
|
logPanicToWriter(fmtWriter, loggedError, lineEnding)
|
2015-05-14 17:34:58 +00:00
|
|
|
|
|
|
|
return full
|
|
|
|
}
|
|
|
|
|
2017-09-11 09:42:47 +00:00
|
|
|
func ipAddresses() []string {
|
|
|
|
ips := make([]string, 0, 1)
|
|
|
|
ifaces, err := net.Interfaces()
|
|
|
|
if err != nil {
|
2022-01-28 05:49:32 +00:00
|
|
|
ips = append(ips, tr.Tr.Get("Error getting network interface: %s", err.Error()))
|
2017-09-11 09:42:47 +00:00
|
|
|
return ips
|
|
|
|
}
|
|
|
|
for _, i := range ifaces {
|
|
|
|
if i.Flags&net.FlagUp == 0 {
|
|
|
|
continue // interface down
|
|
|
|
}
|
|
|
|
if i.Flags&net.FlagLoopback != 0 {
|
|
|
|
continue // loopback interface
|
|
|
|
}
|
|
|
|
addrs, _ := i.Addrs()
|
|
|
|
l := make([]string, 0, 1)
|
|
|
|
if err != nil {
|
2022-01-28 05:49:32 +00:00
|
|
|
ips = append(ips, tr.Tr.Get("Error getting IP address: %s", err.Error()))
|
2017-09-11 09:42:47 +00:00
|
|
|
continue
|
|
|
|
}
|
|
|
|
for _, addr := range addrs {
|
|
|
|
var ip net.IP
|
|
|
|
switch v := addr.(type) {
|
|
|
|
case *net.IPNet:
|
|
|
|
ip = v.IP
|
|
|
|
case *net.IPAddr:
|
|
|
|
ip = v.IP
|
|
|
|
}
|
|
|
|
if ip == nil || ip.IsLoopback() {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
l = append(l, ip.String())
|
|
|
|
}
|
|
|
|
if len(l) > 0 {
|
|
|
|
ips = append(ips, strings.Join(l, " "))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return ips
|
|
|
|
}
|
|
|
|
|
2017-04-25 19:00:55 +00:00
|
|
|
func logPanicToWriter(w io.Writer, loggedError error, le string) {
|
2015-07-28 22:43:22 +00:00
|
|
|
// log the version
|
2017-10-26 02:23:43 +00:00
|
|
|
gitV, err := git.Version()
|
2015-07-28 22:43:22 +00:00
|
|
|
if err != nil {
|
2022-01-28 05:49:32 +00:00
|
|
|
gitV = tr.Tr.Get("Error getting Git version: %s", err.Error())
|
2015-07-28 22:43:22 +00:00
|
|
|
}
|
|
|
|
|
2022-01-29 03:38:01 +00:00
|
|
|
fmt.Fprint(w, config.VersionDesc, le)
|
|
|
|
fmt.Fprint(w, gitV, le)
|
2015-07-28 22:43:22 +00:00
|
|
|
|
|
|
|
// log the command that was run
|
2017-04-25 19:00:55 +00:00
|
|
|
fmt.Fprint(w, le)
|
2015-07-28 22:43:22 +00:00
|
|
|
fmt.Fprintf(w, "$ %s", filepath.Base(os.Args[0]))
|
2014-06-05 18:19:30 +00:00
|
|
|
if len(os.Args) > 0 {
|
2015-05-14 17:34:58 +00:00
|
|
|
fmt.Fprintf(w, " %s", strings.Join(os.Args[1:], " "))
|
2014-06-05 18:19:30 +00:00
|
|
|
}
|
2017-04-25 19:00:55 +00:00
|
|
|
fmt.Fprint(w, le)
|
2014-06-05 18:19:30 +00:00
|
|
|
|
2015-07-28 22:43:22 +00:00
|
|
|
// log the error message and stack trace
|
2015-05-14 17:34:58 +00:00
|
|
|
w.Write(ErrorBuffer.Bytes())
|
2017-04-25 19:00:55 +00:00
|
|
|
fmt.Fprint(w, le)
|
2014-06-05 18:19:30 +00:00
|
|
|
|
2022-01-29 03:38:01 +00:00
|
|
|
fmt.Fprintf(w, "%+v%s", loggedError, le)
|
2016-08-19 18:30:53 +00:00
|
|
|
|
2016-08-19 20:03:39 +00:00
|
|
|
for key, val := range errors.Context(err) {
|
2022-01-29 03:38:01 +00:00
|
|
|
fmt.Fprintf(w, "%s=%v%s", key, val, le)
|
2014-08-07 22:08:47 +00:00
|
|
|
}
|
2016-08-18 21:43:28 +00:00
|
|
|
|
2022-01-28 05:49:32 +00:00
|
|
|
fmt.Fprint(w, le, tr.Tr.Get("Current time in UTC:"), le)
|
2022-01-29 03:38:01 +00:00
|
|
|
fmt.Fprint(w, time.Now().UTC().Format("2006-01-02 15:04:05"), le)
|
2017-09-11 10:21:39 +00:00
|
|
|
|
2022-01-28 05:49:32 +00:00
|
|
|
fmt.Fprint(w, le, tr.Tr.Get("Environment:"), le)
|
2014-06-05 18:19:30 +00:00
|
|
|
|
2015-07-28 22:43:22 +00:00
|
|
|
// log the environment
|
2020-10-02 18:20:26 +00:00
|
|
|
for _, env := range lfs.Environ(cfg, getTransferManifest(), oldEnv) {
|
2022-01-29 03:38:01 +00:00
|
|
|
fmt.Fprint(w, env, le)
|
2015-05-14 17:20:23 +00:00
|
|
|
}
|
2017-09-11 09:42:47 +00:00
|
|
|
|
2022-01-28 05:49:32 +00:00
|
|
|
fmt.Fprint(w, le, tr.Tr.Get("Client IP addresses:"), le)
|
2017-09-11 09:42:47 +00:00
|
|
|
|
|
|
|
for _, ip := range ipAddresses() {
|
2022-01-29 03:38:01 +00:00
|
|
|
fmt.Fprint(w, ip, le)
|
2017-09-11 09:42:47 +00:00
|
|
|
}
|
2015-05-14 17:20:23 +00:00
|
|
|
}
|
|
|
|
|
2020-03-27 19:02:58 +00:00
|
|
|
func determineIncludeExcludePaths(config *config.Configuration, includeArg, excludeArg *string, useFetchOptions bool) (include, exclude []string) {
|
2016-08-01 22:47:41 +00:00
|
|
|
if includeArg == nil {
|
2020-03-27 19:02:58 +00:00
|
|
|
if useFetchOptions {
|
|
|
|
include = config.FetchIncludePaths()
|
|
|
|
} else {
|
|
|
|
include = []string{}
|
|
|
|
}
|
2016-08-01 22:47:41 +00:00
|
|
|
} else {
|
|
|
|
include = tools.CleanPaths(*includeArg, ",")
|
|
|
|
}
|
|
|
|
if excludeArg == nil {
|
2020-03-27 19:02:58 +00:00
|
|
|
if useFetchOptions {
|
|
|
|
exclude = config.FetchExcludePaths()
|
|
|
|
} else {
|
|
|
|
exclude = []string{}
|
|
|
|
}
|
2016-08-01 22:47:41 +00:00
|
|
|
} else {
|
|
|
|
exclude = tools.CleanPaths(*excludeArg, ",")
|
|
|
|
}
|
|
|
|
return
|
2016-05-31 15:48:09 +00:00
|
|
|
}
|
|
|
|
|
2018-01-06 02:01:50 +00:00
|
|
|
func buildProgressMeter(dryRun bool, d tq.Direction) *tq.Meter {
|
2018-12-05 16:15:52 +00:00
|
|
|
m := tq.NewMeter(cfg)
|
2017-12-07 22:13:11 +00:00
|
|
|
m.Logger = m.LoggerFromEnv(cfg.Os)
|
|
|
|
m.DryRun = dryRun
|
2018-01-06 02:01:50 +00:00
|
|
|
m.Direction = d
|
2017-12-07 22:13:11 +00:00
|
|
|
return m
|
2016-12-07 02:50:57 +00:00
|
|
|
}
|
|
|
|
|
2016-08-17 22:13:36 +00:00
|
|
|
func requireGitVersion() {
|
|
|
|
minimumGit := "1.8.2"
|
2016-08-17 22:17:35 +00:00
|
|
|
|
2017-10-26 02:23:43 +00:00
|
|
|
if !git.IsGitVersionAtLeast(minimumGit) {
|
|
|
|
gitver, err := git.Version()
|
2016-08-17 22:21:00 +00:00
|
|
|
if err != nil {
|
2022-01-28 05:49:32 +00:00
|
|
|
Exit(tr.Tr.Get("Error getting Git version: %s", err))
|
2016-08-17 22:21:00 +00:00
|
|
|
}
|
2022-01-28 05:49:32 +00:00
|
|
|
Exit(tr.Tr.Get("Git version %s or higher is required for Git LFS; your version: %s", minimumGit, gitver))
|
2016-08-17 22:13:36 +00:00
|
|
|
}
|
|
|
|
}
|