Index: build/cygtar.py |
diff --git a/build/cygtar.py b/build/cygtar.py |
index 4cdf1ca23362e39e28ecfcc8a4ce1b2bc5f2a29a..780648ec579ea89e44392b957ac761787ae06c49 100755 |
--- a/build/cygtar.py |
+++ b/build/cygtar.py |
@@ -7,6 +7,7 @@ import glob |
import hashlib |
import optparse |
import os |
+import posixpath |
import shutil |
import subprocess |
import stat |
@@ -129,7 +130,8 @@ def CreateWin32Hardlink(filepath, targpath, try_mklink): |
def ComputeFileHash(filepath): |
"""Generate a sha1 hash for the file at the given path.""" |
sha1 = hashlib.sha1() |
- sha1.update(open(filepath, 'rb').read()) |
+ with open(filepath, 'rb') as fp: |
+ sha1.update(fp.read()) |
return sha1.hexdigest() |
@@ -148,6 +150,7 @@ class CygTar(object): |
""" CygTar is an object which represents a Win32 and Cygwin aware tarball.""" |
def __init__(self, filename, mode='r', verbose=False): |
self.size_map = {} |
+ self.file_hashes = {} |
# Set errorlevel=1 so that fatal errors actually raise! |
self.tar = tarfile.open(filename, mode, errorlevel=1) |
self.verbose = verbose |
@@ -183,7 +186,7 @@ class CygTar(object): |
tarinfo.size = 0 |
self.__AddFile(tarinfo) |
- def Add(self, filepath): |
+ def Add(self, filepath, prefix=None): |
"""Add path filepath to the archive which may be Native style. |
Add files individually recursing on directories. For POSIX we use |
@@ -196,11 +199,14 @@ class CygTar(object): |
# At this point tarinfo.name will contain a POSIX style path regardless |
# of the original filepath. |
tarinfo = self.tar.gettarinfo(filepath) |
+ if prefix: |
+ tarinfo.name = posixpath.join(prefix, tarinfo.name) |
+ |
if sys.platform == 'win32': |
# On win32 os.stat() always claims that files are world writable |
# which means that unless we remove this bit here we end up with |
# world writables files in the archive, which is almost certainly |
- # not indented. |
+ # not intended. |
tarinfo.mode &= ~stat.S_IWOTH |
tarinfo.mode &= ~stat.S_IWGRP |
@@ -215,7 +221,7 @@ class CygTar(object): |
self.__AddFile(tarinfo) |
native_files = glob.glob(os.path.join(filepath, '*')) |
for native_file in native_files: |
- if not self.Add(native_file): return False |
+ if not self.Add(native_file, prefix): return False |
return True |
# At this point we only allow addition of "FILES" |
@@ -227,7 +233,8 @@ class CygTar(object): |
# We go ahead and check on all platforms just in case we are tar'ing a |
# mount shared with windows. |
if tarinfo.size <= 524: |
- symtext = open(tarinfo.name).read() |
+ with open(filepath) as fp: |
+ symtext = fp.read() |
if IsCygwinSymlink(symtext): |
self.__AddLink(tarinfo, tarfile.SYMTYPE, SymDatToPath(symtext)) |
return True |
@@ -239,31 +246,31 @@ class CygTar(object): |
# If that size bucket is empty, add this file, no need to get the hash until |
# we get a bucket collision for the first time.. |
if not nodelist: |
- self.size_map[tarinfo.size] = [(tarinfo.name, None)] |
- fp = open(tarinfo.name, 'rb') |
- self.__AddFile(tarinfo, fp) |
- fp.close() |
+ self.size_map[tarinfo.size] = [filepath] |
+ with open(filepath, 'rb') as fp: |
+ self.__AddFile(tarinfo, fp) |
return True |
# If the size collides with anything, we'll need to check hashes. We assume |
# no hash collisions for SHA1 on a given bucket, since the number of files |
# in a bucket over possible SHA1 values is near zero. |
- newhash = ComputeFileHash(tarinfo.name) |
- for (oldname, oldhash) in nodelist: |
- # if this is the first collision, we may need to compute the hash |
- # for this first node. |
- if oldhash is None: |
+ newhash = ComputeFileHash(filepath) |
+ self.file_hashes[filepath] = newhash |
+ |
+ for oldname in nodelist: |
+ oldhash = self.file_hashes.get(oldname, None) |
+ if not oldhash: |
oldhash = ComputeFileHash(oldname) |
+ self.file_hashes[oldname] = oldhash |
if oldhash == newhash: |
self.__AddLink(tarinfo, tarfile.LNKTYPE, oldname) |
return True |
# Otherwise, we missed, so add it to the bucket for this size |
- self.size_map[tarinfo.size].append((tarinfo.name, newhash)) |
- fp = open(tarinfo.name, 'rb') |
- self.__AddFile(tarinfo, fp) |
- fp.close() |
+ self.size_map[tarinfo.size].append(filepath) |
+ with open(filepath, 'rb') as fp: |
+ self.__AddFile(tarinfo, fp) |
return True |
def Extract(self): |
@@ -333,6 +340,7 @@ def Main(args): |
dest='filename', default='') |
parser.add_option('-C', '--directory', help='Change directory.', |
dest='cd', default='') |
+ parser.add_option('--prefix', help='Subdirectory prefix for all paths') |
options, args = parser.parse_args(args[1:]) |
if not options.action: |
@@ -364,7 +372,7 @@ def Main(args): |
if options.action == 'c': |
for filepath in args: |
- if not tar.Add(filepath): |
+ if not tar.Add(filepath, options.prefix): |
return -1 |
tar.Close() |
return 0 |