comparison upmana/mercurial/archival.py @ 28:ff154cf3350c ornery-orc

Traipse 'OpenRPG' {100203-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 (Stable) New Features: New Bookmarks Feature New 'boot' command to remote admin New confirmation window for sent nodes Miniatures Layer pop up box allows users to turn off Mini labels, from FlexiRPG New Zoom Mouse plugin added New Images added to Plugin UI Switching to Element Tree New Map efficiency, from FlexiRPG New Status Bar to Update Manager New TrueDebug Class in orpg_log (See documentation for usage) New Portable Mercurial New Tip of the Day, from Core and community New Reference Syntax added for custom PC sheets New Child Reference for gametree New Parent Reference for gametree New Gametree Recursion method, mapping, context sensitivity, and effeciency.. New Features node with bonus nodes and Node Referencing help added New Dieroller structure from Core New DieRoller portability for odd Dice New 7th Sea die roller; ie [7k3] = [7d10.takeHighest(3).open(10)] New 'Mythos' System die roller added New vs. die roller method for WoD; ie [3v3] = [3d10.vs(3)]. Included for Mythos roller also New Warhammer FRPG Die Roller (Special thanks to Puu-san for the support) New EZ_Tree Reference system. Push a button, Traipse the tree, get a reference (Beta!) New Grids act more like Spreadsheets in Use mode, with Auto Calc Fixes: Fix to allow for portability to an OpenSUSE linux OS Fix to mplay_client for Fedora and OpenSUSE Fix to Text based Server Fix to Remote Admin Commands Fix to Pretty Print, from Core Fix to Splitter Nodes not being created Fix to massive amounts of images loading, from Core Fix to Map from gametree not showing to all clients Fix to gametree about menus Fix to Password Manager check on startup Fix to PC Sheets from tool nodes. They now use the tabber_panel Fix to Whiteboard ID to prevent random line or text deleting. Fixes to Server, Remote Server, and Server GUI Fix to Update Manager; cleaner clode for saved repositories Fixes made to Settings Panel and now reactive settings when Ok is pressed Fixes to Alternity roller's attack roll. Uses a simple Tuple instead of a Splice Fix to Use panel of Forms and Tabbers. Now longer enters design mode Fix made Image Fetching. New fetching image and new failed image Fix to whiteboard ID's to prevent non updated clients from ruining the fix. default_manifest.xml renamed to default_upmana.xml
author sirebral
date Wed, 03 Feb 2010 22:16:49 -0600
parents
children
comparison
equal deleted inserted replaced
27:51428d30c59e 28:ff154cf3350c
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()