comparison upmana/mercurial/hg.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 # 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)