Mercurial > public > mercurial-scm > hg
comparison mercurial/localrepo.py @ 1782:b9671b41e360
merge with crew
author | Benoit Boissinot <benoit.boissinot@ens-lyon.org> |
---|---|
date | Tue, 21 Feb 2006 16:46:38 +0100 |
parents | 284fc722c342 fdfe89a3962d |
children | 2e0a288ca93e e431344e604c |
comparison
equal
deleted
inserted
replaced
1781:284fc722c342 | 1782:b9671b41e360 |
---|---|
46 try: | 46 try: |
47 self.ui.readconfig(self.join("hgrc")) | 47 self.ui.readconfig(self.join("hgrc")) |
48 except IOError: | 48 except IOError: |
49 pass | 49 pass |
50 | 50 |
51 def hook(self, name, **args): | 51 def hook(self, name, throw=False, **args): |
52 def runhook(name, cmd): | 52 def runhook(name, cmd): |
53 self.ui.note(_("running hook %s: %s\n") % (name, cmd)) | 53 self.ui.note(_("running hook %s: %s\n") % (name, cmd)) |
54 old = {} | 54 old = {} |
55 for k, v in args.items(): | 55 for k, v in args.items(): |
56 k = k.upper() | 56 k = k.upper() |
57 old['HG_' + k] = os.environ.get(k, None) | |
57 old[k] = os.environ.get(k, None) | 58 old[k] = os.environ.get(k, None) |
58 os.environ[k] = v | 59 os.environ['HG_' + k] = str(v) |
59 | 60 os.environ[k] = str(v) |
60 # Hooks run in the repository root | 61 |
61 olddir = os.getcwd() | 62 try: |
62 os.chdir(self.root) | 63 # Hooks run in the repository root |
63 r = os.system(cmd) | 64 olddir = os.getcwd() |
64 os.chdir(olddir) | 65 os.chdir(self.root) |
65 | 66 r = os.system(cmd) |
66 for k, v in old.items(): | 67 finally: |
67 if v != None: | 68 for k, v in old.items(): |
68 os.environ[k] = v | 69 if v is not None: |
69 else: | 70 os.environ[k] = v |
70 del os.environ[k] | 71 else: |
72 del os.environ[k] | |
73 | |
74 os.chdir(olddir) | |
71 | 75 |
72 if r: | 76 if r: |
73 self.ui.warn(_("abort: %s hook failed with status %d!\n") % | 77 desc, r = util.explain_exit(r) |
74 (name, r)) | 78 if throw: |
79 raise util.Abort(_('%s hook %s') % (name, desc)) | |
80 self.ui.warn(_('error: %s hook %s\n') % (name, desc)) | |
75 return False | 81 return False |
76 return True | 82 return True |
77 | 83 |
78 r = True | 84 r = True |
79 for hname, cmd in self.ui.configitems("hooks"): | 85 for hname, cmd in self.ui.configitems("hooks"): |
223 | 229 |
224 return transaction.transaction(self.ui.warn, self.opener, | 230 return transaction.transaction(self.ui.warn, self.opener, |
225 self.join("journal"), after) | 231 self.join("journal"), after) |
226 | 232 |
227 def recover(self): | 233 def recover(self): |
228 lock = self.lock() | 234 l = self.lock() |
229 if os.path.exists(self.join("journal")): | 235 if os.path.exists(self.join("journal")): |
230 self.ui.status(_("rolling back interrupted transaction\n")) | 236 self.ui.status(_("rolling back interrupted transaction\n")) |
231 transaction.rollback(self.opener, self.join("journal")) | 237 transaction.rollback(self.opener, self.join("journal")) |
232 self.manifest = manifest.manifest(self.opener) | 238 self.manifest = manifest.manifest(self.opener) |
233 self.changelog = changelog.changelog(self.opener) | 239 self.changelog = changelog.changelog(self.opener) |
237 return False | 243 return False |
238 | 244 |
239 def undo(self, wlock=None): | 245 def undo(self, wlock=None): |
240 if not wlock: | 246 if not wlock: |
241 wlock = self.wlock() | 247 wlock = self.wlock() |
242 lock = self.lock() | 248 l = self.lock() |
243 if os.path.exists(self.join("undo")): | 249 if os.path.exists(self.join("undo")): |
244 self.ui.status(_("rolling back last transaction\n")) | 250 self.ui.status(_("rolling back last transaction\n")) |
245 transaction.rollback(self.opener, self.join("undo")) | 251 transaction.rollback(self.opener, self.join("undo")) |
246 util.rename(self.join("undo.dirstate"), self.join("dirstate")) | 252 util.rename(self.join("undo.dirstate"), self.join("dirstate")) |
247 self.dirstate.read() | 253 self.dirstate.read() |
248 else: | 254 else: |
249 self.ui.warn(_("no undo information available\n")) | 255 self.ui.warn(_("no undo information available\n")) |
250 | 256 |
251 def lock(self, wait=1): | 257 def do_lock(self, lockname, wait, releasefn=None, acquirefn=None): |
252 try: | 258 try: |
253 return lock.lock(self.join("lock"), 0) | 259 l = lock.lock(self.join(lockname), 0, releasefn) |
254 except lock.LockHeld, inst: | |
255 if wait: | |
256 self.ui.warn(_("waiting for lock held by %s\n") % inst.args[0]) | |
257 return lock.lock(self.join("lock"), wait) | |
258 raise inst | |
259 | |
260 def wlock(self, wait=1): | |
261 try: | |
262 wlock = lock.lock(self.join("wlock"), 0, self.dirstate.write) | |
263 except lock.LockHeld, inst: | 260 except lock.LockHeld, inst: |
264 if not wait: | 261 if not wait: |
265 raise inst | 262 raise inst |
266 self.ui.warn(_("waiting for lock held by %s\n") % inst.args[0]) | 263 self.ui.warn(_("waiting for lock held by %s\n") % inst.args[0]) |
267 wlock = lock.lock(self.join("wlock"), wait, self.dirstate.write) | 264 l = lock.lock(self.join(lockname), wait, releasefn) |
268 self.dirstate.read() | 265 if acquirefn: |
269 return wlock | 266 acquirefn() |
267 return l | |
268 | |
269 def lock(self, wait=1): | |
270 return self.do_lock("lock", wait) | |
271 | |
272 def wlock(self, wait=1): | |
273 return self.do_lock("wlock", wait, | |
274 self.dirstate.write, | |
275 self.dirstate.read) | |
276 | |
277 def checkfilemerge(self, filename, text, filelog, manifest1, manifest2): | |
278 "determine whether a new filenode is needed" | |
279 fp1 = manifest1.get(filename, nullid) | |
280 fp2 = manifest2.get(filename, nullid) | |
281 | |
282 if fp2 != nullid: | |
283 # is one parent an ancestor of the other? | |
284 fpa = filelog.ancestor(fp1, fp2) | |
285 if fpa == fp1: | |
286 fp1, fp2 = fp2, nullid | |
287 elif fpa == fp2: | |
288 fp2 = nullid | |
289 | |
290 # is the file unmodified from the parent? report existing entry | |
291 if fp2 == nullid and text == filelog.read(fp1): | |
292 return (fp1, None, None) | |
293 | |
294 return (None, fp1, fp2) | |
270 | 295 |
271 def rawcommit(self, files, text, user, date, p1=None, p2=None, wlock=None): | 296 def rawcommit(self, files, text, user, date, p1=None, p2=None, wlock=None): |
272 orig_parent = self.dirstate.parents()[0] or nullid | 297 orig_parent = self.dirstate.parents()[0] or nullid |
273 p1 = p1 or self.dirstate.parents()[0] or nullid | 298 p1 = p1 or self.dirstate.parents()[0] or nullid |
274 p2 = p2 or self.dirstate.parents()[1] or nullid | 299 p2 = p2 or self.dirstate.parents()[1] or nullid |
284 else: | 309 else: |
285 update_dirstate = 0 | 310 update_dirstate = 0 |
286 | 311 |
287 if not wlock: | 312 if not wlock: |
288 wlock = self.wlock() | 313 wlock = self.wlock() |
289 lock = self.lock() | 314 l = self.lock() |
290 tr = self.transaction() | 315 tr = self.transaction() |
291 mm = m1.copy() | 316 mm = m1.copy() |
292 mfm = mf1.copy() | 317 mfm = mf1.copy() |
293 linkrev = self.changelog.count() | 318 linkrev = self.changelog.count() |
294 for f in files: | 319 for f in files: |
296 t = self.wread(f) | 321 t = self.wread(f) |
297 tm = util.is_exec(self.wjoin(f), mfm.get(f, False)) | 322 tm = util.is_exec(self.wjoin(f), mfm.get(f, False)) |
298 r = self.file(f) | 323 r = self.file(f) |
299 mfm[f] = tm | 324 mfm[f] = tm |
300 | 325 |
301 fp1 = m1.get(f, nullid) | 326 (entry, fp1, fp2) = self.checkfilemerge(f, t, r, m1, m2) |
302 fp2 = m2.get(f, nullid) | 327 if entry: |
303 | 328 mm[f] = entry |
304 # is the same revision on two branches of a merge? | 329 continue |
305 if fp2 == fp1: | |
306 fp2 = nullid | |
307 | |
308 if fp2 != nullid: | |
309 # is one parent an ancestor of the other? | |
310 fpa = r.ancestor(fp1, fp2) | |
311 if fpa == fp1: | |
312 fp1, fp2 = fp2, nullid | |
313 elif fpa == fp2: | |
314 fp2 = nullid | |
315 | |
316 # is the file unmodified from the parent? | |
317 if t == r.read(fp1): | |
318 # record the proper existing parent in manifest | |
319 # no need to add a revision | |
320 mm[f] = fp1 | |
321 continue | |
322 | 330 |
323 mm[f] = r.add(t, {}, tr, linkrev, fp1, fp2) | 331 mm[f] = r.add(t, {}, tr, linkrev, fp1, fp2) |
324 changed.append(f) | 332 changed.append(f) |
325 if update_dirstate: | 333 if update_dirstate: |
326 self.dirstate.update([f], "n") | 334 self.dirstate.update([f], "n") |
370 | 378 |
371 if not commit and not remove and not force and p2 == nullid: | 379 if not commit and not remove and not force and p2 == nullid: |
372 self.ui.status(_("nothing changed\n")) | 380 self.ui.status(_("nothing changed\n")) |
373 return None | 381 return None |
374 | 382 |
375 if not self.hook("precommit"): | 383 xp1 = hex(p1) |
376 return None | 384 if p2 == nullid: xp2 = '' |
385 else: xp2 = hex(p2) | |
386 | |
387 self.hook("precommit", throw=True, parent1=xp1, parent2=xp2) | |
377 | 388 |
378 if not wlock: | 389 if not wlock: |
379 wlock = self.wlock() | 390 wlock = self.wlock() |
380 lock = self.lock() | 391 l = self.lock() |
381 tr = self.transaction() | 392 tr = self.transaction() |
382 | 393 |
383 # check in files | 394 # check in files |
384 new = {} | 395 new = {} |
385 linkrev = self.changelog.count() | 396 linkrev = self.changelog.count() |
401 meta["copy"] = cp | 412 meta["copy"] = cp |
402 meta["copyrev"] = hex(m1.get(cp, m2.get(cp, nullid))) | 413 meta["copyrev"] = hex(m1.get(cp, m2.get(cp, nullid))) |
403 self.ui.debug(_(" %s: copy %s:%s\n") % (f, cp, meta["copyrev"])) | 414 self.ui.debug(_(" %s: copy %s:%s\n") % (f, cp, meta["copyrev"])) |
404 fp1, fp2 = nullid, nullid | 415 fp1, fp2 = nullid, nullid |
405 else: | 416 else: |
406 fp1 = m1.get(f, nullid) | 417 entry, fp1, fp2 = self.checkfilemerge(f, t, r, m1, m2) |
407 fp2 = m2.get(f, nullid) | 418 if entry: |
408 | 419 new[f] = entry |
409 if fp2 != nullid: | |
410 # is one parent an ancestor of the other? | |
411 fpa = r.ancestor(fp1, fp2) | |
412 if fpa == fp1: | |
413 fp1, fp2 = fp2, nullid | |
414 elif fpa == fp2: | |
415 fp2 = nullid | |
416 | |
417 # is the file unmodified from the parent? | |
418 if not meta and t == r.read(fp1) and fp2 == nullid: | |
419 # record the proper existing parent in manifest | |
420 # no need to add a revision | |
421 new[f] = fp1 | |
422 continue | 420 continue |
423 | 421 |
424 new[f] = r.add(t, meta, tr, linkrev, fp1, fp2) | 422 new[f] = r.add(t, meta, tr, linkrev, fp1, fp2) |
425 # remember what we've added so that we can later calculate | 423 # remember what we've added so that we can later calculate |
426 # the files to pull from a set of changesets | 424 # the files to pull from a set of changesets |
457 return None | 455 return None |
458 text = edittext | 456 text = edittext |
459 | 457 |
460 user = user or self.ui.username() | 458 user = user or self.ui.username() |
461 n = self.changelog.add(mn, changed + remove, text, tr, p1, p2, user, date) | 459 n = self.changelog.add(mn, changed + remove, text, tr, p1, p2, user, date) |
460 self.hook('pretxncommit', throw=True, node=hex(n), parent1=xp1, | |
461 parent2=xp2) | |
462 tr.close() | 462 tr.close() |
463 | 463 |
464 self.dirstate.setparents(n) | 464 self.dirstate.setparents(n) |
465 self.dirstate.update(new, "n") | 465 self.dirstate.update(new, "n") |
466 self.dirstate.forget(remove) | 466 self.dirstate.forget(remove) |
467 | 467 |
468 if not self.hook("commit", node=hex(n)): | 468 self.hook("commit", node=hex(n), parent1=xp1, parent2=xp2) |
469 return None | |
470 return n | 469 return n |
471 | 470 |
472 def walk(self, node=None, files=[], match=util.always): | 471 def walk(self, node=None, files=[], match=util.always): |
473 if node: | 472 if node: |
474 fdict = dict.fromkeys(files) | 473 fdict = dict.fromkeys(files) |
507 # are we comparing the working directory? | 506 # are we comparing the working directory? |
508 if not node2: | 507 if not node2: |
509 if not wlock: | 508 if not wlock: |
510 try: | 509 try: |
511 wlock = self.wlock(wait=0) | 510 wlock = self.wlock(wait=0) |
512 except lock.LockHeld: | 511 except lock.LockException: |
513 wlock = None | 512 wlock = None |
514 lookup, modified, added, removed, deleted, unknown = ( | 513 lookup, modified, added, removed, deleted, unknown = ( |
515 self.dirstate.changes(files, match)) | 514 self.dirstate.changes(files, match)) |
516 | 515 |
517 # are we comparing working dir against its parent? | 516 # are we comparing working dir against its parent? |
596 for f in list: | 595 for f in list: |
597 p = self.wjoin(f) | 596 p = self.wjoin(f) |
598 if os.path.exists(p): | 597 if os.path.exists(p): |
599 self.ui.warn(_("%s still exists!\n") % f) | 598 self.ui.warn(_("%s still exists!\n") % f) |
600 elif self.dirstate.state(f) == 'a': | 599 elif self.dirstate.state(f) == 'a': |
601 self.ui.warn(_("%s never committed!\n") % f) | |
602 self.dirstate.forget([f]) | 600 self.dirstate.forget([f]) |
603 elif f not in self.dirstate: | 601 elif f not in self.dirstate: |
604 self.ui.warn(_("%s not tracked!\n") % f) | 602 self.ui.warn(_("%s not tracked!\n") % f) |
605 else: | 603 else: |
606 self.dirstate.update([f], "r") | 604 self.dirstate.update([f], "r") |
931 | 929 |
932 # this is the set of all roots we have to push | 930 # this is the set of all roots we have to push |
933 return subset | 931 return subset |
934 | 932 |
935 def pull(self, remote, heads=None): | 933 def pull(self, remote, heads=None): |
936 lock = self.lock() | 934 l = self.lock() |
937 | 935 |
938 # if we have an empty repo, fetch everything | 936 # if we have an empty repo, fetch everything |
939 if self.changelog.tip() == nullid: | 937 if self.changelog.tip() == nullid: |
940 self.ui.status(_("requesting all changes\n")) | 938 self.ui.status(_("requesting all changes\n")) |
941 fetch = [nullid] | 939 fetch = [nullid] |
945 if not fetch: | 943 if not fetch: |
946 self.ui.status(_("no changes found\n")) | 944 self.ui.status(_("no changes found\n")) |
947 return 1 | 945 return 1 |
948 | 946 |
949 if heads is None: | 947 if heads is None: |
950 cg = remote.changegroup(fetch) | 948 cg = remote.changegroup(fetch, 'pull') |
951 else: | 949 else: |
952 cg = remote.changegroupsubset(fetch, heads) | 950 cg = remote.changegroupsubset(fetch, heads, 'pull') |
953 return self.addchangegroup(cg) | 951 return self.addchangegroup(cg) |
954 | 952 |
955 def push(self, remote, force=False, revs=None): | 953 def push(self, remote, force=False, revs=None): |
956 lock = remote.lock() | 954 lock = remote.lock() |
957 | 955 |
978 self.ui.status(_("(did you forget to merge?" | 976 self.ui.status(_("(did you forget to merge?" |
979 " use push -f to force)\n")) | 977 " use push -f to force)\n")) |
980 return 1 | 978 return 1 |
981 | 979 |
982 if revs is None: | 980 if revs is None: |
983 cg = self.changegroup(update) | 981 cg = self.changegroup(update, 'push') |
984 else: | 982 else: |
985 cg = self.changegroupsubset(update, revs) | 983 cg = self.changegroupsubset(update, revs, 'push') |
986 return remote.addchangegroup(cg) | 984 return remote.addchangegroup(cg) |
987 | 985 |
988 def changegroupsubset(self, bases, heads): | 986 def changegroupsubset(self, bases, heads, source): |
989 """This function generates a changegroup consisting of all the nodes | 987 """This function generates a changegroup consisting of all the nodes |
990 that are descendents of any of the bases, and ancestors of any of | 988 that are descendents of any of the bases, and ancestors of any of |
991 the heads. | 989 the heads. |
992 | 990 |
993 It is fairly complex as determining which filenodes and which | 991 It is fairly complex as determining which filenodes and which |
994 manifest nodes need to be included for the changeset to be complete | 992 manifest nodes need to be included for the changeset to be complete |
995 is non-trivial. | 993 is non-trivial. |
996 | 994 |
997 Another wrinkle is doing the reverse, figuring out which changeset in | 995 Another wrinkle is doing the reverse, figuring out which changeset in |
998 the changegroup a particular filenode or manifestnode belongs to.""" | 996 the changegroup a particular filenode or manifestnode belongs to.""" |
997 | |
998 self.hook('preoutgoing', throw=True, source=source) | |
999 | 999 |
1000 # Set up some initial variables | 1000 # Set up some initial variables |
1001 # Make it easy to refer to self.changelog | 1001 # Make it easy to refer to self.changelog |
1002 cl = self.changelog | 1002 cl = self.changelog |
1003 # msng is short for missing - compute the list of changesets in this | 1003 # msng is short for missing - compute the list of changesets in this |
1247 # Don't need this anymore, toss it to free memory. | 1247 # Don't need this anymore, toss it to free memory. |
1248 del msng_filenode_set[fname] | 1248 del msng_filenode_set[fname] |
1249 # Signal that no more groups are left. | 1249 # Signal that no more groups are left. |
1250 yield struct.pack(">l", 0) | 1250 yield struct.pack(">l", 0) |
1251 | 1251 |
1252 self.hook('outgoing', node=hex(msng_cl_lst[0]), source=source) | |
1253 | |
1252 return util.chunkbuffer(gengroup()) | 1254 return util.chunkbuffer(gengroup()) |
1253 | 1255 |
1254 def changegroup(self, basenodes): | 1256 def changegroup(self, basenodes, source): |
1255 """Generate a changegroup of all nodes that we have that a recipient | 1257 """Generate a changegroup of all nodes that we have that a recipient |
1256 doesn't. | 1258 doesn't. |
1257 | 1259 |
1258 This is much easier than the previous function as we can assume that | 1260 This is much easier than the previous function as we can assume that |
1259 the recipient has any changenode we aren't sending them.""" | 1261 the recipient has any changenode we aren't sending them.""" |
1262 | |
1263 self.hook('preoutgoing', throw=True, source=source) | |
1264 | |
1260 cl = self.changelog | 1265 cl = self.changelog |
1261 nodes = cl.nodesbetween(basenodes, None)[0] | 1266 nodes = cl.nodesbetween(basenodes, None)[0] |
1262 revset = dict.fromkeys([cl.rev(n) for n in nodes]) | 1267 revset = dict.fromkeys([cl.rev(n) for n in nodes]) |
1263 | 1268 |
1264 def identity(x): | 1269 def identity(x): |
1306 lookup = lookuprevlink_func(filerevlog) | 1311 lookup = lookuprevlink_func(filerevlog) |
1307 for chnk in filerevlog.group(nodeiter, lookup): | 1312 for chnk in filerevlog.group(nodeiter, lookup): |
1308 yield chnk | 1313 yield chnk |
1309 | 1314 |
1310 yield struct.pack(">l", 0) | 1315 yield struct.pack(">l", 0) |
1316 self.hook('outgoing', node=hex(nodes[0]), source=source) | |
1311 | 1317 |
1312 return util.chunkbuffer(gengroup()) | 1318 return util.chunkbuffer(gengroup()) |
1313 | 1319 |
1314 def addchangegroup(self, source): | 1320 def addchangegroup(self, source): |
1315 | 1321 |
1341 def revmap(x): | 1347 def revmap(x): |
1342 return self.changelog.rev(x) | 1348 return self.changelog.rev(x) |
1343 | 1349 |
1344 if not source: | 1350 if not source: |
1345 return | 1351 return |
1352 | |
1353 self.hook('prechangegroup', throw=True) | |
1354 | |
1346 changesets = files = revisions = 0 | 1355 changesets = files = revisions = 0 |
1347 | 1356 |
1348 tr = self.transaction() | 1357 tr = self.transaction() |
1349 | 1358 |
1350 oldheads = len(self.changelog.heads()) | 1359 oldheads = len(self.changelog.heads()) |
1383 | 1392 |
1384 self.ui.status(_("added %d changesets" | 1393 self.ui.status(_("added %d changesets" |
1385 " with %d changes to %d files%s\n") | 1394 " with %d changes to %d files%s\n") |
1386 % (changesets, revisions, files, heads)) | 1395 % (changesets, revisions, files, heads)) |
1387 | 1396 |
1397 self.hook('pretxnchangegroup', throw=True, | |
1398 node=hex(self.changelog.node(cor+1))) | |
1399 | |
1388 tr.close() | 1400 tr.close() |
1389 | 1401 |
1390 if changesets > 0: | 1402 if changesets > 0: |
1391 if not self.hook("changegroup", | 1403 self.hook("changegroup", node=hex(self.changelog.node(cor+1))) |
1392 node=hex(self.changelog.node(cor+1))): | |
1393 self.ui.warn(_("abort: changegroup hook returned failure!\n")) | |
1394 return 1 | |
1395 | 1404 |
1396 for i in range(cor + 1, cnr + 1): | 1405 for i in range(cor + 1, cnr + 1): |
1397 self.hook("incoming", node=hex(self.changelog.node(i))) | 1406 self.hook("incoming", node=hex(self.changelog.node(i))) |
1398 | |
1399 return | |
1400 | 1407 |
1401 def update(self, node, allow=False, force=False, choose=None, | 1408 def update(self, node, allow=False, force=False, choose=None, |
1402 moddirstate=True, forcemerge=False, wlock=None): | 1409 moddirstate=True, forcemerge=False, wlock=None): |
1403 pl = self.dirstate.parents() | 1410 pl = self.dirstate.parents() |
1404 if not force and pl[1] != nullid: | 1411 if not force and pl[1] != nullid: |