2016-05-18 10:43:42 +00:00
|
|
|
// Package config collects together all configuration settings
|
|
|
|
// NOTE: Subject to change, do not rely on this package from outside git-lfs source
|
2016-05-13 16:38:06 +00:00
|
|
|
package config
|
2013-11-05 17:07:03 +00:00
|
|
|
|
2013-11-05 17:45:01 +00:00
|
|
|
import (
|
2016-08-08 22:48:21 +00:00
|
|
|
"errors"
|
2014-05-22 23:02:56 +00:00
|
|
|
"fmt"
|
2016-08-12 21:33:54 +00:00
|
|
|
"os"
|
2016-08-08 22:48:21 +00:00
|
|
|
"reflect"
|
2015-04-23 14:48:44 +00:00
|
|
|
"strconv"
|
2014-02-01 20:38:29 +00:00
|
|
|
"strings"
|
2015-04-23 01:07:52 +00:00
|
|
|
"sync"
|
2015-05-13 19:43:41 +00:00
|
|
|
|
2016-05-23 18:02:27 +00:00
|
|
|
"github.com/ThomsonReutersEikon/go-ntlm/ntlm"
|
|
|
|
"github.com/bgentry/go-netrc/netrc"
|
2016-11-15 17:01:18 +00:00
|
|
|
"github.com/git-lfs/git-lfs/git"
|
|
|
|
"github.com/git-lfs/git-lfs/tools"
|
2016-05-23 18:02:27 +00:00
|
|
|
"github.com/rubyist/tracerx"
|
2013-11-05 17:45:01 +00:00
|
|
|
)
|
|
|
|
|
2015-06-17 20:38:09 +00:00
|
|
|
var (
|
2016-07-21 23:38:44 +00:00
|
|
|
Config = New()
|
2015-11-24 18:58:52 +00:00
|
|
|
ShowConfigWarnings = false
|
|
|
|
defaultRemote = "origin"
|
|
|
|
gitConfigWarningPrefix = "lfs."
|
2015-06-17 20:38:09 +00:00
|
|
|
)
|
|
|
|
|
2015-08-04 16:46:51 +00:00
|
|
|
// FetchPruneConfig collects together the config options that control fetching and pruning
|
|
|
|
type FetchPruneConfig struct {
|
|
|
|
// The number of days prior to current date for which (local) refs other than HEAD
|
|
|
|
// will be fetched with --recent (default 7, 0 = only fetch HEAD)
|
2016-08-09 20:27:11 +00:00
|
|
|
FetchRecentRefsDays int `git:"lfs.fetchrecentrefsdays"`
|
2015-09-01 11:06:30 +00:00
|
|
|
// Makes the FetchRecentRefsDays option apply to remote refs from fetch source as well (default true)
|
2016-08-09 20:27:11 +00:00
|
|
|
FetchRecentRefsIncludeRemotes bool `git:"lfs.fetchrecentremoterefs"`
|
2015-08-04 16:46:51 +00:00
|
|
|
// number of days prior to latest commit on a ref that we'll fetch previous
|
2015-08-17 11:04:43 +00:00
|
|
|
// LFS changes too (default 0 = only fetch at ref)
|
2016-08-09 20:27:11 +00:00
|
|
|
FetchRecentCommitsDays int `git:"lfs.fetchrecentcommitsdays"`
|
2015-08-17 11:03:13 +00:00
|
|
|
// Whether to always fetch recent even without --recent
|
2016-08-09 20:27:11 +00:00
|
|
|
FetchRecentAlways bool `git:"lfs.fetchrecentalways"`
|
2015-08-04 16:46:51 +00:00
|
|
|
// Number of days added to FetchRecent*; data outside combined window will be
|
|
|
|
// deleted when prune is run. (default 3)
|
2016-08-09 20:27:11 +00:00
|
|
|
PruneOffsetDays int `git:"lfs.pruneoffsetdays"`
|
2015-09-08 14:00:28 +00:00
|
|
|
// Always verify with remote before pruning
|
2016-08-09 20:27:11 +00:00
|
|
|
PruneVerifyRemoteAlways bool `git:"lfs.pruneverifyremotealways"`
|
2015-09-08 14:00:28 +00:00
|
|
|
// Name of remote to check for unpushed and verify checks
|
2016-08-09 20:27:11 +00:00
|
|
|
PruneRemoteName string `git:"lfs.pruneremotetocheck"`
|
2015-08-04 16:46:51 +00:00
|
|
|
}
|
|
|
|
|
2013-11-05 17:07:03 +00:00
|
|
|
type Configuration struct {
|
2016-08-04 20:41:04 +00:00
|
|
|
// Os provides a `*Environment` used to access to the system's
|
2016-08-03 22:07:05 +00:00
|
|
|
// environment through os.Getenv. It is the point of entry for all
|
|
|
|
// system environment configuration.
|
2016-08-15 19:17:11 +00:00
|
|
|
Os Environment
|
2016-08-03 22:07:05 +00:00
|
|
|
|
2016-08-05 20:16:29 +00:00
|
|
|
// Git provides a `*Environment` used to access to the various levels of
|
|
|
|
// `.gitconfig`'s. It is the point of entry for all Git environment
|
|
|
|
// configuration.
|
2016-08-15 19:17:11 +00:00
|
|
|
Git Environment
|
2016-08-05 23:23:56 +00:00
|
|
|
|
2016-05-13 16:38:06 +00:00
|
|
|
CurrentRemote string
|
|
|
|
NtlmSession ntlm.ClientSession
|
|
|
|
envVars map[string]string
|
|
|
|
envVarsMutex sync.Mutex
|
|
|
|
IsTracingHttp bool
|
|
|
|
IsDebuggingHttp bool
|
|
|
|
IsLoggingStats bool
|
2015-06-13 23:00:36 +00:00
|
|
|
|
2016-08-05 23:23:56 +00:00
|
|
|
loading sync.Mutex // guards initialization of gitConfig and remotes
|
|
|
|
remotes []string
|
|
|
|
extensions map[string]Extension
|
|
|
|
manualEndpoint *Endpoint
|
|
|
|
parsedNetrc netrcfinder
|
2016-08-12 21:41:07 +00:00
|
|
|
urlAliasesMap map[string]string
|
2016-08-12 21:20:46 +00:00
|
|
|
urlAliasMu sync.Mutex
|
2013-11-05 17:07:03 +00:00
|
|
|
}
|
|
|
|
|
2016-07-21 23:38:44 +00:00
|
|
|
func New() *Configuration {
|
2015-03-05 20:04:00 +00:00
|
|
|
c := &Configuration{
|
2016-08-15 20:48:43 +00:00
|
|
|
Os: EnvironmentOf(NewOsFetcher()),
|
2015-03-05 20:04:00 +00:00
|
|
|
CurrentRemote: defaultRemote,
|
2015-06-13 23:13:58 +00:00
|
|
|
envVars: make(map[string]string),
|
2015-03-05 19:59:52 +00:00
|
|
|
}
|
2016-08-16 17:20:15 +00:00
|
|
|
|
2016-08-15 20:48:43 +00:00
|
|
|
c.Git = &gitEnvironment{config: c}
|
2016-08-10 19:51:53 +00:00
|
|
|
c.IsTracingHttp = c.Os.Bool("GIT_CURL_VERBOSE", false)
|
|
|
|
c.IsDebuggingHttp = c.Os.Bool("LFS_DEBUG_HTTP", false)
|
|
|
|
c.IsLoggingStats = c.Os.Bool("GIT_LOG_STATS", false)
|
2015-03-05 19:59:52 +00:00
|
|
|
return c
|
|
|
|
}
|
|
|
|
|
2016-08-03 23:42:21 +00:00
|
|
|
// Values is a convenience type used to call the NewFromValues function. It
|
|
|
|
// specifies `Git` and `Env` maps to use as mock values, instead of calling out
|
|
|
|
// to real `.gitconfig`s and the `os.Getenv` function.
|
|
|
|
type Values struct {
|
2016-08-04 20:41:04 +00:00
|
|
|
// Git and Os are the stand-in maps used to provide values for their
|
2016-08-03 23:42:21 +00:00
|
|
|
// respective environments.
|
2016-08-04 20:41:04 +00:00
|
|
|
Git, Os map[string]string
|
2016-08-03 23:42:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// NewFrom returns a new `*config.Configuration` that reads both its Git
|
|
|
|
// and Enviornment-level values from the ones provided instead of the actual
|
|
|
|
// `.gitconfig` file or `os.Getenv`, respectively.
|
2016-05-31 16:38:02 +00:00
|
|
|
//
|
2016-08-03 23:42:21 +00:00
|
|
|
// This method should only be used during testing.
|
|
|
|
func NewFrom(v Values) *Configuration {
|
2016-08-05 20:16:29 +00:00
|
|
|
return &Configuration{
|
2016-11-10 00:46:52 +00:00
|
|
|
Os: EnvironmentOf(mapFetcher(v.Os)),
|
|
|
|
Git: EnvironmentOf(mapFetcher(v.Git)),
|
2016-05-31 16:38:02 +00:00
|
|
|
|
2016-08-05 20:16:29 +00:00
|
|
|
envVars: make(map[string]string, 0),
|
2016-05-31 16:38:02 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-08-08 22:48:21 +00:00
|
|
|
// Unmarshal unmarshals the *Configuration in context into all of `v`'s fields,
|
|
|
|
// according to the following rules:
|
|
|
|
//
|
|
|
|
// Values are marshaled according to the given key and environment, as follows:
|
|
|
|
// type T struct {
|
|
|
|
// Field string `git:"key"`
|
|
|
|
// Other string `os:"key"`
|
|
|
|
// }
|
|
|
|
//
|
|
|
|
// If an unknown environment is given, an error will be returned. If there is no
|
|
|
|
// method supporting conversion into a field's type, an error will be returned.
|
|
|
|
// If no value is associated with the given key and environment, the field will
|
2016-08-09 16:08:56 +00:00
|
|
|
// // only be modified if there is a config value present matching the given
|
|
|
|
// key. If the field is already set to a non-zero value of that field's type,
|
|
|
|
// then it will be left alone.
|
2016-08-08 22:48:21 +00:00
|
|
|
//
|
|
|
|
// Otherwise, the field will be set to the value of calling the
|
|
|
|
// appropriately-typed method on the specified environment.
|
|
|
|
func (c *Configuration) Unmarshal(v interface{}) error {
|
|
|
|
into := reflect.ValueOf(v)
|
|
|
|
if into.Kind() != reflect.Ptr {
|
|
|
|
return fmt.Errorf("lfs/config: unable to parse non-pointer type of %T", v)
|
|
|
|
}
|
|
|
|
into = into.Elem()
|
|
|
|
|
|
|
|
for i := 0; i < into.Type().NumField(); i++ {
|
|
|
|
field := into.Field(i)
|
|
|
|
sfield := into.Type().Field(i)
|
|
|
|
|
|
|
|
key, env, err := c.parseTag(sfield.Tag)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
if env == nil {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
var val interface{}
|
|
|
|
switch sfield.Type.Kind() {
|
|
|
|
case reflect.String:
|
2016-08-09 16:08:56 +00:00
|
|
|
var ok bool
|
|
|
|
|
|
|
|
val, ok = env.Get(key)
|
|
|
|
if !ok {
|
|
|
|
val = field.String()
|
|
|
|
}
|
2016-08-08 22:48:21 +00:00
|
|
|
case reflect.Int:
|
2016-08-09 16:08:56 +00:00
|
|
|
val = env.Int(key, int(field.Int()))
|
2016-08-08 22:48:21 +00:00
|
|
|
case reflect.Bool:
|
2016-08-09 16:08:56 +00:00
|
|
|
val = env.Bool(key, field.Bool())
|
2016-08-08 22:48:21 +00:00
|
|
|
default:
|
|
|
|
return fmt.Errorf(
|
|
|
|
"lfs/config: unsupported target type for field %q: %v",
|
|
|
|
sfield.Name, sfield.Type.String())
|
|
|
|
}
|
|
|
|
|
|
|
|
if val != nil {
|
|
|
|
into.Field(i).Set(reflect.ValueOf(val))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// parseTag returns the key, environment, and optional error assosciated with a
|
|
|
|
// given tag. It will return the XOR of either the `git` or `os` tag. That is to
|
|
|
|
// say, a field tagged with EITHER `git` OR `os` is valid, but pone tagged with
|
|
|
|
// both is not.
|
|
|
|
//
|
|
|
|
// If neither field was found, then a nil environment will be returned.
|
2016-08-15 19:17:11 +00:00
|
|
|
func (c *Configuration) parseTag(tag reflect.StructTag) (key string, env Environment, err error) {
|
2016-08-08 22:48:21 +00:00
|
|
|
git, os := tag.Get("git"), tag.Get("os")
|
|
|
|
|
|
|
|
if len(git) != 0 && len(os) != 0 {
|
|
|
|
return "", nil, errors.New("lfs/config: ambiguous tags")
|
|
|
|
}
|
|
|
|
|
|
|
|
if len(git) != 0 {
|
|
|
|
return git, c.Git, nil
|
|
|
|
}
|
|
|
|
if len(os) != 0 {
|
|
|
|
return os, c.Os, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2016-01-25 15:09:55 +00:00
|
|
|
// GitRemoteUrl returns the git clone/push url for a given remote (blank if not found)
|
|
|
|
// the forpush argument is to cater for separate remote.name.pushurl settings
|
|
|
|
func (c *Configuration) GitRemoteUrl(remote string, forpush bool) string {
|
|
|
|
if forpush {
|
2016-08-15 21:43:38 +00:00
|
|
|
if u, ok := c.Git.Get("remote." + remote + ".pushurl"); ok {
|
2016-01-25 15:09:55 +00:00
|
|
|
return u
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-08-15 21:43:38 +00:00
|
|
|
if u, ok := c.Git.Get("remote." + remote + ".url"); ok {
|
2016-01-25 15:09:55 +00:00
|
|
|
return u
|
|
|
|
}
|
|
|
|
|
2016-03-17 23:15:17 +00:00
|
|
|
if err := git.ValidateRemote(remote); err == nil {
|
|
|
|
return remote
|
|
|
|
}
|
|
|
|
|
2016-01-25 15:09:55 +00:00
|
|
|
return ""
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2015-11-24 13:05:47 +00:00
|
|
|
// Manually set an Endpoint to use instead of deriving from Git config
|
|
|
|
func (c *Configuration) SetManualEndpoint(e Endpoint) {
|
|
|
|
c.manualEndpoint = &e
|
|
|
|
}
|
|
|
|
|
2016-01-25 15:09:55 +00:00
|
|
|
func (c *Configuration) Endpoint(operation string) Endpoint {
|
2015-11-24 13:05:47 +00:00
|
|
|
if c.manualEndpoint != nil {
|
|
|
|
return *c.manualEndpoint
|
|
|
|
}
|
|
|
|
|
2016-01-25 15:09:55 +00:00
|
|
|
if operation == "upload" {
|
2016-08-15 21:43:38 +00:00
|
|
|
if url, ok := c.Git.Get("lfs.pushurl"); ok {
|
2016-02-02 17:42:20 +00:00
|
|
|
return NewEndpointWithConfig(url, c)
|
2016-01-25 15:09:55 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-08-15 21:43:38 +00:00
|
|
|
if url, ok := c.Git.Get("lfs.url"); ok {
|
2016-02-02 17:42:20 +00:00
|
|
|
return NewEndpointWithConfig(url, c)
|
2013-11-05 17:07:03 +00:00
|
|
|
}
|
|
|
|
|
2015-02-02 22:39:03 +00:00
|
|
|
if len(c.CurrentRemote) > 0 && c.CurrentRemote != defaultRemote {
|
2016-01-25 15:09:55 +00:00
|
|
|
if endpoint := c.RemoteEndpoint(c.CurrentRemote, operation); len(endpoint.Url) > 0 {
|
2015-02-02 22:39:03 +00:00
|
|
|
return endpoint
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-01-25 15:09:55 +00:00
|
|
|
return c.RemoteEndpoint(defaultRemote, operation)
|
2013-11-05 17:07:03 +00:00
|
|
|
}
|
2013-11-05 17:45:01 +00:00
|
|
|
|
2015-05-13 15:27:06 +00:00
|
|
|
func (c *Configuration) ConcurrentTransfers() int {
|
2016-01-25 15:09:55 +00:00
|
|
|
if c.NtlmAccess("download") {
|
2015-11-06 18:08:44 +00:00
|
|
|
return 1
|
|
|
|
}
|
|
|
|
|
2015-04-23 14:48:44 +00:00
|
|
|
uploads := 3
|
|
|
|
|
2016-08-15 21:43:38 +00:00
|
|
|
if v, ok := c.Git.Get("lfs.concurrenttransfers"); ok {
|
2015-04-23 14:48:44 +00:00
|
|
|
n, err := strconv.Atoi(v)
|
2015-05-26 19:42:37 +00:00
|
|
|
if err == nil && n > 0 {
|
2015-04-23 14:48:44 +00:00
|
|
|
uploads = n
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return uploads
|
|
|
|
}
|
|
|
|
|
2016-07-25 18:50:58 +00:00
|
|
|
// BasicTransfersOnly returns whether to only allow "basic" HTTP transfers.
|
2016-06-10 07:43:32 +00:00
|
|
|
// Default is false, including if the lfs.basictransfersonly is invalid
|
2016-06-09 10:45:24 +00:00
|
|
|
func (c *Configuration) BasicTransfersOnly() bool {
|
2016-08-15 21:43:38 +00:00
|
|
|
return c.Git.Bool("lfs.basictransfersonly", false)
|
2016-06-09 10:45:24 +00:00
|
|
|
}
|
|
|
|
|
2016-07-25 18:50:58 +00:00
|
|
|
// TusTransfersAllowed returns whether to only use "tus.io" HTTP transfers.
|
|
|
|
// Default is false, including if the lfs.tustransfers is invalid
|
|
|
|
func (c *Configuration) TusTransfersAllowed() bool {
|
2016-08-15 21:43:38 +00:00
|
|
|
return c.Git.Bool("lfs.tustransfers", false)
|
2016-06-09 10:45:24 +00:00
|
|
|
}
|
|
|
|
|
2015-05-07 18:37:30 +00:00
|
|
|
func (c *Configuration) BatchTransfer() bool {
|
2016-08-15 21:43:38 +00:00
|
|
|
return c.Git.Bool("lfs.batch", true)
|
2015-05-07 18:37:30 +00:00
|
|
|
}
|
|
|
|
|
2016-01-25 15:09:55 +00:00
|
|
|
func (c *Configuration) NtlmAccess(operation string) bool {
|
|
|
|
return c.Access(operation) == "ntlm"
|
2015-10-05 19:26:39 +00:00
|
|
|
}
|
|
|
|
|
2015-06-24 20:18:41 +00:00
|
|
|
// PrivateAccess will retrieve the access value and return true if
|
|
|
|
// the value is set to private. When a repo is marked as having private
|
|
|
|
// access, the http requests for the batch api will fetch the credentials
|
|
|
|
// before running, otherwise the request will run without credentials.
|
2016-01-25 15:09:55 +00:00
|
|
|
func (c *Configuration) PrivateAccess(operation string) bool {
|
|
|
|
return c.Access(operation) != "none"
|
2015-09-01 17:24:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Access returns the access auth type.
|
2016-01-25 15:09:55 +00:00
|
|
|
func (c *Configuration) Access(operation string) string {
|
|
|
|
return c.EndpointAccess(c.Endpoint(operation))
|
2015-09-01 21:47:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// SetAccess will set the private access flag in .git/config.
|
2016-01-25 15:09:55 +00:00
|
|
|
func (c *Configuration) SetAccess(operation string, authType string) {
|
|
|
|
c.SetEndpointAccess(c.Endpoint(operation), authType)
|
2015-09-01 21:47:47 +00:00
|
|
|
}
|
|
|
|
|
2015-11-18 17:23:36 +00:00
|
|
|
func (c *Configuration) FindNetrcHost(host string) (*netrc.Machine, error) {
|
|
|
|
c.loading.Lock()
|
|
|
|
defer c.loading.Unlock()
|
|
|
|
if c.parsedNetrc == nil {
|
|
|
|
n, err := c.parseNetrc()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
c.parsedNetrc = n
|
|
|
|
}
|
|
|
|
|
|
|
|
return c.parsedNetrc.FindMachine(host), nil
|
|
|
|
}
|
|
|
|
|
2016-05-13 16:38:06 +00:00
|
|
|
// Manually override the netrc config
|
|
|
|
func (c *Configuration) SetNetrc(n netrcfinder) {
|
|
|
|
c.parsedNetrc = n
|
|
|
|
}
|
|
|
|
|
2015-09-02 18:53:43 +00:00
|
|
|
func (c *Configuration) EndpointAccess(e Endpoint) string {
|
2015-09-01 21:47:47 +00:00
|
|
|
key := fmt.Sprintf("lfs.%s.access", e.Url)
|
2016-08-15 21:43:38 +00:00
|
|
|
if v, ok := c.Git.Get(key); ok && len(v) > 0 {
|
2015-09-02 19:03:37 +00:00
|
|
|
lower := strings.ToLower(v)
|
|
|
|
if lower == "private" {
|
|
|
|
return "basic"
|
|
|
|
}
|
|
|
|
return lower
|
2015-06-18 16:46:27 +00:00
|
|
|
}
|
2015-09-02 18:53:43 +00:00
|
|
|
return "none"
|
2015-06-18 16:46:27 +00:00
|
|
|
}
|
|
|
|
|
2015-09-02 18:53:43 +00:00
|
|
|
func (c *Configuration) SetEndpointAccess(e Endpoint, authType string) {
|
2016-08-15 20:48:43 +00:00
|
|
|
c.loadGitConfig()
|
|
|
|
|
2015-09-01 17:24:10 +00:00
|
|
|
tracerx.Printf("setting repository access to %s", authType)
|
2015-09-01 21:47:47 +00:00
|
|
|
key := fmt.Sprintf("lfs.%s.access", e.Url)
|
2015-06-23 21:27:04 +00:00
|
|
|
|
|
|
|
// Modify the config cache because it's checked again in this process
|
|
|
|
// without being reloaded.
|
2015-09-02 18:53:43 +00:00
|
|
|
switch authType {
|
|
|
|
case "", "none":
|
2015-09-02 19:28:30 +00:00
|
|
|
git.Config.UnsetLocalKey("", key)
|
2016-11-10 18:16:46 +00:00
|
|
|
c.Git.del(key)
|
2015-09-02 18:53:43 +00:00
|
|
|
default:
|
2015-09-02 19:28:30 +00:00
|
|
|
git.Config.SetLocal("", key, authType)
|
2016-11-10 18:16:46 +00:00
|
|
|
c.Git.set(key, authType)
|
2015-09-01 17:24:10 +00:00
|
|
|
}
|
2015-06-23 21:27:04 +00:00
|
|
|
}
|
|
|
|
|
2016-05-31 15:48:09 +00:00
|
|
|
func (c *Configuration) FetchIncludePaths() []string {
|
2016-08-05 21:59:57 +00:00
|
|
|
patterns, _ := c.Git.Get("lfs.fetchinclude")
|
|
|
|
return tools.CleanPaths(patterns, ",")
|
2015-08-06 13:56:57 +00:00
|
|
|
}
|
2016-05-27 19:11:24 +00:00
|
|
|
|
2016-05-31 15:48:09 +00:00
|
|
|
func (c *Configuration) FetchExcludePaths() []string {
|
2016-08-05 22:30:25 +00:00
|
|
|
patterns, _ := c.Git.Get("lfs.fetchexclude")
|
2016-08-05 21:59:57 +00:00
|
|
|
return tools.CleanPaths(patterns, ",")
|
2015-08-06 13:56:57 +00:00
|
|
|
}
|
|
|
|
|
2016-01-25 15:09:55 +00:00
|
|
|
func (c *Configuration) RemoteEndpoint(remote, operation string) Endpoint {
|
2015-02-02 22:39:03 +00:00
|
|
|
if len(remote) == 0 {
|
|
|
|
remote = defaultRemote
|
|
|
|
}
|
2016-01-25 15:09:55 +00:00
|
|
|
|
|
|
|
// Support separate push URL if specified and pushing
|
|
|
|
if operation == "upload" {
|
2016-08-15 21:43:38 +00:00
|
|
|
if url, ok := c.Git.Get("remote." + remote + ".lfspushurl"); ok {
|
2016-02-02 17:42:20 +00:00
|
|
|
return NewEndpointWithConfig(url, c)
|
2016-01-25 15:09:55 +00:00
|
|
|
}
|
|
|
|
}
|
2016-08-15 21:43:38 +00:00
|
|
|
if url, ok := c.Git.Get("remote." + remote + ".lfsurl"); ok {
|
2016-02-02 17:42:20 +00:00
|
|
|
return NewEndpointWithConfig(url, c)
|
2014-02-01 20:38:29 +00:00
|
|
|
}
|
|
|
|
|
2016-01-25 15:09:55 +00:00
|
|
|
// finally fall back on git remote url (also supports pushurl)
|
|
|
|
if url := c.GitRemoteUrl(remote, operation == "upload"); url != "" {
|
2016-02-02 17:42:20 +00:00
|
|
|
return NewEndpointFromCloneURLWithConfig(url, c)
|
2015-06-13 22:55:23 +00:00
|
|
|
}
|
2014-03-19 21:21:52 +00:00
|
|
|
|
2015-06-13 22:55:23 +00:00
|
|
|
return Endpoint{}
|
|
|
|
}
|
2014-03-19 21:21:52 +00:00
|
|
|
|
2014-02-01 20:38:29 +00:00
|
|
|
func (c *Configuration) Remotes() []string {
|
2015-03-05 19:49:15 +00:00
|
|
|
c.loadGitConfig()
|
2016-08-15 20:48:43 +00:00
|
|
|
|
2014-02-01 20:38:29 +00:00
|
|
|
return c.remotes
|
|
|
|
}
|
|
|
|
|
2016-02-02 17:42:20 +00:00
|
|
|
// GitProtocol returns the protocol for the LFS API when converting from a
|
|
|
|
// git:// remote url.
|
|
|
|
func (c *Configuration) GitProtocol() string {
|
2016-08-15 21:43:38 +00:00
|
|
|
if value, ok := c.Git.Get("lfs.gitprotocol"); ok {
|
2016-02-02 17:42:20 +00:00
|
|
|
return value
|
|
|
|
}
|
|
|
|
return "https"
|
|
|
|
}
|
|
|
|
|
2015-07-10 20:54:06 +00:00
|
|
|
func (c *Configuration) Extensions() map[string]Extension {
|
|
|
|
c.loadGitConfig()
|
2016-08-15 20:48:43 +00:00
|
|
|
|
2015-07-10 20:54:06 +00:00
|
|
|
return c.extensions
|
|
|
|
}
|
|
|
|
|
2016-05-13 16:38:06 +00:00
|
|
|
// SortedExtensions gets the list of extensions ordered by Priority
|
|
|
|
func (c *Configuration) SortedExtensions() ([]Extension, error) {
|
|
|
|
return SortExtensions(c.Extensions())
|
|
|
|
}
|
|
|
|
|
2016-08-12 21:41:07 +00:00
|
|
|
func (c *Configuration) urlAliases() map[string]string {
|
2016-08-12 21:20:46 +00:00
|
|
|
c.urlAliasMu.Lock()
|
|
|
|
defer c.urlAliasMu.Unlock()
|
|
|
|
|
2016-08-12 21:41:07 +00:00
|
|
|
if c.urlAliasesMap == nil {
|
|
|
|
c.urlAliasesMap = make(map[string]string)
|
2016-08-12 21:20:46 +00:00
|
|
|
prefix := "url."
|
|
|
|
suffix := ".insteadof"
|
2016-11-10 00:33:43 +00:00
|
|
|
for gitkey, gitval := range c.Git.All() {
|
2016-08-12 21:20:46 +00:00
|
|
|
if strings.HasPrefix(gitkey, prefix) && strings.HasSuffix(gitkey, suffix) {
|
2016-08-12 22:30:43 +00:00
|
|
|
if _, ok := c.urlAliasesMap[gitval]; ok {
|
|
|
|
fmt.Fprintf(os.Stderr, "WARNING: Multiple 'url.*.insteadof' keys with the same alias: %q\n", gitval)
|
|
|
|
}
|
2016-08-12 21:41:07 +00:00
|
|
|
c.urlAliasesMap[gitval] = gitkey[len(prefix) : len(gitkey)-len(suffix)]
|
2016-08-12 21:20:46 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-08-12 21:41:07 +00:00
|
|
|
return c.urlAliasesMap
|
2016-08-12 21:20:46 +00:00
|
|
|
}
|
|
|
|
|
2016-08-12 21:33:54 +00:00
|
|
|
// ReplaceUrlAlias returns a url with a prefix from a `url.*.insteadof` git
|
|
|
|
// config setting. If multiple aliases match, use the longest one.
|
|
|
|
// See https://git-scm.com/docs/git-config for Git's docs.
|
|
|
|
func (c *Configuration) ReplaceUrlAlias(rawurl string) string {
|
|
|
|
var longestalias string
|
2016-08-12 21:41:07 +00:00
|
|
|
aliases := c.urlAliases()
|
|
|
|
for alias, _ := range aliases {
|
2016-08-12 21:33:54 +00:00
|
|
|
if !strings.HasPrefix(rawurl, alias) {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
if longestalias < alias {
|
|
|
|
longestalias = alias
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if len(longestalias) > 0 {
|
2016-08-12 21:41:07 +00:00
|
|
|
return aliases[longestalias] + rawurl[len(longestalias):]
|
2016-08-12 21:33:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return rawurl
|
|
|
|
}
|
|
|
|
|
2016-08-09 20:27:11 +00:00
|
|
|
func (c *Configuration) FetchPruneConfig() FetchPruneConfig {
|
|
|
|
f := &FetchPruneConfig{
|
|
|
|
FetchRecentRefsDays: 7,
|
|
|
|
FetchRecentRefsIncludeRemotes: true,
|
|
|
|
PruneOffsetDays: 3,
|
|
|
|
PruneRemoteName: "origin",
|
2015-08-04 16:46:51 +00:00
|
|
|
}
|
2016-08-05 23:23:56 +00:00
|
|
|
|
2016-08-09 20:27:11 +00:00
|
|
|
if err := c.Unmarshal(f); err != nil {
|
|
|
|
panic(err.Error())
|
|
|
|
}
|
|
|
|
return *f
|
2015-08-04 16:46:51 +00:00
|
|
|
}
|
|
|
|
|
2016-05-10 10:38:17 +00:00
|
|
|
func (c *Configuration) SkipDownloadErrors() bool {
|
2016-08-16 17:20:15 +00:00
|
|
|
return c.Os.Bool("GIT_LFS_SKIP_DOWNLOAD_ERRORS", false) || c.Git.Bool("lfs.skipdownloaderrors", false)
|
2016-05-10 10:38:17 +00:00
|
|
|
}
|
|
|
|
|
2016-08-15 20:48:43 +00:00
|
|
|
// loadGitConfig is a temporary measure to support legacy behavior dependent on
|
|
|
|
// accessing properties set by ReadGitConfig, namely:
|
|
|
|
// - `c.extensions`
|
|
|
|
// - `c.uniqRemotes`
|
|
|
|
// - `c.gitConfig`
|
|
|
|
//
|
|
|
|
// Since the *gitEnvironment is responsible for setting these values on the
|
|
|
|
// (*config.Configuration) instance, we must call that method, if it exists.
|
|
|
|
//
|
|
|
|
// loadGitConfig returns a bool returning whether or not `loadGitConfig` was
|
|
|
|
// called AND the method did not return early.
|
2015-08-28 21:19:52 +00:00
|
|
|
func (c *Configuration) loadGitConfig() bool {
|
2016-08-15 20:48:43 +00:00
|
|
|
if g, ok := c.Git.(*gitEnvironment); ok {
|
|
|
|
return g.loadGitConfig()
|
2015-10-20 16:31:56 +00:00
|
|
|
}
|
2014-03-12 15:31:41 +00:00
|
|
|
|
2016-08-15 20:48:43 +00:00
|
|
|
return false
|
2015-10-20 16:31:56 +00:00
|
|
|
}
|