Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(93)

Side by Side Diff: go/src/infra/tools/cipd/client.go

Issue 1381583007: cipd: Implement local cache for ResolveVersion(...) call with tags. (Closed) Base URL: https://chromium.googlesource.com/infra/infra.git@cipd-init
Patch Set: rebase Created 5 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « go/src/infra/tools/cipd/apps/cipd/main.go ('k') | go/src/infra/tools/cipd/internal/checksum.go » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2015 The Chromium Authors. All rights reserved. 1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 /* 5 /*
6 Package cipd implements client side of Chrome Infra Package Deployer. 6 Package cipd implements client side of Chrome Infra Package Deployer.
7 7
8 TODO: write more. 8 TODO: write more.
9 9
10 Binary package file format (in free form representation): 10 Binary package file format (in free form representation):
(...skipping 23 matching lines...) Expand all
34 */ 34 */
35 package cipd 35 package cipd
36 36
37 import ( 37 import (
38 "bufio" 38 "bufio"
39 "errors" 39 "errors"
40 "fmt" 40 "fmt"
41 "io" 41 "io"
42 "net/http" 42 "net/http"
43 "os" 43 "os"
44 "path/filepath"
44 "sort" 45 "sort"
45 "strings" 46 "strings"
47 "sync"
46 "time" 48 "time"
47 49
48 "github.com/luci/luci-go/common/logging" 50 "github.com/luci/luci-go/common/logging"
49 51
50 "infra/tools/cipd/common" 52 "infra/tools/cipd/common"
53 "infra/tools/cipd/internal"
51 "infra/tools/cipd/local" 54 "infra/tools/cipd/local"
52 ) 55 )
53 56
54 // PackageACLChangeAction defines a flavor of PackageACLChange. 57 // PackageACLChangeAction defines a flavor of PackageACLChange.
55 type PackageACLChangeAction string 58 type PackageACLChangeAction string
56 59
57 const ( 60 const (
58 // GrantRole is used in PackageACLChange to request a role to be granted . 61 // GrantRole is used in PackageACLChange to request a role to be granted .
59 GrantRole PackageACLChangeAction = "GRANT" 62 GrantRole PackageACLChangeAction = "GRANT"
60 // RevokeRole is used in PackageACLChange to request a role to be revoke d. 63 // RevokeRole is used in PackageACLChange to request a role to be revoke d.
61 RevokeRole PackageACLChangeAction = "REVOKE" 64 RevokeRole PackageACLChangeAction = "REVOKE"
62 65
63 // CASFinalizationTimeout is how long to wait for CAS service to finaliz e the upload. 66 // CASFinalizationTimeout is how long to wait for CAS service to finaliz e the upload.
64 CASFinalizationTimeout = 1 * time.Minute 67 CASFinalizationTimeout = 1 * time.Minute
65 // SetRefTimeout is how long to wait for an instance to be processed whe n setting a ref. 68 // SetRefTimeout is how long to wait for an instance to be processed whe n setting a ref.
66 SetRefTimeout = 1 * time.Minute 69 SetRefTimeout = 1 * time.Minute
67 // TagAttachTimeout is how long to wait for an instance to be processed when attaching tags. 70 // TagAttachTimeout is how long to wait for an instance to be processed when attaching tags.
68 TagAttachTimeout = 1 * time.Minute 71 TagAttachTimeout = 1 * time.Minute
69 72
70 // UserAgent is HTTP user agent string for CIPD client. 73 // UserAgent is HTTP user agent string for CIPD client.
71 UserAgent = "cipd 1.0" 74 UserAgent = "cipd 1.0"
72 75
73 // ServiceURL is URL of a backend to connect to by default. 76 // ServiceURL is URL of a backend to connect to by default.
74 ServiceURL = "https://chrome-infra-packages.appspot.com" 77 ServiceURL = "https://chrome-infra-packages.appspot.com"
75 ) 78 )
76 79
77 var ( 80 var (
78 // ErrFinalizationTimeout is returned if CAS service can not finalize up load fast enough. 81 // ErrFinalizationTimeout is returned if CAS service can not finalize up load fast enough.
79 » ErrFinalizationTimeout = errors.New("Timeout while waiting for CAS servi ce to finalize the upload") 82 » ErrFinalizationTimeout = errors.New("timeout while waiting for CAS servi ce to finalize the upload")
80 // ErrBadUpload is returned when a package file is uploaded, but servers asks us to upload it again. 83 // ErrBadUpload is returned when a package file is uploaded, but servers asks us to upload it again.
81 » ErrBadUpload = errors.New("Package file is uploaded, but servers asks us to upload it again") 84 » ErrBadUpload = errors.New("package file is uploaded, but servers asks us to upload it again")
82 // ErrBadUploadSession is returned by UploadToCAS if provided UploadSess ion is not valid. 85 // ErrBadUploadSession is returned by UploadToCAS if provided UploadSess ion is not valid.
83 » ErrBadUploadSession = errors.New("UploadURL must be set if UploadSession ID is used") 86 » ErrBadUploadSession = errors.New("uploadURL must be set if UploadSession ID is used")
84 // ErrUploadSessionDied is returned by UploadToCAS if upload session sud denly disappeared. 87 // ErrUploadSessionDied is returned by UploadToCAS if upload session sud denly disappeared.
85 » ErrUploadSessionDied = errors.New("Upload session is unexpectedly missin g") 88 » ErrUploadSessionDied = errors.New("upload session is unexpectedly missin g")
86 // ErrNoUploadSessionID is returned by UploadToCAS if server didn't prov ide upload session ID. 89 // ErrNoUploadSessionID is returned by UploadToCAS if server didn't prov ide upload session ID.
87 » ErrNoUploadSessionID = errors.New("Server didn't provide upload session ID") 90 » ErrNoUploadSessionID = errors.New("server didn't provide upload session ID")
88 // ErrSetRefTimeout is returned when service refuses to move a ref for a long time. 91 // ErrSetRefTimeout is returned when service refuses to move a ref for a long time.
89 » ErrSetRefTimeout = errors.New("Timeout while moving a ref") 92 » ErrSetRefTimeout = errors.New("timeout while moving a ref")
90 // ErrAttachTagsTimeout is returned when service refuses to accept tags for a long time. 93 // ErrAttachTagsTimeout is returned when service refuses to accept tags for a long time.
91 » ErrAttachTagsTimeout = errors.New("Timeout while attaching tags") 94 » ErrAttachTagsTimeout = errors.New("timeout while attaching tags")
92 // ErrDownloadError is returned by FetchInstance on download errors. 95 // ErrDownloadError is returned by FetchInstance on download errors.
93 » ErrDownloadError = errors.New("Failed to download the package file after multiple attempts") 96 » ErrDownloadError = errors.New("failed to download the package file after multiple attempts")
94 // ErrUploadError is returned by RegisterInstance and UploadToCAS on upl oad errors. 97 // ErrUploadError is returned by RegisterInstance and UploadToCAS on upl oad errors.
95 » ErrUploadError = errors.New("Failed to upload the package file after mul tiple attempts") 98 » ErrUploadError = errors.New("failed to upload the package file after mul tiple attempts")
96 // ErrAccessDenined is returned by calls talking to backend on 401 or 40 3 HTTP errors. 99 // ErrAccessDenined is returned by calls talking to backend on 401 or 40 3 HTTP errors.
97 » ErrAccessDenined = errors.New("Access denied (not authenticated or not e nough permissions)") 100 » ErrAccessDenined = errors.New("access denied (not authenticated or not e nough permissions)")
98 // ErrBackendInaccessible is returned by calls talking to backed if it d oesn't response. 101 // ErrBackendInaccessible is returned by calls talking to backed if it d oesn't response.
99 » ErrBackendInaccessible = errors.New("Request to the backend failed after multiple attempts") 102 » ErrBackendInaccessible = errors.New("request to the backend failed after multiple attempts")
100 // ErrEnsurePackagesFailed is returned by EnsurePackages if something is not right. 103 // ErrEnsurePackagesFailed is returned by EnsurePackages if something is not right.
101 » ErrEnsurePackagesFailed = errors.New("Failed to update packages, see the log") 104 » ErrEnsurePackagesFailed = errors.New("failed to update packages, see the log")
102 ) 105 )
103 106
104 // PackageACL is per package path per role access control list that is a part of 107 // PackageACL is per package path per role access control list that is a part of
105 // larger overall ACL: ACL for package "a/b/c" is a union of PackageACLs for "a" 108 // larger overall ACL: ACL for package "a/b/c" is a union of PackageACLs for "a"
106 // "a/b" and "a/b/c". 109 // "a/b" and "a/b/c".
107 type PackageACL struct { 110 type PackageACL struct {
108 // PackagePath is a package subpath this ACL is defined for. 111 // PackagePath is a package subpath this ACL is defined for.
109 PackagePath string 112 PackagePath string
110 // Role is a role that listed users have, e.g. 'READER', 'WRITER', ... 113 // Role is a role that listed users have, e.g. 'READER', 'WRITER', ...
111 Role string 114 Role string
(...skipping 16 matching lines...) Expand all
128 } 131 }
129 132
130 // UploadSession describes open CAS upload session. 133 // UploadSession describes open CAS upload session.
131 type UploadSession struct { 134 type UploadSession struct {
132 // ID identifies upload session in the backend. 135 // ID identifies upload session in the backend.
133 ID string 136 ID string
134 // URL is where to upload the data to. 137 // URL is where to upload the data to.
135 URL string 138 URL string
136 } 139 }
137 140
138 // Client provides high-level CIPD client interface. 141 // Client provides high-level CIPD client interface. Thread safe.
139 type Client interface { 142 type Client interface {
140 // FetchACL returns a list of PackageACL objects (parent paths first) th at 143 // FetchACL returns a list of PackageACL objects (parent paths first) th at
141 // together define the access control list for the given package subpath . 144 // together define the access control list for the given package subpath .
142 FetchACL(packagePath string) ([]PackageACL, error) 145 FetchACL(packagePath string) ([]PackageACL, error)
143 146
144 // ModifyACL applies a set of PackageACLChanges to a package path. 147 // ModifyACL applies a set of PackageACLChanges to a package path.
145 ModifyACL(packagePath string, changes []PackageACLChange) error 148 ModifyACL(packagePath string, changes []PackageACLChange) error
146 149
147 // UploadToCAS uploads package data blob to Content Addressed Store if i t is 150 // UploadToCAS uploads package data blob to Content Addressed Store if i t is
148 // not there already. The data is addressed by SHA1 hash (also known as 151 // not there already. The data is addressed by SHA1 hash (also known as
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after
188 // <package name> <desired version>. Whitespaces are ignored. Lines that start 191 // <package name> <desired version>. Whitespaces are ignored. Lines that start
189 // with '#' are ignored. Version can be specified as instance ID, tag or ref. 192 // with '#' are ignored. Version can be specified as instance ID, tag or ref.
190 // Will resolve tags and refs to concrete instance IDs by calling the ba ckend. 193 // Will resolve tags and refs to concrete instance IDs by calling the ba ckend.
191 ProcessEnsureFile(r io.Reader) ([]common.Pin, error) 194 ProcessEnsureFile(r io.Reader) ([]common.Pin, error)
192 195
193 // EnsurePackages is high-level interface for installation, removal and update 196 // EnsurePackages is high-level interface for installation, removal and update
194 // of packages inside the installation site root. Given a description of 197 // of packages inside the installation site root. Given a description of
195 // what packages (and versions) should be installed it will do all neces sary 198 // what packages (and versions) should be installed it will do all neces sary
196 // actions to bring the state of the site root to the desired one. 199 // actions to bring the state of the site root to the desired one.
197 EnsurePackages(pins []common.Pin) error 200 EnsurePackages(pins []common.Pin) error
201
202 // Close should be called to dump any cached state to disk.
203 Close()
198 } 204 }
199 205
200 // HTTPClientFactory lazily creates http.Client to use for making requests. 206 // HTTPClientFactory lazily creates http.Client to use for making requests.
201 type HTTPClientFactory func() (*http.Client, error) 207 type HTTPClientFactory func() (*http.Client, error)
202 208
203 // ClientOptions is passed to NewClient factory function. 209 // ClientOptions is passed to NewClient factory function.
204 type ClientOptions struct { 210 type ClientOptions struct {
205 // ServiceURL is root URL of the backend service. 211 // ServiceURL is root URL of the backend service.
206 ServiceURL string 212 ServiceURL string
207 » // Root is a site root directory (where packages will be installed). It can 213
208 » // be empty string if client is not going to be used to deploy or remove local packages. 214 » // Root is a site root directory (a directory where packages will be
215 » // installed to). It also hosts .cipd/* directory that tracks internal s tate
216 » // of installed packages and keeps various cache files. 'Root' can be an empty
217 » // string if the client is not going to be used to deploy or remove loca l
218 » // packages. In that case caches are also disabled.
209 Root string 219 Root string
220
210 // Logger is a logger to use for logs (null-logger by default). 221 // Logger is a logger to use for logs (null-logger by default).
211 Logger logging.Logger 222 Logger logging.Logger
212 » // AuthenticatedClientFactory lazily creates http.Client to use for maki ng RPC requests. 223
224 » // AuthenticatedClientFactory lazily creates http.Client to use for maki ng
225 » // RPC requests.
213 AuthenticatedClientFactory HTTPClientFactory 226 AuthenticatedClientFactory HTTPClientFactory
214 » // AnonymousClientFactory lazily creates http.Client to use for making r equests to storage. 227
228 » // AnonymousClientFactory lazily creates http.Client to use for making
229 » // requests to storage.
215 AnonymousClientFactory HTTPClientFactory 230 AnonymousClientFactory HTTPClientFactory
231
216 // UserAgent is put into User-Agent HTTP header with each request. 232 // UserAgent is put into User-Agent HTTP header with each request.
217 UserAgent string 233 UserAgent string
218 } 234 }
219 235
220 // NewClient initializes CIPD client object. 236 // NewClient initializes CIPD client object.
221 func NewClient(opts ClientOptions) Client { 237 func NewClient(opts ClientOptions) Client {
222 if opts.ServiceURL == "" { 238 if opts.ServiceURL == "" {
223 opts.ServiceURL = ServiceURL 239 opts.ServiceURL = ServiceURL
224 } 240 }
225 if opts.Logger == nil { 241 if opts.Logger == nil {
(...skipping 14 matching lines...) Expand all
240 } 256 }
241 c.remote = &remoteImpl{c} 257 c.remote = &remoteImpl{c}
242 c.storage = &storageImpl{c, uploadChunkSize} 258 c.storage = &storageImpl{c, uploadChunkSize}
243 c.deployer = local.NewDeployer(opts.Root, opts.Logger) 259 c.deployer = local.NewDeployer(opts.Root, opts.Logger)
244 return c 260 return c
245 } 261 }
246 262
247 type clientImpl struct { 263 type clientImpl struct {
248 ClientOptions 264 ClientOptions
249 265
250 » // clock provides current time and ability to sleep. 266 » // lock protects lazily initialized portions of the client.
267 » lock sync.Mutex
268
269 » // clock provides current time and ability to sleep. Thread safe.
251 clock clock 270 clock clock
252 » // remote knows how to call backend REST API. 271
272 » // remote knows how to call backend REST API. Thread safe.
253 remote remote 273 remote remote
274
254 // storage knows how to upload and download raw binaries using signed UR Ls. 275 // storage knows how to upload and download raw binaries using signed UR Ls.
276 // Thread safe.
255 storage storage 277 storage storage
256 » // deployer knows how to install packages to local file system. 278
279 » // deployer knows how to install packages to local file system. Thread s afe.
257 deployer local.Deployer 280 deployer local.Deployer
258 281
259 » // authClient is a lazily created http.Client to use for authenticated r equests. 282 » // tagCache is used to cache (pkgname, tag) -> instanceID mapping.
283 » // Thread safe, but lazily initialized under lock.
284 » tagCache *internal.TagCache
285
286 » // authClient is a lazily created http.Client to use for authenticated
287 » // requests. Thread safe, but lazily initialized under lock.
260 authClient *http.Client 288 authClient *http.Client
289
261 // anonClient is a lazily created http.Client to use for anonymous reque sts. 290 // anonClient is a lazily created http.Client to use for anonymous reque sts.
291 // Thread safe, but lazily initialized under lock.
262 anonClient *http.Client 292 anonClient *http.Client
263 } 293 }
264 294
265 // doAuthenticatedHTTPRequest is used by remote implementation to make HTTP call s. 295 // doAuthenticatedHTTPRequest is used by remote implementation to make HTTP call s.
266 func (client *clientImpl) doAuthenticatedHTTPRequest(req *http.Request) (*http.R esponse, error) { 296 func (client *clientImpl) doAuthenticatedHTTPRequest(req *http.Request) (*http.R esponse, error) {
267 » if client.authClient == nil { 297 » return client.doRequest(req, &client.authClient, client.AuthenticatedCli entFactory)
268 » » var err error
269 » » client.authClient, err = client.AuthenticatedClientFactory()
270 » » if err != nil {
271 » » » return nil, err
272 » » }
273 » }
274 » return client.authClient.Do(req)
275 } 298 }
276 299
277 // doAnonymousHTTPRequest is used by storage implementation to make HTTP calls. 300 // doAnonymousHTTPRequest is used by storage implementation to make HTTP calls.
278 func (client *clientImpl) doAnonymousHTTPRequest(req *http.Request) (*http.Respo nse, error) { 301 func (client *clientImpl) doAnonymousHTTPRequest(req *http.Request) (*http.Respo nse, error) {
279 » if client.anonClient == nil { 302 » return client.doRequest(req, &client.anonClient, client.AnonymousClientF actory)
303 }
304
305 // doRequest lazy-initializes http.Client using provided factory and then
306 // executes the request.
307 func (client *clientImpl) doRequest(req *http.Request, c **http.Client, fac HTTP ClientFactory) (*http.Response, error) {
308 » httpClient, err := func() (*http.Client, error) {
309 » » client.lock.Lock()
310 » » defer client.lock.Unlock()
280 var err error 311 var err error
281 » » client.anonClient, err = client.AnonymousClientFactory() 312 » » if *c == nil {
282 » » if err != nil { 313 » » » *c, err = fac()
283 » » » return nil, err 314 » » }
315 » » return *c, err
316 » }()
317 » if err != nil {
318 » » return nil, err
319 » }
320 » return httpClient.Do(req)
321 }
322
323 // tagCachePath returns path to a tag cache file or "" if no root dir.
324 func (client *clientImpl) tagCachePath() string {
325 » if client.Root == "" {
326 » » return ""
327 » }
328 » return filepath.Join(client.Root, local.SiteServiceDir, "tagcache.db")
329 }
330
331 // getTagCache lazy-initializes tagCache instance and returns it.
332 func (client *clientImpl) getTagCache() *internal.TagCache {
333 » client.lock.Lock()
334 » defer client.lock.Unlock()
335 » if client.tagCache == nil {
336 » » if path := client.tagCachePath(); path != "" {
337 » » » var err error
338 » » » client.tagCache, err = internal.LoadTagCacheFromFile(pat h)
339 » » » if err != nil {
340 » » » » client.Logger.Warningf("cipd: failed to load tag cache - %s", err)
341 » » » }
342 » » }
343 » » if client.tagCache == nil {
344 » » » client.tagCache = &internal.TagCache{}
284 } 345 }
285 } 346 }
286 » return client.anonClient.Do(req) 347 » return client.tagCache
348 }
349
350 // closeTagCache dumps any changes made to tag cache to disk, if necessary.
351 // Must be called under lock.
352 func (client *clientImpl) closeTagCache() {
353 » path := client.tagCachePath()
354 » if client.tagCache == nil || path == "" || !client.tagCache.Dirty() {
355 » » client.tagCache = nil
356 » » return
357 » }
358 » // It's tiny in size (and protobuf can't serialize to io.Reader anyway). Dump
359 » // it to disk via FileSystem object to deal with possible concurrent upd ates,
360 » // missing directories, etc.
361 » fs := local.NewFileSystem(filepath.Dir(path), client.Logger)
362 » out, err := client.tagCache.Save()
363 » if err == nil {
364 » » err = fs.EnsureFile(path, out, 0666)
365 » }
366 » if err != nil {
367 » » client.Logger.Warningf("cipd: failed to update tag cache - %s", err)
368 » }
369 » client.tagCache = nil
287 } 370 }
288 371
289 func (client *clientImpl) FetchACL(packagePath string) ([]PackageACL, error) { 372 func (client *clientImpl) FetchACL(packagePath string) ([]PackageACL, error) {
290 return client.remote.fetchACL(packagePath) 373 return client.remote.fetchACL(packagePath)
291 } 374 }
292 375
293 func (client *clientImpl) ModifyACL(packagePath string, changes []PackageACLChan ge) error { 376 func (client *clientImpl) ModifyACL(packagePath string, changes []PackageACLChan ge) error {
294 return client.remote.modifyACL(packagePath, changes) 377 return client.remote.modifyACL(packagePath, changes)
295 } 378 }
296 379
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after
365 if err := common.ValidatePackageName(packageName); err != nil { 448 if err := common.ValidatePackageName(packageName); err != nil {
366 return common.Pin{}, err 449 return common.Pin{}, err
367 } 450 }
368 // Is it instance ID already? Don't bother calling the backend. 451 // Is it instance ID already? Don't bother calling the backend.
369 if common.ValidateInstanceID(version) == nil { 452 if common.ValidateInstanceID(version) == nil {
370 return common.Pin{PackageName: packageName, InstanceID: version} , nil 453 return common.Pin{PackageName: packageName, InstanceID: version} , nil
371 } 454 }
372 if err := common.ValidateInstanceVersion(version); err != nil { 455 if err := common.ValidateInstanceVersion(version); err != nil {
373 return common.Pin{}, err 456 return common.Pin{}, err
374 } 457 }
375 » return client.remote.resolveVersion(packageName, version) 458 » // Use local cache when resolving tags to avoid round trips to backend w hen
459 » // calling same 'cipd ensure' command again and again.
460 » isTag := common.ValidateInstanceTag(version) == nil
461 » if isTag {
462 » » cached := client.getTagCache().ResolveTag(packageName, version)
463 » » if cached.InstanceID != "" {
464 » » » return cached, nil
465 » » }
466 » }
467 » pin, err := client.remote.resolveVersion(packageName, version)
468 » if err != nil {
469 » » return pin, err
470 » }
471 » if isTag {
472 » » client.getTagCache().AddTag(pin, version)
473 » }
474 » return pin, nil
376 } 475 }
377 476
378 func (client *clientImpl) RegisterInstance(instance local.PackageInstance) error { 477 func (client *clientImpl) RegisterInstance(instance local.PackageInstance) error {
379 // Attempt to register. 478 // Attempt to register.
380 client.Logger.Infof("cipd: registering %s", instance.Pin()) 479 client.Logger.Infof("cipd: registering %s", instance.Pin())
381 result, err := client.remote.registerInstance(instance.Pin()) 480 result, err := client.remote.registerInstance(instance.Pin())
382 if err != nil { 481 if err != nil {
383 return err 482 return err
384 } 483 }
385 484
(...skipping 250 matching lines...) Expand 10 before | Expand all | Expand 10 after
636 } 735 }
637 } 736 }
638 737
639 if !fail { 738 if !fail {
640 client.Logger.Infof("All changes applied.") 739 client.Logger.Infof("All changes applied.")
641 return nil 740 return nil
642 } 741 }
643 return ErrEnsurePackagesFailed 742 return ErrEnsurePackagesFailed
644 } 743 }
645 744
745 func (client *clientImpl) Close() {
746 client.lock.Lock()
747 defer client.lock.Unlock()
748 client.closeTagCache()
749 client.authClient = nil
750 client.anonClient = nil
751 }
752
646 //////////////////////////////////////////////////////////////////////////////// 753 ////////////////////////////////////////////////////////////////////////////////
647 // Private structs and interfaces. 754 // Private structs and interfaces.
648 755
649 type clock interface { 756 type clock interface {
650 now() time.Time 757 now() time.Time
651 sleep(time.Duration) 758 sleep(time.Duration)
652 } 759 }
653 760
654 type remote interface { 761 type remote interface {
655 fetchACL(packagePath string) ([]PackageACL, error) 762 fetchACL(packagePath string) ([]PackageACL, error)
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after
716 } 823 }
717 824
718 // buildInstanceIDMap builds mapping {package name -> instance ID}. 825 // buildInstanceIDMap builds mapping {package name -> instance ID}.
719 func buildInstanceIDMap(pins []common.Pin) map[string]string { 826 func buildInstanceIDMap(pins []common.Pin) map[string]string {
720 out := map[string]string{} 827 out := map[string]string{}
721 for _, p := range pins { 828 for _, p := range pins {
722 out[p.PackageName] = p.InstanceID 829 out[p.PackageName] = p.InstanceID
723 } 830 }
724 return out 831 return out
725 } 832 }
OLDNEW
« no previous file with comments | « go/src/infra/tools/cipd/apps/cipd/main.go ('k') | go/src/infra/tools/cipd/internal/checksum.go » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698