| 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
|
|
|