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( |
M-A Ruel
2017/04/27 17:58:49
this fits 80 cols
kjlubick
2017/04/27 18:02:04
Done.
| |
313 filepath, prevdict, read_only, algo, collapse_symlinks): | |
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. |
330 collapse_symlinks: True if symlinked files should be treated like they were | |
331 the normal underlying file. | |
329 | 332 |
330 Returns: | 333 Returns: |
331 The necessary dict to create a entry in the 'files' section of an .isolated | 334 The necessary dict to create a entry in the 'files' section of an .isolated |
332 file. | 335 file. |
333 """ | 336 """ |
334 # TODO(maruel): None is not a valid value. | 337 # TODO(maruel): None is not a valid value. |
335 assert read_only in (None, 0, 1, 2), read_only | 338 assert read_only in (None, 0, 1, 2), read_only |
336 out = {} | 339 out = {} |
337 # Always check the file stat and check if it is a link. The timestamp is used | 340 # 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. | 341 # 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. | 342 # 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 | 343 # 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. | 344 # manually while its content changed. We don't protect against that use case. |
342 try: | 345 try: |
343 filestats = os.lstat(filepath) | 346 if collapse_symlinks: |
347 # os.stat follows symbolic links | |
348 filestats = os.stat(filepath) | |
349 else: | |
350 # os.lstat does not follow symbolic links, and thus preserves them. | |
351 filestats = os.lstat(filepath) | |
344 except OSError: | 352 except OSError: |
345 # The file is not present. | 353 # The file is not present. |
346 raise MappingError('%s is missing' % filepath) | 354 raise MappingError('%s is missing' % filepath) |
347 is_link = stat.S_ISLNK(filestats.st_mode) | 355 is_link = stat.S_ISLNK(filestats.st_mode) |
348 | 356 |
349 if sys.platform != 'win32': | 357 if sys.platform != 'win32': |
350 # Ignore file mode on Windows since it's not really useful there. | 358 # Ignore file mode on Windows since it's not really useful there. |
351 filemode = stat.S_IMODE(filestats.st_mode) | 359 filemode = stat.S_IMODE(filestats.st_mode) |
352 # Remove write access for group and all access to 'others'. | 360 # Remove write access for group and all access to 'others'. |
353 filemode &= ~(stat.S_IWGRP | stat.S_IRWXO) | 361 filemode &= ~(stat.S_IWGRP | stat.S_IRWXO) |
(...skipping 213 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
567 data['files'] = dict( | 575 data['files'] = dict( |
568 (k.replace(wrong_path_sep, os.path.sep), v) | 576 (k.replace(wrong_path_sep, os.path.sep), v) |
569 for k, v in data['files'].iteritems()) | 577 for k, v in data['files'].iteritems()) |
570 for v in data['files'].itervalues(): | 578 for v in data['files'].itervalues(): |
571 if 'l' in v: | 579 if 'l' in v: |
572 v['l'] = v['l'].replace(wrong_path_sep, os.path.sep) | 580 v['l'] = v['l'].replace(wrong_path_sep, os.path.sep) |
573 if 'relative_cwd' in data: | 581 if 'relative_cwd' in data: |
574 data['relative_cwd'] = data['relative_cwd'].replace( | 582 data['relative_cwd'] = data['relative_cwd'].replace( |
575 wrong_path_sep, os.path.sep) | 583 wrong_path_sep, os.path.sep) |
576 return data | 584 return data |
OLD | NEW |