| Index: tools/isolate/tree_creator.py
|
| diff --git a/tools/isolate/tree_creator.py b/tools/isolate/tree_creator.py
|
| index 3c7e0c235d0bc978cf3666dd1d13efdd8d72098f..ad0990cc63d6d7ec0c5705924e34db4d3ab7e8aa 100644
|
| --- a/tools/isolate/tree_creator.py
|
| +++ b/tools/isolate/tree_creator.py
|
| @@ -2,13 +2,20 @@
|
| # Use of this source code is governed by a BSD-style license that can be
|
| # found in the LICENSE file.
|
|
|
| -"""Creates a tree of hardlinks, symlinks or copy the inputs files."""
|
| +"""File related utility functions.
|
| +
|
| +Creates a tree of hardlinks, symlinks or copy the inputs files. Calculate files
|
| +hash.
|
| +"""
|
|
|
| import ctypes
|
| +import hashlib
|
| import logging
|
| import os
|
| import shutil
|
| +import stat
|
| import sys
|
| +import time
|
|
|
|
|
| # Types of action accepted by recreate_tree().
|
| @@ -30,20 +37,9 @@ def os_link(source, link_name):
|
| os.link(source, link_name)
|
|
|
|
|
| -def preprocess_inputs(indir, infiles, blacklist):
|
| - """Reads the infiles and expands the directories and applies the blacklist.
|
| -
|
| - Returns the normalized indir and infiles. Converts infiles with a trailing
|
| - slash as the list of its files.
|
| - """
|
| - logging.debug('preprocess_inputs(%s, %s, %s)' % (indir, infiles, blacklist))
|
| - # Both need to be a local path.
|
| - indir = os.path.normpath(indir)
|
| - if not os.path.isdir(indir):
|
| - raise MappingError('%s is not a directory' % indir)
|
| -
|
| - # Do not call abspath until it was verified the directory exists.
|
| - indir = os.path.abspath(indir)
|
| +def expand_directories(indir, infiles, blacklist):
|
| + """Expands the directories, applies the blacklist and verifies files exist."""
|
| + logging.debug('expand_directories(%s, %s, %s)' % (indir, infiles, blacklist))
|
| outfiles = []
|
| for relfile in infiles:
|
| if os.path.isabs(relfile):
|
| @@ -68,10 +64,40 @@ def preprocess_inputs(indir, infiles, blacklist):
|
| if not os.path.isfile(infile):
|
| raise MappingError('Input file %s doesn\'t exist' % infile)
|
| outfiles.append(relfile)
|
| - return outfiles, indir
|
| + return outfiles
|
|
|
|
|
| -def process_file(outfile, infile, action):
|
| +def process_inputs(indir, infiles, need_hash, read_only):
|
| + """Returns a dictionary of input files, populated with the files' mode and
|
| + hash.
|
| +
|
| + The file mode is manipulated if read_only is True. In practice, we only save
|
| + one of 4 modes: 0755 (rwx), 0644 (rw), 0555 (rx), 0444 (r).
|
| + """
|
| + outdict = {}
|
| + for infile in infiles:
|
| + filepath = os.path.join(indir, infile)
|
| + filemode = stat.S_IMODE(os.stat(filepath).st_mode)
|
| + # Remove write access for non-owner.
|
| + filemode &= ~(stat.S_IWGRP | stat.S_IWOTH)
|
| + if read_only:
|
| + filemode &= ~stat.S_IWUSR
|
| + if filemode & stat.S_IXUSR:
|
| + filemode |= (stat.S_IXGRP | stat.S_IXOTH)
|
| + else:
|
| + filemode &= ~(stat.S_IXGRP | stat.S_IXOTH)
|
| + outdict[infile] = {
|
| + 'mode': filemode,
|
| + }
|
| + if need_hash:
|
| + h = hashlib.sha1()
|
| + with open(filepath, 'rb') as f:
|
| + h.update(f.read())
|
| + outdict[infile]['sha-1'] = h.hexdigest()
|
| + return outdict
|
| +
|
| +
|
| +def link_file(outfile, infile, action):
|
| """Links a file. The type of link depends on |action|."""
|
| logging.debug('Mapping %s to %s' % (infile, outfile))
|
| if os.path.isfile(outfile):
|
| @@ -98,10 +124,9 @@ def recreate_tree(outdir, indir, infiles, action):
|
| """Creates a new tree with only the input files in it.
|
|
|
| Arguments:
|
| - outdir: Temporary directory to create the files in.
|
| + outdir: Output directory to create the files in.
|
| indir: Root directory the infiles are based in.
|
| - infiles: List of files to map from |indir| to |outdir|. Must have been
|
| - sanitized with preprocess_inputs().
|
| + infiles: List of files to map from |indir| to |outdir|.
|
| action: See assert below.
|
| """
|
| logging.debug(
|
| @@ -122,7 +147,7 @@ def recreate_tree(outdir, indir, infiles, action):
|
| outsubdir = os.path.dirname(outfile)
|
| if not os.path.isdir(outsubdir):
|
| os.makedirs(outsubdir)
|
| - process_file(outfile, infile, action)
|
| + link_file(outfile, infile, action)
|
|
|
|
|
| def _set_write_bit(path, read_only):
|
| @@ -148,3 +173,19 @@ def make_writable(root, read_only):
|
|
|
| for dirname in dirnames:
|
| _set_write_bit(os.path.join(dirpath, dirname), read_only)
|
| +
|
| +
|
| +def rmtree(root):
|
| + """Wrapper around shutil.rmtree() to retry automatically on Windows."""
|
| + if sys.platform == 'win32':
|
| + for i in range(3):
|
| + try:
|
| + shutil.rmtree(root)
|
| + break
|
| + except WindowsError: # pylint: disable=E0602
|
| + delay = (i+1)*2
|
| + print >> sys.stderr, (
|
| + 'The test has subprocess outliving it. Sleep %d seconds.' % delay)
|
| + time.sleep(delay)
|
| + else:
|
| + shutil.rmtree(root)
|
|
|