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"): |
372 |
378 |
373 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: |
374 self.ui.status(_("nothing changed\n")) |
380 self.ui.status(_("nothing changed\n")) |
375 return None |
381 return None |
376 |
382 |
377 if not self.hook("precommit"): |
383 xp1 = hex(p1) |
378 return None |
384 if p2 == nullid: xp2 = '' |
|
385 else: xp2 = hex(p2) |
|
386 |
|
387 self.hook("precommit", throw=True, parent1=xp1, parent2=xp2) |
379 |
388 |
380 if not wlock: |
389 if not wlock: |
381 wlock = self.wlock() |
390 wlock = self.wlock() |
382 lock = self.lock() |
391 lock = self.lock() |
383 tr = self.transaction() |
392 tr = self.transaction() |
446 return None |
455 return None |
447 text = edittext |
456 text = edittext |
448 |
457 |
449 user = user or self.ui.username() |
458 user = user or self.ui.username() |
450 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) |
451 tr.close() |
462 tr.close() |
452 |
463 |
453 self.dirstate.setparents(n) |
464 self.dirstate.setparents(n) |
454 self.dirstate.update(new, "n") |
465 self.dirstate.update(new, "n") |
455 self.dirstate.forget(remove) |
466 self.dirstate.forget(remove) |
456 |
467 |
457 if not self.hook("commit", node=hex(n)): |
468 self.hook("commit", node=hex(n), parent1=xp1, parent2=xp2) |
458 return None |
|
459 return n |
469 return n |
460 |
470 |
461 def walk(self, node=None, files=[], match=util.always): |
471 def walk(self, node=None, files=[], match=util.always): |
462 if node: |
472 if node: |
463 fdict = dict.fromkeys(files) |
473 fdict = dict.fromkeys(files) |
934 if not fetch: |
944 if not fetch: |
935 self.ui.status(_("no changes found\n")) |
945 self.ui.status(_("no changes found\n")) |
936 return 1 |
946 return 1 |
937 |
947 |
938 if heads is None: |
948 if heads is None: |
939 cg = remote.changegroup(fetch) |
949 cg = remote.changegroup(fetch, 'pull') |
940 else: |
950 else: |
941 cg = remote.changegroupsubset(fetch, heads) |
951 cg = remote.changegroupsubset(fetch, heads, 'pull') |
942 return self.addchangegroup(cg) |
952 return self.addchangegroup(cg) |
943 |
953 |
944 def push(self, remote, force=False): |
954 def push(self, remote, force=False): |
945 lock = remote.lock() |
955 lock = remote.lock() |
946 |
956 |
961 self.ui.warn(_("abort: push creates new remote branches!\n")) |
971 self.ui.warn(_("abort: push creates new remote branches!\n")) |
962 self.ui.status(_("(did you forget to merge?" |
972 self.ui.status(_("(did you forget to merge?" |
963 " use push -f to force)\n")) |
973 " use push -f to force)\n")) |
964 return 1 |
974 return 1 |
965 |
975 |
966 cg = self.changegroup(update) |
976 cg = self.changegroup(update, 'push') |
967 return remote.addchangegroup(cg) |
977 return remote.addchangegroup(cg) |
968 |
978 |
969 def changegroupsubset(self, bases, heads): |
979 def changegroupsubset(self, bases, heads, source): |
970 """This function generates a changegroup consisting of all the nodes |
980 """This function generates a changegroup consisting of all the nodes |
971 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 |
972 the heads. |
982 the heads. |
973 |
983 |
974 It is fairly complex as determining which filenodes and which |
984 It is fairly complex as determining which filenodes and which |
975 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 |
976 is non-trivial. |
986 is non-trivial. |
977 |
987 |
978 Another wrinkle is doing the reverse, figuring out which changeset in |
988 Another wrinkle is doing the reverse, figuring out which changeset in |
979 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) |
980 |
992 |
981 # Set up some initial variables |
993 # Set up some initial variables |
982 # Make it easy to refer to self.changelog |
994 # Make it easy to refer to self.changelog |
983 cl = self.changelog |
995 cl = self.changelog |
984 # 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 |
1228 # Don't need this anymore, toss it to free memory. |
1240 # Don't need this anymore, toss it to free memory. |
1229 del msng_filenode_set[fname] |
1241 del msng_filenode_set[fname] |
1230 # Signal that no more groups are left. |
1242 # Signal that no more groups are left. |
1231 yield struct.pack(">l", 0) |
1243 yield struct.pack(">l", 0) |
1232 |
1244 |
|
1245 self.hook('outgoing', node=hex(msng_cl_lst[0]), source=source) |
|
1246 |
1233 return util.chunkbuffer(gengroup()) |
1247 return util.chunkbuffer(gengroup()) |
1234 |
1248 |
1235 def changegroup(self, basenodes): |
1249 def changegroup(self, basenodes, source): |
1236 """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 |
1237 doesn't. |
1251 doesn't. |
1238 |
1252 |
1239 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 |
1240 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 |
1241 cl = self.changelog |
1258 cl = self.changelog |
1242 nodes = cl.nodesbetween(basenodes, None)[0] |
1259 nodes = cl.nodesbetween(basenodes, None)[0] |
1243 revset = dict.fromkeys([cl.rev(n) for n in nodes]) |
1260 revset = dict.fromkeys([cl.rev(n) for n in nodes]) |
1244 |
1261 |
1245 def identity(x): |
1262 def identity(x): |
1287 lookup = lookuprevlink_func(filerevlog) |
1304 lookup = lookuprevlink_func(filerevlog) |
1288 for chnk in filerevlog.group(nodeiter, lookup): |
1305 for chnk in filerevlog.group(nodeiter, lookup): |
1289 yield chnk |
1306 yield chnk |
1290 |
1307 |
1291 yield struct.pack(">l", 0) |
1308 yield struct.pack(">l", 0) |
|
1309 self.hook('outgoing', node=hex(nodes[0]), source=source) |
1292 |
1310 |
1293 return util.chunkbuffer(gengroup()) |
1311 return util.chunkbuffer(gengroup()) |
1294 |
1312 |
1295 def addchangegroup(self, source): |
1313 def addchangegroup(self, source): |
1296 |
1314 |
1364 |
1385 |
1365 self.ui.status(_("added %d changesets" |
1386 self.ui.status(_("added %d changesets" |
1366 " with %d changes to %d files%s\n") |
1387 " with %d changes to %d files%s\n") |
1367 % (changesets, revisions, files, heads)) |
1388 % (changesets, revisions, files, heads)) |
1368 |
1389 |
|
1390 self.hook('pretxnchangegroup', throw=True, |
|
1391 node=hex(self.changelog.node(cor+1))) |
|
1392 |
1369 tr.close() |
1393 tr.close() |
1370 |
1394 |
1371 if changesets > 0: |
1395 if changesets > 0: |
1372 if not self.hook("changegroup", |
1396 self.hook("changegroup", node=hex(self.changelog.node(cor+1))) |
1373 node=hex(self.changelog.node(cor+1))): |
|
1374 self.ui.warn(_("abort: changegroup hook returned failure!\n")) |
|
1375 return 1 |
|
1376 |
1397 |
1377 for i in range(cor + 1, cnr + 1): |
1398 for i in range(cor + 1, cnr + 1): |
1378 self.hook("incoming", node=hex(self.changelog.node(i))) |
1399 self.hook("incoming", node=hex(self.changelog.node(i))) |
1379 |
|
1380 return |
|
1381 |
1400 |
1382 def update(self, node, allow=False, force=False, choose=None, |
1401 def update(self, node, allow=False, force=False, choose=None, |
1383 moddirstate=True, forcemerge=False, wlock=None): |
1402 moddirstate=True, forcemerge=False, wlock=None): |
1384 pl = self.dirstate.parents() |
1403 pl = self.dirstate.parents() |
1385 if not force and pl[1] != nullid: |
1404 if not force and pl[1] != nullid: |