comparison mercurial/localrepo.py @ 1779:a1e6e02e9d05

Merge with mpm
author Josef "Jeff" Sipek <jeffpc@optonline.net>
date Sat, 18 Feb 2006 22:24:42 -0500
parents 2c9872a4f3fd
children 91c56c427171
comparison
equal deleted inserted replaced
1778:b08b87cecc37 1779:a1e6e02e9d05
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"):
266 self.ui.warn(_("waiting for lock held by %s\n") % inst.args[0]) 272 self.ui.warn(_("waiting for lock held by %s\n") % inst.args[0])
267 wlock = lock.lock(self.join("wlock"), wait, self.dirstate.write) 273 wlock = lock.lock(self.join("wlock"), wait, self.dirstate.write)
268 self.dirstate.read() 274 self.dirstate.read()
269 return wlock 275 return wlock
270 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)
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
275 c1 = self.changelog.read(p1) 300 c1 = self.changelog.read(p1)
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 lock = self.lock()
381 tr = self.transaction() 392 tr = self.transaction()
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)
945 if not fetch: 944 if not fetch:
946 self.ui.status(_("no changes found\n")) 945 self.ui.status(_("no changes found\n"))
947 return 1 946 return 1
948 947
949 if heads is None: 948 if heads is None:
950 cg = remote.changegroup(fetch) 949 cg = remote.changegroup(fetch, 'pull')
951 else: 950 else:
952 cg = remote.changegroupsubset(fetch, heads) 951 cg = remote.changegroupsubset(fetch, heads, 'pull')
953 return self.addchangegroup(cg) 952 return self.addchangegroup(cg)
954 953
955 def push(self, remote, force=False): 954 def push(self, remote, force=False):
956 lock = remote.lock() 955 lock = remote.lock()
957 956
972 self.ui.warn(_("abort: push creates new remote branches!\n")) 971 self.ui.warn(_("abort: push creates new remote branches!\n"))
973 self.ui.status(_("(did you forget to merge?" 972 self.ui.status(_("(did you forget to merge?"
974 " use push -f to force)\n")) 973 " use push -f to force)\n"))
975 return 1 974 return 1
976 975
977 cg = self.changegroup(update) 976 cg = self.changegroup(update, 'push')
978 return remote.addchangegroup(cg) 977 return remote.addchangegroup(cg)
979 978
980 def changegroupsubset(self, bases, heads): 979 def changegroupsubset(self, bases, heads, source):
981 """This function generates a changegroup consisting of all the nodes 980 """This function generates a changegroup consisting of all the nodes
982 that are descendents of any of the bases, and ancestors of any of 981 that are descendents of any of the bases, and ancestors of any of
983 the heads. 982 the heads.
984 983
985 It is fairly complex as determining which filenodes and which 984 It is fairly complex as determining which filenodes and which
986 manifest nodes need to be included for the changeset to be complete 985 manifest nodes need to be included for the changeset to be complete
987 is non-trivial. 986 is non-trivial.
988 987
989 Another wrinkle is doing the reverse, figuring out which changeset in 988 Another wrinkle is doing the reverse, figuring out which changeset in
990 the changegroup a particular filenode or manifestnode belongs to.""" 989 the changegroup a particular filenode or manifestnode belongs to."""
990
991 self.hook('preoutgoing', throw=True, source=source)
991 992
992 # Set up some initial variables 993 # Set up some initial variables
993 # Make it easy to refer to self.changelog 994 # Make it easy to refer to self.changelog
994 cl = self.changelog 995 cl = self.changelog
995 # msng is short for missing - compute the list of changesets in this 996 # msng is short for missing - compute the list of changesets in this
1239 # Don't need this anymore, toss it to free memory. 1240 # Don't need this anymore, toss it to free memory.
1240 del msng_filenode_set[fname] 1241 del msng_filenode_set[fname]
1241 # Signal that no more groups are left. 1242 # Signal that no more groups are left.
1242 yield struct.pack(">l", 0) 1243 yield struct.pack(">l", 0)
1243 1244
1245 self.hook('outgoing', node=hex(msng_cl_lst[0]), source=source)
1246
1244 return util.chunkbuffer(gengroup()) 1247 return util.chunkbuffer(gengroup())
1245 1248
1246 def changegroup(self, basenodes): 1249 def changegroup(self, basenodes, source):
1247 """Generate a changegroup of all nodes that we have that a recipient 1250 """Generate a changegroup of all nodes that we have that a recipient
1248 doesn't. 1251 doesn't.
1249 1252
1250 This is much easier than the previous function as we can assume that 1253 This is much easier than the previous function as we can assume that
1251 the recipient has any changenode we aren't sending them.""" 1254 the recipient has any changenode we aren't sending them."""
1255
1256 self.hook('preoutgoing', throw=True, source=source)
1257
1252 cl = self.changelog 1258 cl = self.changelog
1253 nodes = cl.nodesbetween(basenodes, None)[0] 1259 nodes = cl.nodesbetween(basenodes, None)[0]
1254 revset = dict.fromkeys([cl.rev(n) for n in nodes]) 1260 revset = dict.fromkeys([cl.rev(n) for n in nodes])
1255 1261
1256 def identity(x): 1262 def identity(x):
1298 lookup = lookuprevlink_func(filerevlog) 1304 lookup = lookuprevlink_func(filerevlog)
1299 for chnk in filerevlog.group(nodeiter, lookup): 1305 for chnk in filerevlog.group(nodeiter, lookup):
1300 yield chnk 1306 yield chnk
1301 1307
1302 yield struct.pack(">l", 0) 1308 yield struct.pack(">l", 0)
1309 self.hook('outgoing', node=hex(nodes[0]), source=source)
1303 1310
1304 return util.chunkbuffer(gengroup()) 1311 return util.chunkbuffer(gengroup())
1305 1312
1306 def addchangegroup(self, source): 1313 def addchangegroup(self, source):
1307 1314
1333 def revmap(x): 1340 def revmap(x):
1334 return self.changelog.rev(x) 1341 return self.changelog.rev(x)
1335 1342
1336 if not source: 1343 if not source:
1337 return 1344 return
1345
1346 self.hook('prechangegroup', throw=True)
1347
1338 changesets = files = revisions = 0 1348 changesets = files = revisions = 0
1339 1349
1340 tr = self.transaction() 1350 tr = self.transaction()
1341 1351
1342 oldheads = len(self.changelog.heads()) 1352 oldheads = len(self.changelog.heads())
1375 1385
1376 self.ui.status(_("added %d changesets" 1386 self.ui.status(_("added %d changesets"
1377 " with %d changes to %d files%s\n") 1387 " with %d changes to %d files%s\n")
1378 % (changesets, revisions, files, heads)) 1388 % (changesets, revisions, files, heads))
1379 1389
1390 self.hook('pretxnchangegroup', throw=True,
1391 node=hex(self.changelog.node(cor+1)))
1392
1380 tr.close() 1393 tr.close()
1381 1394
1382 if changesets > 0: 1395 if changesets > 0:
1383 if not self.hook("changegroup", 1396 self.hook("changegroup", node=hex(self.changelog.node(cor+1)))
1384 node=hex(self.changelog.node(cor+1))):
1385 self.ui.warn(_("abort: changegroup hook returned failure!\n"))
1386 return 1
1387 1397
1388 for i in range(cor + 1, cnr + 1): 1398 for i in range(cor + 1, cnr + 1):
1389 self.hook("incoming", node=hex(self.changelog.node(i))) 1399 self.hook("incoming", node=hex(self.changelog.node(i)))
1390
1391 return
1392 1400
1393 def update(self, node, allow=False, force=False, choose=None, 1401 def update(self, node, allow=False, force=False, choose=None,
1394 moddirstate=True, forcemerge=False, wlock=None): 1402 moddirstate=True, forcemerge=False, wlock=None):
1395 pl = self.dirstate.parents() 1403 pl = self.dirstate.parents()
1396 if not force and pl[1] != nullid: 1404 if not force and pl[1] != nullid: