github.com/git-lfs/git-lfs@v2.5.2+incompatible/tq/manifest.go (about)

     1  package tq
     2  
     3  import (
     4  	"sync"
     5  
     6  	"github.com/git-lfs/git-lfs/config"
     7  	"github.com/git-lfs/git-lfs/fs"
     8  	"github.com/git-lfs/git-lfs/lfsapi"
     9  	"github.com/rubyist/tracerx"
    10  )
    11  
    12  const (
    13  	defaultMaxRetries          = 8
    14  	defaultConcurrentTransfers = 8
    15  )
    16  
    17  type Manifest struct {
    18  	// maxRetries is the maximum number of retries a single object can
    19  	// attempt to make before it will be dropped.
    20  	maxRetries              int
    21  	concurrentTransfers     int
    22  	basicTransfersOnly      bool
    23  	standaloneTransferAgent string
    24  	tusTransfersAllowed     bool
    25  	downloadAdapterFuncs    map[string]NewAdapterFunc
    26  	uploadAdapterFuncs      map[string]NewAdapterFunc
    27  	fs                      *fs.Filesystem
    28  	apiClient               *lfsapi.Client
    29  	tqClient                *tqClient
    30  	mu                      sync.Mutex
    31  }
    32  
    33  func (m *Manifest) APIClient() *lfsapi.Client {
    34  	return m.apiClient
    35  }
    36  
    37  func (m *Manifest) MaxRetries() int {
    38  	return m.maxRetries
    39  }
    40  
    41  func (m *Manifest) ConcurrentTransfers() int {
    42  	return m.concurrentTransfers
    43  }
    44  
    45  func (m *Manifest) IsStandaloneTransfer() bool {
    46  	return m.standaloneTransferAgent != ""
    47  }
    48  
    49  func (m *Manifest) batchClient() *tqClient {
    50  	if r := m.MaxRetries(); r > 0 {
    51  		m.tqClient.MaxRetries = r
    52  	}
    53  	return m.tqClient
    54  }
    55  
    56  func NewManifest(f *fs.Filesystem, apiClient *lfsapi.Client, operation, remote string) *Manifest {
    57  	if apiClient == nil {
    58  		cli, err := lfsapi.NewClient(nil)
    59  		if err != nil {
    60  			tracerx.Printf("unable to init tq.Manifest: %s", err)
    61  			return nil
    62  		}
    63  		apiClient = cli
    64  	}
    65  
    66  	m := &Manifest{
    67  		fs:                   f,
    68  		apiClient:            apiClient,
    69  		tqClient:             &tqClient{Client: apiClient},
    70  		downloadAdapterFuncs: make(map[string]NewAdapterFunc),
    71  		uploadAdapterFuncs:   make(map[string]NewAdapterFunc),
    72  	}
    73  
    74  	var tusAllowed bool
    75  	if git := apiClient.GitEnv(); git != nil {
    76  		if v := git.Int("lfs.transfer.maxretries", 0); v > 0 {
    77  			m.maxRetries = v
    78  		}
    79  		if v := git.Int("lfs.concurrenttransfers", 0); v > 0 {
    80  			m.concurrentTransfers = v
    81  		}
    82  		m.basicTransfersOnly = git.Bool("lfs.basictransfersonly", false)
    83  		m.standaloneTransferAgent = findStandaloneTransfer(
    84  			apiClient, operation, remote,
    85  		)
    86  		tusAllowed = git.Bool("lfs.tustransfers", false)
    87  		configureCustomAdapters(git, m)
    88  	}
    89  
    90  	if m.maxRetries < 1 {
    91  		m.maxRetries = defaultMaxRetries
    92  	}
    93  
    94  	if m.concurrentTransfers < 1 {
    95  		m.concurrentTransfers = defaultConcurrentTransfers
    96  	}
    97  
    98  	configureBasicDownloadAdapter(m)
    99  	configureBasicUploadAdapter(m)
   100  	if tusAllowed {
   101  		configureTusAdapter(m)
   102  	}
   103  	return m
   104  }
   105  
   106  func findStandaloneTransfer(client *lfsapi.Client, operation, remote string) string {
   107  	if operation == "" || remote == "" {
   108  		v, _ := client.GitEnv().Get("lfs.standalonetransferagent")
   109  		return v
   110  	}
   111  
   112  	ep := client.Endpoints.RemoteEndpoint(operation, remote)
   113  	uc := config.NewURLConfig(client.GitEnv())
   114  	v, ok := uc.Get("lfs", ep.Url, "standalonetransferagent")
   115  	if !ok {
   116  		return ""
   117  	}
   118  
   119  	return v
   120  }
   121  
   122  // GetAdapterNames returns a list of the names of adapters available to be created
   123  func (m *Manifest) GetAdapterNames(dir Direction) []string {
   124  	switch dir {
   125  	case Upload:
   126  		return m.GetUploadAdapterNames()
   127  	case Download:
   128  		return m.GetDownloadAdapterNames()
   129  	}
   130  	return nil
   131  }
   132  
   133  // GetDownloadAdapterNames returns a list of the names of download adapters available to be created
   134  func (m *Manifest) GetDownloadAdapterNames() []string {
   135  	return m.getAdapterNames(m.downloadAdapterFuncs)
   136  }
   137  
   138  // GetUploadAdapterNames returns a list of the names of upload adapters available to be created
   139  func (m *Manifest) GetUploadAdapterNames() []string {
   140  	return m.getAdapterNames(m.uploadAdapterFuncs)
   141  }
   142  
   143  // getAdapterNames returns a list of the names of adapters available to be created
   144  func (m *Manifest) getAdapterNames(adapters map[string]NewAdapterFunc) []string {
   145  	if m.basicTransfersOnly {
   146  		return []string{BasicAdapterName}
   147  	}
   148  
   149  	m.mu.Lock()
   150  	defer m.mu.Unlock()
   151  
   152  	ret := make([]string, 0, len(adapters))
   153  	for n, _ := range adapters {
   154  		ret = append(ret, n)
   155  	}
   156  	return ret
   157  }
   158  
   159  // RegisterNewTransferAdapterFunc registers a new function for creating upload
   160  // or download adapters. If a function with that name & direction is already
   161  // registered, it is overridden
   162  func (m *Manifest) RegisterNewAdapterFunc(name string, dir Direction, f NewAdapterFunc) {
   163  	m.mu.Lock()
   164  	defer m.mu.Unlock()
   165  
   166  	switch dir {
   167  	case Upload:
   168  		m.uploadAdapterFuncs[name] = f
   169  	case Download:
   170  		m.downloadAdapterFuncs[name] = f
   171  	}
   172  }
   173  
   174  // Create a new adapter by name and direction; default to BasicAdapterName if doesn't exist
   175  func (m *Manifest) NewAdapterOrDefault(name string, dir Direction) Adapter {
   176  	if len(name) == 0 {
   177  		name = BasicAdapterName
   178  	}
   179  
   180  	a := m.NewAdapter(name, dir)
   181  	if a == nil {
   182  		tracerx.Printf("Defaulting to basic transfer adapter since %q did not exist", name)
   183  		a = m.NewAdapter(BasicAdapterName, dir)
   184  	}
   185  	return a
   186  }
   187  
   188  // Create a new adapter by name and direction, or nil if doesn't exist
   189  func (m *Manifest) NewAdapter(name string, dir Direction) Adapter {
   190  	m.mu.Lock()
   191  	defer m.mu.Unlock()
   192  
   193  	switch dir {
   194  	case Upload:
   195  		if u, ok := m.uploadAdapterFuncs[name]; ok {
   196  			return u(name, dir)
   197  		}
   198  	case Download:
   199  		if d, ok := m.downloadAdapterFuncs[name]; ok {
   200  			return d(name, dir)
   201  		}
   202  	}
   203  	return nil
   204  }
   205  
   206  // Create a new download adapter by name, or BasicAdapterName if doesn't exist
   207  func (m *Manifest) NewDownloadAdapter(name string) Adapter {
   208  	return m.NewAdapterOrDefault(name, Download)
   209  }
   210  
   211  // Create a new upload adapter by name, or BasicAdapterName if doesn't exist
   212  func (m *Manifest) NewUploadAdapter(name string) Adapter {
   213  	return m.NewAdapterOrDefault(name, Upload)
   214  }
   215  
   216  // Env is any object with a config.Environment interface.
   217  type Env interface {
   218  	Get(key string) (val string, ok bool)
   219  	GetAll(key string) []string
   220  	Bool(key string, def bool) (val bool)
   221  	Int(key string, def int) (val int)
   222  	All() map[string][]string
   223  }