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)