Index: isolate/tree_creator.py |
=================================================================== |
--- isolate/tree_creator.py (revision 0) |
+++ isolate/tree_creator.py (revision 0) |
@@ -0,0 +1,124 @@ |
+# Copyright (c) 2012 The Chromium Authors. All rights reserved. |
+# 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.""" |
+ |
+import logging |
+import os |
+import shutil |
+import sys |
+ |
+import find_depot_tools # pylint: disable=W0611 |
+import gclient_utils |
+ |
+ |
+# Types of action accepted by recreate_tree(). |
+DRY_RUN, HARDLINK, SYMLINK, COPY = range(5)[1:] |
+ |
+ |
+def CreateHardLink(src, dst): |
+ """Add support for os.link() on Windows.""" |
+ import ctypes |
+ if not ctypes.windll.kernel32.CreateHardLinkW(unicode(dst), unicode(src), 0): |
+ raise OSError() |
+ |
+ |
+class Foo(OSError): |
+ """Failed to recreate the tree.""" |
+ pass |
+ |
+ |
+def recreate_tree(outdir, indir, infiles, action, blacklist): |
+ """Creates a new tree with only the input files in it.""" |
+ assert action in (DRY_RUN, HARDLINK, SYMLINK, COPY) |
+ indir = os.path.normpath(indir) |
+ outdir = os.path.normpath(outdir) |
+ logging.info('%s -> %s' % (indir, outdir)) |
+ if not os.path.isdir(indir): |
+ raise Foo('%s is not a directory' % indir) |
+ # Do not call abspath until it was verified the directory exists. |
+ indir = os.path.abspath(indir) |
+ if os.path.isdir(outdir): |
+ logging.warn('Deleting %s' % outdir) |
+ if action != DRY_RUN: |
+ gclient_utils.RemoveDirectory(outdir) |
+ if action != DRY_RUN: |
+ logging.info ('Creating %s' % outdir) |
+ os.makedirs(outdir) |
+ # Do not call abspath until the directory exists. |
+ outdir = os.path.abspath(outdir) |
+ logging.info ('Created %s' % outdir) |
+ |
+ def process(inf, outf): |
+ inf = os.path.normpath(inf) |
+ outf = os.path.normpath(outf) |
+ if action == DRY_RUN: |
+ print outf |
+ else: |
+ logging.debug('%s -> %s' % (inf, outf)) |
+ if not os.path.isfile(inf): |
+ raise Foo('%s doesn\'t exist' % inf) |
+ if os.path.isfile(outf): |
+ raise Foo('%s already exist' % outf) |
+ if action == COPY: |
+ shutil.copy(inf, outf) |
+ elif action == SYMLINK: |
+ os.symlink(inf, outf) |
+ try: |
+ if action == HARDLINK: |
+ if sys.platform == 'win32': |
+ CreateHardLink(inf, outf) |
+ else: |
+ os.link(inf, outf) |
+ except OSError: |
+ # Probably a different file system. |
+ os.symlink(inf, outf) |
+ |
+ # Make the file read-only. |
+ # TODO(maruel): Implement DACL modification on Windows. |
+ mode = os.stat(inf).st_mode |
+ mode = mode & 0500 |
+ if hasattr(os, 'lchmod'): |
+ # Module 'os' has no 'lchmod' member |
+ # pylint: disable=E1101 |
+ os.lchmod(outf, mode) |
+ else: |
+ os.chmod(outf, mode) |
+ |
+ for relfile in infiles: |
+ infile = os.path.normpath(os.path.join(indir, relfile)) |
+ logging.debug(infile) |
+ if not infile.startswith(indir): |
+ raise Foo('Can\'t map file %s outside %s' % (infile, indir)) |
+ if os.path.isdir(infile): |
+ # Process recursively. |
+ for dirpath, dirnames, filenames in os.walk(infile): |
+ insubdir = os.path.normpath(os.path.join(infile, dirpath)) |
+ outsubdir = os.path.normpath( |
+ os.path.join(outdir, insubdir[len(indir) + 1:])) |
+ for filename in filenames: |
+ insubfile = os.path.normpath(os.path.join(infile, dirpath, filename)) |
+ outsubfile = os.path.normpath(os.path.join(outsubdir, filename)) |
+ if blacklist and blacklist(outsubfile): |
+ continue |
+ if not os.path.isdir(outsubdir): |
+ os.makedirs(outsubdir) |
+ process(insubfile, outsubfile) |
+ for index, dirname in enumerate(dirnames): |
+ if blacklist(os.path.normpath(os.path.join(outdir, dirname))): |
+ del dirnames[index] |
+ else: |
+ # TODO(maruel): Is that secure? |
+ outsubfile = os.path.normpath(os.path.join(outdir, relfile)) |
+ if blacklist and blacklist(outsubfile): |
+ continue |
+ outsubdir = os.path.dirname(outsubfile) |
+ if not os.path.isdir(outsubdir): |
+ os.makedirs(outsubdir) |
+ process(infile, outsubfile) |
+ |
+ # Then mark all the directories as read-only to inhibit file creation. |
+ for dirpath, _, _ in os.walk(outdir): |
+ # TODO(maruel): Implement DACL modification on Windows. |
+ os.chmod(os.path.join(outdir, dirpath), 0500) |
Property changes on: isolate/tree_creator.py |
___________________________________________________________________ |
Added: svn:eol-style |
+ LF |