8 from node import * |
8 from node import * |
9 from i18n import _ |
9 from i18n import _ |
10 import repo, changegroup |
10 import repo, changegroup |
11 import changelog, dirstate, filelog, manifest, context |
11 import changelog, dirstate, filelog, manifest, context |
12 import re, lock, transaction, tempfile, stat, mdiff, errno, ui |
12 import re, lock, transaction, tempfile, stat, mdiff, errno, ui |
13 import os, revlog, time, util, extensions |
13 import os, revlog, time, util, extensions, hook |
14 |
14 |
15 class localrepository(repo.repository): |
15 class localrepository(repo.repository): |
16 capabilities = ('lookup', 'changegroupsubset') |
16 capabilities = ('lookup', 'changegroupsubset') |
17 supported = ('revlogv1', 'store') |
17 supported = ('revlogv1', 'store') |
18 |
18 |
103 |
103 |
104 def url(self): |
104 def url(self): |
105 return 'file:' + self.root |
105 return 'file:' + self.root |
106 |
106 |
107 def hook(self, name, throw=False, **args): |
107 def hook(self, name, throw=False, **args): |
108 def callhook(hname, funcname): |
108 return hook.hook(self.ui, self, name, throw, **args) |
109 '''call python hook. hook is callable object, looked up as |
|
110 name in python module. if callable returns "true", hook |
|
111 fails, else passes. if hook raises exception, treated as |
|
112 hook failure. exception propagates if throw is "true". |
|
113 |
|
114 reason for "true" meaning "hook failed" is so that |
|
115 unmodified commands (e.g. mercurial.commands.update) can |
|
116 be run as hooks without wrappers to convert return values.''' |
|
117 |
|
118 self.ui.note(_("calling hook %s: %s\n") % (hname, funcname)) |
|
119 obj = funcname |
|
120 if not callable(obj): |
|
121 d = funcname.rfind('.') |
|
122 if d == -1: |
|
123 raise util.Abort(_('%s hook is invalid ("%s" not in ' |
|
124 'a module)') % (hname, funcname)) |
|
125 modname = funcname[:d] |
|
126 try: |
|
127 obj = __import__(modname) |
|
128 except ImportError: |
|
129 try: |
|
130 # extensions are loaded with hgext_ prefix |
|
131 obj = __import__("hgext_%s" % modname) |
|
132 except ImportError: |
|
133 raise util.Abort(_('%s hook is invalid ' |
|
134 '(import of "%s" failed)') % |
|
135 (hname, modname)) |
|
136 try: |
|
137 for p in funcname.split('.')[1:]: |
|
138 obj = getattr(obj, p) |
|
139 except AttributeError, err: |
|
140 raise util.Abort(_('%s hook is invalid ' |
|
141 '("%s" is not defined)') % |
|
142 (hname, funcname)) |
|
143 if not callable(obj): |
|
144 raise util.Abort(_('%s hook is invalid ' |
|
145 '("%s" is not callable)') % |
|
146 (hname, funcname)) |
|
147 try: |
|
148 r = obj(ui=self.ui, repo=self, hooktype=name, **args) |
|
149 except (KeyboardInterrupt, util.SignalInterrupt): |
|
150 raise |
|
151 except Exception, exc: |
|
152 if isinstance(exc, util.Abort): |
|
153 self.ui.warn(_('error: %s hook failed: %s\n') % |
|
154 (hname, exc.args[0])) |
|
155 else: |
|
156 self.ui.warn(_('error: %s hook raised an exception: ' |
|
157 '%s\n') % (hname, exc)) |
|
158 if throw: |
|
159 raise |
|
160 self.ui.print_exc() |
|
161 return True |
|
162 if r: |
|
163 if throw: |
|
164 raise util.Abort(_('%s hook failed') % hname) |
|
165 self.ui.warn(_('warning: %s hook failed\n') % hname) |
|
166 return r |
|
167 |
|
168 def runhook(name, cmd): |
|
169 self.ui.note(_("running hook %s: %s\n") % (name, cmd)) |
|
170 env = dict([('HG_' + k.upper(), v) for k, v in args.iteritems()]) |
|
171 r = util.system(cmd, environ=env, cwd=self.root) |
|
172 if r: |
|
173 desc, r = util.explain_exit(r) |
|
174 if throw: |
|
175 raise util.Abort(_('%s hook %s') % (name, desc)) |
|
176 self.ui.warn(_('warning: %s hook %s\n') % (name, desc)) |
|
177 return r |
|
178 |
|
179 r = False |
|
180 hooks = [(hname, cmd) for hname, cmd in self.ui.configitems("hooks") |
|
181 if hname.split(".", 1)[0] == name and cmd] |
|
182 hooks.sort() |
|
183 for hname, cmd in hooks: |
|
184 if callable(cmd): |
|
185 r = callhook(hname, cmd) or r |
|
186 elif cmd.startswith('python:'): |
|
187 r = callhook(hname, cmd[7:].strip()) or r |
|
188 else: |
|
189 r = runhook(hname, cmd) or r |
|
190 return r |
|
191 |
109 |
192 tag_disallowed = ':\r\n' |
110 tag_disallowed = ':\r\n' |
193 |
111 |
194 def _tag(self, name, node, message, local, user, date, parent=None): |
112 def _tag(self, name, node, message, local, user, date, parent=None): |
195 use_dirstate = parent is None |
113 use_dirstate = parent is None |