github.com/2lambda123/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 }