Mercurial > traipse
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() |