Mercurial > traipse_dev
comparison upmana/mercurial/hg.py @ 135:dcf4fbe09b70 beta
Traipse Beta 'OpenRPG' {091010-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 (Beta)
Added Bookmarks
Fix to Remote Admin Commands
Minor fix to text based Server
Fix to Pretty Print, from Core
Fix to Splitter Nodes not being created
Fix to massive amounts of images loading, from Core
Added 'boot' command to remote admin
Added confirmation window for sent nodes
Minor changes to allow for portability to an OpenSUSE linux OS
Miniatures Layer pop up box allows users to turn off Mini labels, from FlexiRPG
Zoom Mouse plugin added
Images added to Plugin UI
Switching to Element Tree
Map efficiency, from FlexiRPG
Added Status Bar to Update Manager
default_manifest.xml renamed to default_upmana.xml
Cleaner clode for saved repositories
New TrueDebug Class in orpg_log (See documentation for usage)
Mercurial's hgweb folder is ported to upmana
**Pretty important update that can help remove thousands of dead children from your gametree.
**Children, <forms />, <group_atts />, <horizontal />, <cols />, <rows />, <height />, etc... are all tags now. Check your gametree and
look for dead children!!
**New Gamtree Recusion method, mapping, and context sensitivity. !!Alpha - Watch out for infinite loops!!
author | sirebral |
---|---|
date | Tue, 10 Nov 2009 14:11:28 -0600 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
101:394ebb3b6a0f | 135:dcf4fbe09b70 |
---|---|
1 # hg.py - repository classes for mercurial | |
2 # | |
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com> | |
4 # Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com> | |
5 # | |
6 # This software may be used and distributed according to the terms of the | |
7 # GNU General Public License version 2, incorporated herein by reference. | |
8 | |
9 from i18n import _ | |
10 from lock import release | |
11 import localrepo, bundlerepo, httprepo, sshrepo, statichttprepo | |
12 import lock, util, extensions, error | |
13 import merge as _merge | |
14 import verify as _verify | |
15 import errno, os, shutil | |
16 | |
17 def _local(path): | |
18 return (os.path.isfile(util.drop_scheme('file', path)) and | |
19 bundlerepo or localrepo) | |
20 | |
21 def parseurl(url, revs=[]): | |
22 '''parse url#branch, returning url, branch + revs''' | |
23 | |
24 if '#' not in url: | |
25 return url, (revs or None), revs and revs[-1] or None | |
26 | |
27 url, branch = url.split('#', 1) | |
28 checkout = revs and revs[-1] or branch | |
29 return url, (revs or []) + [branch], checkout | |
30 | |
31 schemes = { | |
32 'bundle': bundlerepo, | |
33 'file': _local, | |
34 'http': httprepo, | |
35 'https': httprepo, | |
36 'ssh': sshrepo, | |
37 'static-http': statichttprepo, | |
38 } | |
39 | |
40 def _lookup(path): | |
41 scheme = 'file' | |
42 if path: | |
43 c = path.find(':') | |
44 if c > 0: | |
45 scheme = path[:c] | |
46 thing = schemes.get(scheme) or schemes['file'] | |
47 try: | |
48 return thing(path) | |
49 except TypeError: | |
50 return thing | |
51 | |
52 def islocal(repo): | |
53 '''return true if repo or path is local''' | |
54 if isinstance(repo, str): | |
55 try: | |
56 return _lookup(repo).islocal(repo) | |
57 except AttributeError: | |
58 return False | |
59 return repo.local() | |
60 | |
61 def repository(ui, path='', create=False): | |
62 """return a repository object for the specified path""" | |
63 repo = _lookup(path).instance(ui, path, create) | |
64 ui = getattr(repo, "ui", ui) | |
65 for name, module in extensions.extensions(): | |
66 hook = getattr(module, 'reposetup', None) | |
67 if hook: | |
68 hook(ui, repo) | |
69 return repo | |
70 | |
71 def defaultdest(source): | |
72 '''return default destination of clone if none is given''' | |
73 return os.path.basename(os.path.normpath(source)) | |
74 | |
75 def localpath(path): | |
76 if path.startswith('file://localhost/'): | |
77 return path[16:] | |
78 if path.startswith('file://'): | |
79 return path[7:] | |
80 if path.startswith('file:'): | |
81 return path[5:] | |
82 return path | |
83 | |
84 def share(ui, source, dest=None, update=True): | |
85 '''create a shared repository''' | |
86 | |
87 if not islocal(source): | |
88 raise util.Abort(_('can only share local repositories')) | |
89 | |
90 if not dest: | |
91 dest = os.path.basename(source) | |
92 | |
93 if isinstance(source, str): | |
94 origsource = ui.expandpath(source) | |
95 source, rev, checkout = parseurl(origsource, '') | |
96 srcrepo = repository(ui, source) | |
97 else: | |
98 srcrepo = source | |
99 origsource = source = srcrepo.url() | |
100 checkout = None | |
101 | |
102 sharedpath = srcrepo.sharedpath # if our source is already sharing | |
103 | |
104 root = os.path.realpath(dest) | |
105 roothg = os.path.join(root, '.hg') | |
106 | |
107 if os.path.exists(roothg): | |
108 raise util.Abort(_('destination already exists')) | |
109 | |
110 if not os.path.isdir(root): | |
111 os.mkdir(root) | |
112 os.mkdir(roothg) | |
113 | |
114 requirements = '' | |
115 try: | |
116 requirements = srcrepo.opener('requires').read() | |
117 except IOError, inst: | |
118 if inst.errno != errno.ENOENT: | |
119 raise | |
120 | |
121 requirements += 'shared\n' | |
122 file(os.path.join(roothg, 'requires'), 'w').write(requirements) | |
123 file(os.path.join(roothg, 'sharedpath'), 'w').write(sharedpath) | |
124 | |
125 default = srcrepo.ui.config('paths', 'default') | |
126 if default: | |
127 f = file(os.path.join(roothg, 'hgrc'), 'w') | |
128 f.write('[paths]\ndefault = %s\n' % default) | |
129 f.close() | |
130 | |
131 r = repository(ui, root) | |
132 | |
133 if update: | |
134 r.ui.status(_("updating working directory\n")) | |
135 if update is not True: | |
136 checkout = update | |
137 for test in (checkout, 'default', 'tip'): | |
138 try: | |
139 uprev = r.lookup(test) | |
140 break | |
141 except: | |
142 continue | |
143 _update(r, uprev) | |
144 | |
145 def clone(ui, source, dest=None, pull=False, rev=None, update=True, | |
146 stream=False): | |
147 """Make a copy of an existing repository. | |
148 | |
149 Create a copy of an existing repository in a new directory. The | |
150 source and destination are URLs, as passed to the repository | |
151 function. Returns a pair of repository objects, the source and | |
152 newly created destination. | |
153 | |
154 The location of the source is added to the new repository's | |
155 .hg/hgrc file, as the default to be used for future pulls and | |
156 pushes. | |
157 | |
158 If an exception is raised, the partly cloned/updated destination | |
159 repository will be deleted. | |
160 | |
161 Arguments: | |
162 | |
163 source: repository object or URL | |
164 | |
165 dest: URL of destination repository to create (defaults to base | |
166 name of source repository) | |
167 | |
168 pull: always pull from source repository, even in local case | |
169 | |
170 stream: stream raw data uncompressed from repository (fast over | |
171 LAN, slow over WAN) | |
172 | |
173 rev: revision to clone up to (implies pull=True) | |
174 | |
175 update: update working directory after clone completes, if | |
176 destination is local repository (True means update to default rev, | |
177 anything else is treated as a revision) | |
178 """ | |
179 | |
180 if isinstance(source, str): | |
181 origsource = ui.expandpath(source) | |
182 source, rev, checkout = parseurl(origsource, rev) | |
183 src_repo = repository(ui, source) | |
184 else: | |
185 src_repo = source | |
186 origsource = source = src_repo.url() | |
187 checkout = rev and rev[-1] or None | |
188 | |
189 if dest is None: | |
190 dest = defaultdest(source) | |
191 ui.status(_("destination directory: %s\n") % dest) | |
192 | |
193 dest = localpath(dest) | |
194 source = localpath(source) | |
195 | |
196 if os.path.exists(dest): | |
197 if not os.path.isdir(dest): | |
198 raise util.Abort(_("destination '%s' already exists") % dest) | |
199 elif os.listdir(dest): | |
200 raise util.Abort(_("destination '%s' is not empty") % dest) | |
201 | |
202 class DirCleanup(object): | |
203 def __init__(self, dir_): | |
204 self.rmtree = shutil.rmtree | |
205 self.dir_ = dir_ | |
206 def close(self): | |
207 self.dir_ = None | |
208 def cleanup(self): | |
209 if self.dir_: | |
210 self.rmtree(self.dir_, True) | |
211 | |
212 src_lock = dest_lock = dir_cleanup = None | |
213 try: | |
214 if islocal(dest): | |
215 dir_cleanup = DirCleanup(dest) | |
216 | |
217 abspath = origsource | |
218 copy = False | |
219 if src_repo.cancopy() and islocal(dest): | |
220 abspath = os.path.abspath(util.drop_scheme('file', origsource)) | |
221 copy = not pull and not rev | |
222 | |
223 if copy: | |
224 try: | |
225 # we use a lock here because if we race with commit, we | |
226 # can end up with extra data in the cloned revlogs that's | |
227 # not pointed to by changesets, thus causing verify to | |
228 # fail | |
229 src_lock = src_repo.lock(wait=False) | |
230 except error.LockError: | |
231 copy = False | |
232 | |
233 if copy: | |
234 src_repo.hook('preoutgoing', throw=True, source='clone') | |
235 hgdir = os.path.realpath(os.path.join(dest, ".hg")) | |
236 if not os.path.exists(dest): | |
237 os.mkdir(dest) | |
238 else: | |
239 # only clean up directories we create ourselves | |
240 dir_cleanup.dir_ = hgdir | |
241 try: | |
242 dest_path = hgdir | |
243 os.mkdir(dest_path) | |
244 except OSError, inst: | |
245 if inst.errno == errno.EEXIST: | |
246 dir_cleanup.close() | |
247 raise util.Abort(_("destination '%s' already exists") | |
248 % dest) | |
249 raise | |
250 | |
251 for f in src_repo.store.copylist(): | |
252 src = os.path.join(src_repo.path, f) | |
253 dst = os.path.join(dest_path, f) | |
254 dstbase = os.path.dirname(dst) | |
255 if dstbase and not os.path.exists(dstbase): | |
256 os.mkdir(dstbase) | |
257 if os.path.exists(src): | |
258 if dst.endswith('data'): | |
259 # lock to avoid premature writing to the target | |
260 dest_lock = lock.lock(os.path.join(dstbase, "lock")) | |
261 util.copyfiles(src, dst) | |
262 | |
263 # we need to re-init the repo after manually copying the data | |
264 # into it | |
265 dest_repo = repository(ui, dest) | |
266 src_repo.hook('outgoing', source='clone', node='0'*40) | |
267 else: | |
268 try: | |
269 dest_repo = repository(ui, dest, create=True) | |
270 except OSError, inst: | |
271 if inst.errno == errno.EEXIST: | |
272 dir_cleanup.close() | |
273 raise util.Abort(_("destination '%s' already exists") | |
274 % dest) | |
275 raise | |
276 | |
277 revs = None | |
278 if rev: | |
279 if 'lookup' not in src_repo.capabilities: | |
280 raise util.Abort(_("src repository does not support revision " | |
281 "lookup and so doesn't support clone by " | |
282 "revision")) | |
283 revs = [src_repo.lookup(r) for r in rev] | |
284 checkout = revs[0] | |
285 if dest_repo.local(): | |
286 dest_repo.clone(src_repo, heads=revs, stream=stream) | |
287 elif src_repo.local(): | |
288 src_repo.push(dest_repo, revs=revs) | |
289 else: | |
290 raise util.Abort(_("clone from remote to remote not supported")) | |
291 | |
292 if dir_cleanup: | |
293 dir_cleanup.close() | |
294 | |
295 if dest_repo.local(): | |
296 fp = dest_repo.opener("hgrc", "w", text=True) | |
297 fp.write("[paths]\n") | |
298 fp.write("default = %s\n" % abspath) | |
299 fp.close() | |
300 | |
301 dest_repo.ui.setconfig('paths', 'default', abspath) | |
302 | |
303 if update: | |
304 dest_repo.ui.status(_("updating working directory\n")) | |
305 if update is not True: | |
306 checkout = update | |
307 for test in (checkout, 'default', 'tip'): | |
308 try: | |
309 uprev = dest_repo.lookup(test) | |
310 break | |
311 except: | |
312 continue | |
313 _update(dest_repo, uprev) | |
314 | |
315 return src_repo, dest_repo | |
316 finally: | |
317 release(src_lock, dest_lock) | |
318 if dir_cleanup is not None: | |
319 dir_cleanup.cleanup() | |
320 | |
321 def _showstats(repo, stats): | |
322 stats = ((stats[0], _("updated")), | |
323 (stats[1], _("merged")), | |
324 (stats[2], _("removed")), | |
325 (stats[3], _("unresolved"))) | |
326 note = ", ".join([_("%d files %s") % s for s in stats]) | |
327 repo.ui.status("%s\n" % note) | |
328 | |
329 def update(repo, node): | |
330 """update the working directory to node, merging linear changes""" | |
331 stats = _merge.update(repo, node, False, False, None) | |
332 _showstats(repo, stats) | |
333 if stats[3]: | |
334 repo.ui.status(_("use 'hg resolve' to retry unresolved file merges\n")) | |
335 return stats[3] > 0 | |
336 | |
337 # naming conflict in clone() | |
338 _update = update | |
339 | |
340 def clean(repo, node, show_stats=True): | |
341 """forcibly switch the working directory to node, clobbering changes""" | |
342 stats = _merge.update(repo, node, False, True, None) | |
343 if show_stats: _showstats(repo, stats) | |
344 return stats[3] > 0 | |
345 | |
346 def merge(repo, node, force=None, remind=True): | |
347 """branch merge with node, resolving changes""" | |
348 stats = _merge.update(repo, node, True, force, False) | |
349 _showstats(repo, stats) | |
350 if stats[3]: | |
351 repo.ui.status(_("use 'hg resolve' to retry unresolved file merges " | |
352 "or 'hg up --clean' to abandon\n")) | |
353 elif remind: | |
354 repo.ui.status(_("(branch merge, don't forget to commit)\n")) | |
355 return stats[3] > 0 | |
356 | |
357 def revert(repo, node, choose): | |
358 """revert changes to revision in node without updating dirstate""" | |
359 return _merge.update(repo, node, False, True, choose)[3] > 0 | |
360 | |
361 def verify(repo): | |
362 """verify the consistency of a repository""" | |
363 return _verify.verify(repo) |