| OLD | NEW |
| 1 # Copyright 2014 The LUCI Authors. All rights reserved. | 1 # Copyright 2014 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 """Understands .isolated files and can do local operations on them.""" | 5 """Understands .isolated files and can do local operations on them.""" |
| 6 | 6 |
| 7 import hashlib | 7 import hashlib |
| 8 import json | 8 import json |
| 9 import logging | 9 import logging |
| 10 import os | 10 import os |
| 11 import re | 11 import re |
| 12 import stat | 12 import stat |
| 13 import sys | 13 import sys |
| 14 | 14 |
| 15 from utils import file_path | 15 from utils import file_path |
| 16 from utils import fs | 16 from utils import fs |
| 17 from utils import tools | 17 from utils import tools |
| 18 | 18 |
| 19 | 19 |
| 20 # Version stored and expected in .isolated files. | 20 # Version stored and expected in .isolated files. |
| 21 ISOLATED_FILE_VERSION = '1.4' | 21 ISOLATED_FILE_VERSION = '1.5' |
| 22 | 22 |
| 23 | 23 |
| 24 # Chunk size to use when doing disk I/O. | 24 # Chunk size to use when doing disk I/O. |
| 25 DISK_FILE_CHUNK = 1024 * 1024 | 25 DISK_FILE_CHUNK = 1024 * 1024 |
| 26 | 26 |
| 27 | 27 |
| 28 # Sadly, hashlib uses 'sha1' instead of the standard 'sha-1' so explicitly | 28 # Sadly, hashlib uses 'sha1' instead of the standard 'sha-1' so explicitly |
| 29 # specify the names here. | 29 # specify the names here. |
| 30 SUPPORTED_ALGOS = { | 30 SUPPORTED_ALGOS = { |
| 31 'md5': hashlib.md5, | 31 'md5': hashlib.md5, |
| 32 'sha-1': hashlib.sha1, | 32 'sha-1': hashlib.sha1, |
| 33 'sha-512': hashlib.sha512, | 33 'sha-512': hashlib.sha512, |
| 34 } | 34 } |
| 35 | 35 |
| 36 | 36 |
| 37 # Used for serialization. | 37 # Used for serialization. |
| 38 SUPPORTED_ALGOS_REVERSE = dict((v, k) for k, v in SUPPORTED_ALGOS.iteritems()) | 38 SUPPORTED_ALGOS_REVERSE = dict((v, k) for k, v in SUPPORTED_ALGOS.iteritems()) |
| 39 | 39 |
| 40 SUPPORTED_FILE_TYPES = ['basic', 'ar'] |
| 41 |
| 40 | 42 |
| 41 class IsolatedError(ValueError): | 43 class IsolatedError(ValueError): |
| 42 """Generic failure to load a .isolated file.""" | 44 """Generic failure to load a .isolated file.""" |
| 43 pass | 45 pass |
| 44 | 46 |
| 45 | 47 |
| 46 class MappingError(OSError): | 48 class MappingError(OSError): |
| 47 """Failed to recreate the tree.""" | 49 """Failed to recreate the tree.""" |
| 48 pass | 50 pass |
| 49 | 51 |
| (...skipping 449 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 499 raise IsolatedError('Expected string, got %r' % subsubvalue) | 501 raise IsolatedError('Expected string, got %r' % subsubvalue) |
| 500 elif subsubkey == 'm': | 502 elif subsubkey == 'm': |
| 501 if not isinstance(subsubvalue, int): | 503 if not isinstance(subsubvalue, int): |
| 502 raise IsolatedError('Expected int, got %r' % subsubvalue) | 504 raise IsolatedError('Expected int, got %r' % subsubvalue) |
| 503 elif subsubkey == 'h': | 505 elif subsubkey == 'h': |
| 504 if not is_valid_hash(subsubvalue, algo): | 506 if not is_valid_hash(subsubvalue, algo): |
| 505 raise IsolatedError('Expected sha-1, got %r' % subsubvalue) | 507 raise IsolatedError('Expected sha-1, got %r' % subsubvalue) |
| 506 elif subsubkey == 's': | 508 elif subsubkey == 's': |
| 507 if not isinstance(subsubvalue, (int, long)): | 509 if not isinstance(subsubvalue, (int, long)): |
| 508 raise IsolatedError('Expected int or long, got %r' % subsubvalue) | 510 raise IsolatedError('Expected int or long, got %r' % subsubvalue) |
| 511 elif subsubkey == 't': |
| 512 if subsubvalue not in SUPPORTED_FILE_TYPES: |
| 513 raise IsolatedError('Expected one of \'%s\', got %r' % ( |
| 514 ', '.join(sorted(SUPPORTED_FILE_TYPES)), subsubvalue)) |
| 509 else: | 515 else: |
| 510 raise IsolatedError('Unknown subsubkey %s' % subsubkey) | 516 raise IsolatedError('Unknown subsubkey %s' % subsubkey) |
| 511 if bool('h' in subvalue) == bool('l' in subvalue): | 517 if bool('h' in subvalue) == bool('l' in subvalue): |
| 512 raise IsolatedError( | 518 raise IsolatedError( |
| 513 'Need only one of \'h\' (sha-1) or \'l\' (link), got: %r' % | 519 'Need only one of \'h\' (sha-1) or \'l\' (link), got: %r' % |
| 514 subvalue) | 520 subvalue) |
| 515 if bool('h' in subvalue) != bool('s' in subvalue): | 521 if bool('h' in subvalue) != bool('s' in subvalue): |
| 516 raise IsolatedError( | 522 raise IsolatedError( |
| 517 'Both \'h\' (sha-1) and \'s\' (size) should be set, got: %r' % | 523 'Both \'h\' (sha-1) and \'s\' (size) should be set, got: %r' % |
| 518 subvalue) | 524 subvalue) |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 561 data['files'] = dict( | 567 data['files'] = dict( |
| 562 (k.replace(wrong_path_sep, os.path.sep), v) | 568 (k.replace(wrong_path_sep, os.path.sep), v) |
| 563 for k, v in data['files'].iteritems()) | 569 for k, v in data['files'].iteritems()) |
| 564 for v in data['files'].itervalues(): | 570 for v in data['files'].itervalues(): |
| 565 if 'l' in v: | 571 if 'l' in v: |
| 566 v['l'] = v['l'].replace(wrong_path_sep, os.path.sep) | 572 v['l'] = v['l'].replace(wrong_path_sep, os.path.sep) |
| 567 if 'relative_cwd' in data: | 573 if 'relative_cwd' in data: |
| 568 data['relative_cwd'] = data['relative_cwd'].replace( | 574 data['relative_cwd'] = data['relative_cwd'].replace( |
| 569 wrong_path_sep, os.path.sep) | 575 wrong_path_sep, os.path.sep) |
| 570 return data | 576 return data |
| OLD | NEW |