| OLD | NEW |
| 1 # Copyright 2016 The LUCI Authors. All rights reserved. | 1 # Copyright 2016 The LUCI Authors. All rights reserved. |
| 2 # Use of this source code is governed under the Apache License, Version 2.0 | 2 # Use of this source code is governed under the Apache License, Version 2.0 |
| 3 # that can be found in the LICENSE file. | 3 # that can be found in the LICENSE file. |
| 4 | 4 |
| 5 """Fetches CIPD client and installs packages.""" | 5 """Fetches CIPD client and installs packages.""" |
| 6 | 6 |
| 7 __version__ = '0.2' | 7 __version__ = '0.2' |
| 8 | 8 |
| 9 import collections | 9 import collections |
| 10 import contextlib | 10 import contextlib |
| (...skipping 350 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 361 version_cache = isolateserver.DiskCache( | 361 version_cache = isolateserver.DiskCache( |
| 362 unicode(os.path.join(cache_dir, 'versions')), | 362 unicode(os.path.join(cache_dir, 'versions')), |
| 363 isolateserver.CachePolicies(0, 0, 300), | 363 isolateserver.CachePolicies(0, 0, 300), |
| 364 hashlib.sha1) | 364 hashlib.sha1) |
| 365 with version_cache: | 365 with version_cache: |
| 366 version_cache.cleanup() | 366 version_cache.cleanup() |
| 367 # Convert |version| to a string that may be used as a filename in disk | 367 # Convert |version| to a string that may be used as a filename in disk |
| 368 # cache by hashing it. | 368 # cache by hashing it. |
| 369 version_digest = hashlib.sha1(version).hexdigest() | 369 version_digest = hashlib.sha1(version).hexdigest() |
| 370 try: | 370 try: |
| 371 instance_id = version_cache.read(version_digest) | 371 with version_cache.getfileobj(version_digest) as f: |
| 372 instance_id = f.read() |
| 372 except isolateserver.CacheMiss: | 373 except isolateserver.CacheMiss: |
| 373 instance_id = resolve_version( | 374 instance_id = resolve_version( |
| 374 service_url, package_name, version, timeout=timeoutfn()) | 375 service_url, package_name, version, timeout=timeoutfn()) |
| 375 version_cache.write(version_digest, instance_id) | 376 version_cache.write(version_digest, instance_id) |
| 376 | 377 |
| 377 # instance_cache is {instance_id -> client binary} mapping. | 378 # instance_cache is {instance_id -> client binary} mapping. |
| 378 # It is bounded by 5 client versions. | 379 # It is bounded by 5 client versions. |
| 379 instance_cache = isolateserver.DiskCache( | 380 instance_cache = isolateserver.DiskCache( |
| 380 unicode(os.path.join(cache_dir, 'clients')), | 381 unicode(os.path.join(cache_dir, 'clients')), |
| 381 isolateserver.CachePolicies(0, 0, 5), | 382 isolateserver.CachePolicies(0, 0, 5), |
| 382 hashlib.sha1) | 383 hashlib.sha1) |
| 383 with instance_cache: | 384 with instance_cache: |
| 384 instance_cache.cleanup() | 385 instance_cache.cleanup() |
| 385 if instance_id not in instance_cache: | 386 if instance_id not in instance_cache: |
| 386 logging.info('Fetching CIPD client %s:%s', package_name, instance_id) | 387 logging.info('Fetching CIPD client %s:%s', package_name, instance_id) |
| 387 fetch_url = get_client_fetch_url( | 388 fetch_url = get_client_fetch_url( |
| 388 service_url, package_name, instance_id, timeout=timeoutfn()) | 389 service_url, package_name, instance_id, timeout=timeoutfn()) |
| 389 _fetch_cipd_client(instance_cache, instance_id, fetch_url, timeoutfn) | 390 _fetch_cipd_client(instance_cache, instance_id, fetch_url, timeoutfn) |
| 390 | 391 |
| 391 # A single host can run multiple swarming bots, but ATM they do not share | 392 # A single host can run multiple swarming bots, but ATM they do not share |
| 392 # same root bot directory. Thus, it is safe to use the same name for the | 393 # same root bot directory. Thus, it is safe to use the same name for the |
| 393 # binary. | 394 # binary. |
| 394 binary_path = unicode(os.path.join(cache_dir, 'cipd' + EXECUTABLE_SUFFIX)) | 395 binary_path = unicode(os.path.join(cache_dir, 'cipd' + EXECUTABLE_SUFFIX)) |
| 395 if fs.isfile(binary_path): | 396 if fs.isfile(binary_path): |
| 396 file_path.remove(binary_path) | 397 file_path.remove(binary_path) |
| 397 instance_cache.link(instance_id, binary_path, 0511, False) # -r-x--x--x | 398 |
| 399 with instance_cache.getfileobj(instance_id) as f: |
| 400 isolateserver.putfile(f, binary_path, 0511) # -r-x--x--x |
| 398 | 401 |
| 399 yield CipdClient(binary_path) | 402 yield CipdClient(binary_path) |
| 400 | 403 |
| 401 | 404 |
| 402 def parse_package_args(packages): | 405 def parse_package_args(packages): |
| 403 """Parses --cipd-package arguments. | 406 """Parses --cipd-package arguments. |
| 404 | 407 |
| 405 Assumes |packages| were validated by validate_cipd_options. | 408 Assumes |packages| were validated by validate_cipd_options. |
| 406 | 409 |
| 407 Returns: | 410 Returns: |
| 408 A map {path: [(package, version)]}. | 411 A map {path: [(package, version)]}. |
| 409 """ | 412 """ |
| 410 result = collections.defaultdict(list) | 413 result = collections.defaultdict(list) |
| 411 for pkg in packages: | 414 for pkg in packages: |
| 412 path, name, version = pkg.split(':', 2) | 415 path, name, version = pkg.split(':', 2) |
| 413 path = path.replace('/', os.path.sep) | 416 path = path.replace('/', os.path.sep) |
| 414 if not name: | 417 if not name: |
| 415 raise Error('Invalid package "%s": package name is not specified' % pkg) | 418 raise Error('Invalid package "%s": package name is not specified' % pkg) |
| 416 if not version: | 419 if not version: |
| 417 raise Error('Invalid package "%s": version is not specified' % pkg) | 420 raise Error('Invalid package "%s": version is not specified' % pkg) |
| 418 result[path].append((name, version)) | 421 result[path].append((name, version)) |
| 419 return result | 422 return result |
| OLD | NEW |