mercurial/archival.py
changeset 4652 06de65673ec2
parent 4368 6af107c742bf
child 4688 8f91264f154a
equal deleted inserted replaced
4651:7176f278d6f9 4652:06de65673ec2
     6 # the GNU General Public License, incorporated herein by reference.
     6 # the GNU General Public License, incorporated herein by reference.
     7 
     7 
     8 from i18n import _
     8 from i18n import _
     9 from node import *
     9 from node import *
    10 import cStringIO, os, stat, tarfile, time, util, zipfile
    10 import cStringIO, os, stat, tarfile, time, util, zipfile
       
    11 import zlib, gzip
    11 
    12 
    12 def tidyprefix(dest, prefix, suffixes):
    13 def tidyprefix(dest, prefix, suffixes):
    13     '''choose prefix to use for names in archive.  make sure prefix is
    14     '''choose prefix to use for names in archive.  make sure prefix is
    14     safe for consumers.'''
    15     safe for consumers.'''
    15 
    16 
    34 
    35 
    35 class tarit:
    36 class tarit:
    36     '''write archive to tar file or stream.  can write uncompressed,
    37     '''write archive to tar file or stream.  can write uncompressed,
    37     or compress with gzip or bzip2.'''
    38     or compress with gzip or bzip2.'''
    38 
    39 
       
    40     class GzipFileWithTime(gzip.GzipFile):
       
    41 
       
    42         def __init__(self, *args, **kw):
       
    43             timestamp = None
       
    44             if 'timestamp' in kw:
       
    45                 timestamp = kw.pop('timestamp')
       
    46             if timestamp == None:
       
    47                 self.timestamp = time.time()
       
    48             else:
       
    49                 self.timestamp = timestamp
       
    50             gzip.GzipFile.__init__(self, *args, **kw)
       
    51 
       
    52         def _write_gzip_header(self):
       
    53             self.fileobj.write('\037\213')             # magic header
       
    54             self.fileobj.write('\010')                 # compression method
       
    55             fname = self.filename[:-3]
       
    56             flags = 0
       
    57             if fname:
       
    58                 flags = gzip.FNAME
       
    59             self.fileobj.write(chr(flags))
       
    60             gzip.write32u(self.fileobj, long(self.timestamp))
       
    61             self.fileobj.write('\002')
       
    62             self.fileobj.write('\377')
       
    63             if fname:
       
    64                 self.fileobj.write(fname + '\000')
       
    65 
    39     def __init__(self, dest, prefix, mtime, kind=''):
    66     def __init__(self, dest, prefix, mtime, kind=''):
    40         self.prefix = tidyprefix(dest, prefix, ['.tar', '.tar.bz2', '.tar.gz',
    67         self.prefix = tidyprefix(dest, prefix, ['.tar', '.tar.bz2', '.tar.gz',
    41                                                 '.tgz', '.tbz2'])
    68                                                 '.tgz', '.tbz2'])
    42         self.mtime = mtime
    69         self.mtime = mtime
       
    70 
       
    71         def taropen(name, mode, fileobj=None):
       
    72             if kind == 'gz':
       
    73                 mode = mode[0]
       
    74                 if not fileobj:
       
    75                     fileobj = open(name, mode)
       
    76                 gzfileobj = self.GzipFileWithTime(name, mode + 'b',
       
    77                                                   zlib.Z_BEST_COMPRESSION,
       
    78                                                   fileobj, timestamp=mtime)
       
    79                 return tarfile.TarFile.taropen(name, mode, gzfileobj)
       
    80             else:
       
    81                 return tarfile.open(name, mode + kind, fileobj)
       
    82 
    43         if isinstance(dest, str):
    83         if isinstance(dest, str):
    44             self.z = tarfile.open(dest, mode='w:'+kind)
    84             self.z = taropen(dest, mode='w:')
    45         else:
    85         else:
    46             # Python 2.5-2.5.1 have a regression that requires a name arg
    86             # Python 2.5-2.5.1 have a regression that requires a name arg
    47             self.z = tarfile.open(name='', mode='w|'+kind, fileobj=dest)
    87             self.z = taropen(name='', mode='w|', fileobj=dest)
    48 
    88 
    49     def addfile(self, name, mode, data):
    89     def addfile(self, name, mode, data):
    50         i = tarfile.TarInfo(self.prefix + name)
    90         i = tarfile.TarInfo(self.prefix + name)
    51         i.mtime = self.mtime
    91         i.mtime = self.mtime
    52         i.size = len(data)
    92         i.size = len(data)