comparison upmana/mercurial/archival.py @ 121:496dbf12a6cb alpha

Traipse Alpha 'OpenRPG' {091030-00} Traipse is a distribution of OpenRPG that is designed to be easy to setup and go. Traipse also makes it easy for developers to work on code without fear of sacrifice. 'Ornery-Orc' continues the trend of 'Grumpy' and adds fixes to the code. 'Ornery-Orc's main goal is to offer more advanced features and enhance the productivity of the user. Update Summary (Cleaning up for Beta): Adds Bookmarks (Alpha) with cool Smiley Star and Plus Symbol images! Changes made to the map for increased portability. SnowDog has changes planned in Core, though. Added an initial push to the BCG. Not much to see, just shows off how it is re-writing Main code. Fix to remote admin commands Minor fix to texted based server, works in /System/ folder Some Core changes to gametree to correctly disply Pretty Print, thanks David! Fix to Splitter Nodes not being created. Added images to Plugin Control panel for Autostart feature Fix to massive amounts of images loading; from Core fix to gsclient so with_statement imports Added 'boot' command to remote admin Prep work in Pass tool for remote admin rankings and different passwords, ei, Server, Admin, Moderator, etc. Remote Admin Commands more organized, more prep work. Added Confirmation window for sent nodes. Minor changes to allow for portability to an OpenSUSE linux OS (hopefully without breaking) {091028} Made changes to gametree to start working with Element Tree, mostly from Core Minor changes to Map to start working with Element Tree, from Core Preliminary changes to map efficiency, from FlexiRPG Miniatures Layer pop up box allows users to turn off Mini labels, from FlexiRPG Changes to main.py to start working with Element Tree {091029} Changes made to server to start working with Element Tree. Changes made to Meta Server Lib. Prepping test work for a multi meta network page. Minor bug fixed with mini to gametree Zoom Mouse plugin added. {091030} Getting ready for Beta. Server needs debugging so Alpha remains bugged. Plugin UI code cleaned. Auto start works with a graphic, pop-up asks to enable or disable plugin. Update Manager now has a partially working Status Bar. Status Bar captures terminal text, so Merc out put is visible. Manifest.xml file, will be renamed, is now much cleaner. Debug Console has a clear button and a Report Bug button. Prep work for a Term2Win class in Debug Console. Known: Current Alpha fails in Windows.
author sirebral
date Fri, 30 Oct 2009 22:21:40 -0500
parents
children
comparison
equal deleted inserted replaced
120:d86e762a994f 121:496dbf12a6cb
1 # archival.py - revision archival for mercurial
2 #
3 # Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com>
4 #
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2, incorporated herein by reference.
7
8 from i18n import _
9 from node import hex
10 import util
11 import cStringIO, os, stat, tarfile, time, zipfile
12 import zlib, gzip
13
14 def tidyprefix(dest, prefix, suffixes):
15 '''choose prefix to use for names in archive. make sure prefix is
16 safe for consumers.'''
17
18 if prefix:
19 prefix = util.normpath(prefix)
20 else:
21 if not isinstance(dest, str):
22 raise ValueError('dest must be string if no prefix')
23 prefix = os.path.basename(dest)
24 lower = prefix.lower()
25 for sfx in suffixes:
26 if lower.endswith(sfx):
27 prefix = prefix[:-len(sfx)]
28 break
29 lpfx = os.path.normpath(util.localpath(prefix))
30 prefix = util.pconvert(lpfx)
31 if not prefix.endswith('/'):
32 prefix += '/'
33 if prefix.startswith('../') or os.path.isabs(lpfx) or '/../' in prefix:
34 raise util.Abort(_('archive prefix contains illegal components'))
35 return prefix
36
37 class tarit(object):
38 '''write archive to tar file or stream. can write uncompressed,
39 or compress with gzip or bzip2.'''
40
41 class GzipFileWithTime(gzip.GzipFile):
42
43 def __init__(self, *args, **kw):
44 timestamp = None
45 if 'timestamp' in kw:
46 timestamp = kw.pop('timestamp')
47 if timestamp is None:
48 self.timestamp = time.time()
49 else:
50 self.timestamp = timestamp
51 gzip.GzipFile.__init__(self, *args, **kw)
52
53 def _write_gzip_header(self):
54 self.fileobj.write('\037\213') # magic header
55 self.fileobj.write('\010') # compression method
56 # Python 2.6 deprecates self.filename
57 fname = getattr(self, 'name', None) or self.filename
58 flags = 0
59 if fname:
60 flags = gzip.FNAME
61 self.fileobj.write(chr(flags))
62 gzip.write32u(self.fileobj, long(self.timestamp))
63 self.fileobj.write('\002')
64 self.fileobj.write('\377')
65 if fname:
66 self.fileobj.write(fname + '\000')
67
68 def __init__(self, dest, prefix, mtime, kind=''):
69 self.prefix = tidyprefix(dest, prefix, ['.tar', '.tar.bz2', '.tar.gz',
70 '.tgz', '.tbz2'])
71 self.mtime = mtime
72
73 def taropen(name, mode, fileobj=None):
74 if kind == 'gz':
75 mode = mode[0]
76 if not fileobj:
77 fileobj = open(name, mode + 'b')
78 gzfileobj = self.GzipFileWithTime(name, mode + 'b',
79 zlib.Z_BEST_COMPRESSION,
80 fileobj, timestamp=mtime)
81 return tarfile.TarFile.taropen(name, mode, gzfileobj)
82 else:
83 return tarfile.open(name, mode + kind, fileobj)
84
85 if isinstance(dest, str):
86 self.z = taropen(dest, mode='w:')
87 else:
88 # Python 2.5-2.5.1 have a regression that requires a name arg
89 self.z = taropen(name='', mode='w|', fileobj=dest)
90
91 def addfile(self, name, mode, islink, data):
92 i = tarfile.TarInfo(self.prefix + name)
93 i.mtime = self.mtime
94 i.size = len(data)
95 if islink:
96 i.type = tarfile.SYMTYPE
97 i.mode = 0777
98 i.linkname = data
99 data = None
100 i.size = 0
101 else:
102 i.mode = mode
103 data = cStringIO.StringIO(data)
104 self.z.addfile(i, data)
105
106 def done(self):
107 self.z.close()
108
109 class tellable(object):
110 '''provide tell method for zipfile.ZipFile when writing to http
111 response file object.'''
112
113 def __init__(self, fp):
114 self.fp = fp
115 self.offset = 0
116
117 def __getattr__(self, key):
118 return getattr(self.fp, key)
119
120 def write(self, s):
121 self.fp.write(s)
122 self.offset += len(s)
123
124 def tell(self):
125 return self.offset
126
127 class zipit(object):
128 '''write archive to zip file or stream. can write uncompressed,
129 or compressed with deflate.'''
130
131 def __init__(self, dest, prefix, mtime, compress=True):
132 self.prefix = tidyprefix(dest, prefix, ('.zip',))
133 if not isinstance(dest, str):
134 try:
135 dest.tell()
136 except (AttributeError, IOError):
137 dest = tellable(dest)
138 self.z = zipfile.ZipFile(dest, 'w',
139 compress and zipfile.ZIP_DEFLATED or
140 zipfile.ZIP_STORED)
141 self.date_time = time.gmtime(mtime)[:6]
142
143 def addfile(self, name, mode, islink, data):
144 i = zipfile.ZipInfo(self.prefix + name, self.date_time)
145 i.compress_type = self.z.compression
146 # unzip will not honor unix file modes unless file creator is
147 # set to unix (id 3).
148 i.create_system = 3
149 ftype = stat.S_IFREG
150 if islink:
151 mode = 0777
152 ftype = stat.S_IFLNK
153 i.external_attr = (mode | ftype) << 16L
154 self.z.writestr(i, data)
155
156 def done(self):
157 self.z.close()
158
159 class fileit(object):
160 '''write archive as files in directory.'''
161
162 def __init__(self, name, prefix, mtime):
163 if prefix:
164 raise util.Abort(_('cannot give prefix when archiving to files'))
165 self.basedir = name
166 self.opener = util.opener(self.basedir)
167
168 def addfile(self, name, mode, islink, data):
169 if islink:
170 self.opener.symlink(data, name)
171 return
172 f = self.opener(name, "w", atomictemp=True)
173 f.write(data)
174 f.rename()
175 destfile = os.path.join(self.basedir, name)
176 os.chmod(destfile, mode)
177
178 def done(self):
179 pass
180
181 archivers = {
182 'files': fileit,
183 'tar': tarit,
184 'tbz2': lambda name, prefix, mtime: tarit(name, prefix, mtime, 'bz2'),
185 'tgz': lambda name, prefix, mtime: tarit(name, prefix, mtime, 'gz'),
186 'uzip': lambda name, prefix, mtime: zipit(name, prefix, mtime, False),
187 'zip': zipit,
188 }
189
190 def archive(repo, dest, node, kind, decode=True, matchfn=None,
191 prefix=None, mtime=None):
192 '''create archive of repo as it was at node.
193
194 dest can be name of directory, name of archive file, or file
195 object to write archive to.
196
197 kind is type of archive to create.
198
199 decode tells whether to put files through decode filters from
200 hgrc.
201
202 matchfn is function to filter names of files to write to archive.
203
204 prefix is name of path to put before every archive member.'''
205
206 def write(name, mode, islink, getdata):
207 if matchfn and not matchfn(name): return
208 data = getdata()
209 if decode:
210 data = repo.wwritedata(name, data)
211 archiver.addfile(name, mode, islink, data)
212
213 if kind not in archivers:
214 raise util.Abort(_("unknown archive type '%s'") % kind)
215
216 ctx = repo[node]
217 archiver = archivers[kind](dest, prefix, mtime or ctx.date()[0])
218
219 if repo.ui.configbool("ui", "archivemeta", True):
220 write('.hg_archival.txt', 0644, False,
221 lambda: 'repo: %s\nnode: %s\n' % (
222 hex(repo.changelog.node(0)), hex(node)))
223 for f in ctx:
224 ff = ctx.flags(f)
225 write(f, 'x' in ff and 0755 or 0644, 'l' in ff, ctx[f].data)
226 archiver.done()