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 |
(...skipping 291 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
302 expand_directory_and_symlink( | 302 expand_directory_and_symlink( |
303 indir, relfile, blacklist, follow_symlinks)) | 303 indir, relfile, blacklist, follow_symlinks)) |
304 except MappingError as e: | 304 except MappingError as e: |
305 if not ignore_broken_items: | 305 if not ignore_broken_items: |
306 raise | 306 raise |
307 logging.info('warning: %s', e) | 307 logging.info('warning: %s', e) |
308 return outfiles | 308 return outfiles |
309 | 309 |
310 | 310 |
311 @tools.profile | 311 @tools.profile |
312 def file_to_metadata(filepath, prevdict, read_only, algo): | 312 def file_to_metadata( |
313 filepath, prevdict, read_only, algo, collapse_symlinks=False): | |
M-A Ruel
2017/04/27 17:44:02
no default please
kjlubick
2017/04/27 17:55:37
Done.
| |
313 """Processes an input file, a dependency, and return meta data about it. | 314 """Processes an input file, a dependency, and return meta data about it. |
314 | 315 |
315 Behaviors: | 316 Behaviors: |
316 - Retrieves the file mode, file size, file timestamp, file link | 317 - Retrieves the file mode, file size, file timestamp, file link |
317 destination if it is a file link and calcultate the SHA-1 of the file's | 318 destination if it is a file link and calcultate the SHA-1 of the file's |
318 content if the path points to a file and not a symlink. | 319 content if the path points to a file and not a symlink. |
319 | 320 |
320 Arguments: | 321 Arguments: |
321 filepath: File to act on. | 322 filepath: File to act on. |
322 prevdict: the previous dictionary. It is used to retrieve the cached sha-1 | 323 prevdict: the previous dictionary. It is used to retrieve the cached sha-1 |
323 to skip recalculating the hash. Optional. | 324 to skip recalculating the hash. Optional. |
324 read_only: If 1 or 2, the file mode is manipulated. In practice, only save | 325 read_only: If 1 or 2, the file mode is manipulated. In practice, only save |
325 one of 4 modes: 0755 (rwx), 0644 (rw), 0555 (rx), 0444 (r). On | 326 one of 4 modes: 0755 (rwx), 0644 (rw), 0555 (rx), 0444 (r). On |
326 windows, mode is not set since all files are 'executable' by | 327 windows, mode is not set since all files are 'executable' by |
327 default. | 328 default. |
328 algo: Hashing algorithm used. | 329 algo: Hashing algorithm used. |
M-A Ruel
2017/04/27 17:44:02
update
kjlubick
2017/04/27 17:55:37
Done.
| |
329 | 330 |
330 Returns: | 331 Returns: |
331 The necessary dict to create a entry in the 'files' section of an .isolated | 332 The necessary dict to create a entry in the 'files' section of an .isolated |
332 file. | 333 file. |
333 """ | 334 """ |
334 # TODO(maruel): None is not a valid value. | 335 # TODO(maruel): None is not a valid value. |
335 assert read_only in (None, 0, 1, 2), read_only | 336 assert read_only in (None, 0, 1, 2), read_only |
336 out = {} | 337 out = {} |
337 # Always check the file stat and check if it is a link. The timestamp is used | 338 # Always check the file stat and check if it is a link. The timestamp is used |
338 # to know if the file's content/symlink destination should be looked into. | 339 # to know if the file's content/symlink destination should be looked into. |
339 # E.g. only reuse from prevdict if the timestamp hasn't changed. | 340 # E.g. only reuse from prevdict if the timestamp hasn't changed. |
340 # There is the risk of the file's timestamp being reset to its last value | 341 # There is the risk of the file's timestamp being reset to its last value |
341 # manually while its content changed. We don't protect against that use case. | 342 # manually while its content changed. We don't protect against that use case. |
342 try: | 343 try: |
343 filestats = os.lstat(filepath) | 344 filestats = None |
M-A Ruel
2017/04/27 17:44:02
not needed
kjlubick
2017/04/27 17:55:37
Done.
| |
345 if collapse_symlinks: | |
346 # os.stat follows symbolic links | |
347 filestats = os.stat(filepath) | |
348 else: | |
349 # os.lstat does not follow symbolic links, and thus preserves them. | |
350 filestats = os.lstat(filepath) | |
344 except OSError: | 351 except OSError: |
345 # The file is not present. | 352 # The file is not present. |
346 raise MappingError('%s is missing' % filepath) | 353 raise MappingError('%s is missing' % filepath) |
347 is_link = stat.S_ISLNK(filestats.st_mode) | 354 is_link = stat.S_ISLNK(filestats.st_mode) |
348 | 355 |
349 if sys.platform != 'win32': | 356 if sys.platform != 'win32': |
350 # Ignore file mode on Windows since it's not really useful there. | 357 # Ignore file mode on Windows since it's not really useful there. |
351 filemode = stat.S_IMODE(filestats.st_mode) | 358 filemode = stat.S_IMODE(filestats.st_mode) |
352 # Remove write access for group and all access to 'others'. | 359 # Remove write access for group and all access to 'others'. |
353 filemode &= ~(stat.S_IWGRP | stat.S_IRWXO) | 360 filemode &= ~(stat.S_IWGRP | stat.S_IRWXO) |
(...skipping 213 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
567 data['files'] = dict( | 574 data['files'] = dict( |
568 (k.replace(wrong_path_sep, os.path.sep), v) | 575 (k.replace(wrong_path_sep, os.path.sep), v) |
569 for k, v in data['files'].iteritems()) | 576 for k, v in data['files'].iteritems()) |
570 for v in data['files'].itervalues(): | 577 for v in data['files'].itervalues(): |
571 if 'l' in v: | 578 if 'l' in v: |
572 v['l'] = v['l'].replace(wrong_path_sep, os.path.sep) | 579 v['l'] = v['l'].replace(wrong_path_sep, os.path.sep) |
573 if 'relative_cwd' in data: | 580 if 'relative_cwd' in data: |
574 data['relative_cwd'] = data['relative_cwd'].replace( | 581 data['relative_cwd'] = data['relative_cwd'].replace( |
575 wrong_path_sep, os.path.sep) | 582 wrong_path_sep, os.path.sep) |
576 return data | 583 return data |
OLD | NEW |