##// END OF EJS Templates
py3: add a __str__ method to Abort...
Denis Laxalde -
r43720:40bf3d7e stable
parent child Browse files
Show More
@@ -1,430 +1,433 b''
1 1 # error.py - Mercurial exceptions
2 2 #
3 3 # Copyright 2005-2008 Matt Mackall <mpm@selenic.com>
4 4 #
5 5 # This software may be used and distributed according to the terms of the
6 6 # GNU General Public License version 2 or any later version.
7 7
8 8 """Mercurial exceptions.
9 9
10 10 This allows us to catch exceptions at higher levels without forcing
11 11 imports.
12 12 """
13 13
14 14 from __future__ import absolute_import
15 15
16 16 # Do not import anything but pycompat here, please
17 17 from . import pycompat
18 18
19 19
20 20 def _tobytes(exc):
21 21 """Byte-stringify exception in the same way as BaseException_str()"""
22 22 if not exc.args:
23 23 return b''
24 24 if len(exc.args) == 1:
25 25 return pycompat.bytestr(exc.args[0])
26 26 return b'(%s)' % b', '.join(b"'%s'" % pycompat.bytestr(a) for a in exc.args)
27 27
28 28
29 29 class Hint(object):
30 30 """Mix-in to provide a hint of an error
31 31
32 32 This should come first in the inheritance list to consume a hint and
33 33 pass remaining arguments to the exception class.
34 34 """
35 35
36 36 def __init__(self, *args, **kw):
37 37 self.hint = kw.pop(r'hint', None)
38 38 super(Hint, self).__init__(*args, **kw)
39 39
40 40
41 41 class StorageError(Hint, Exception):
42 42 """Raised when an error occurs in a storage layer.
43 43
44 44 Usually subclassed by a storage-specific exception.
45 45 """
46 46
47 47 __bytes__ = _tobytes
48 48
49 49
50 50 class RevlogError(StorageError):
51 51 __bytes__ = _tobytes
52 52
53 53
54 54 class SidedataHashError(RevlogError):
55 55 def __init__(self, key, expected, got):
56 56 self.sidedatakey = key
57 57 self.expecteddigest = expected
58 58 self.actualdigest = got
59 59
60 60
61 61 class FilteredIndexError(IndexError):
62 62 __bytes__ = _tobytes
63 63
64 64
65 65 class LookupError(RevlogError, KeyError):
66 66 def __init__(self, name, index, message):
67 67 self.name = name
68 68 self.index = index
69 69 # this can't be called 'message' because at least some installs of
70 70 # Python 2.6+ complain about the 'message' property being deprecated
71 71 self.lookupmessage = message
72 72 if isinstance(name, bytes) and len(name) == 20:
73 73 from .node import short
74 74
75 75 name = short(name)
76 76 RevlogError.__init__(self, b'%s@%s: %s' % (index, name, message))
77 77
78 78 def __bytes__(self):
79 79 return RevlogError.__bytes__(self)
80 80
81 81 def __str__(self):
82 82 return RevlogError.__str__(self)
83 83
84 84
85 85 class AmbiguousPrefixLookupError(LookupError):
86 86 pass
87 87
88 88
89 89 class FilteredLookupError(LookupError):
90 90 pass
91 91
92 92
93 93 class ManifestLookupError(LookupError):
94 94 pass
95 95
96 96
97 97 class CommandError(Exception):
98 98 """Exception raised on errors in parsing the command line."""
99 99
100 100 __bytes__ = _tobytes
101 101
102 102
103 103 class InterventionRequired(Hint, Exception):
104 104 """Exception raised when a command requires human intervention."""
105 105
106 106 __bytes__ = _tobytes
107 107
108 108
109 109 class Abort(Hint, Exception):
110 110 """Raised if a command needs to print an error and exit."""
111 111
112 112 __bytes__ = _tobytes
113 113
114 def __str__(self):
115 return pycompat.sysstr(self.__bytes__())
116
114 117
115 118 class HookLoadError(Abort):
116 119 """raised when loading a hook fails, aborting an operation
117 120
118 121 Exists to allow more specialized catching."""
119 122
120 123
121 124 class HookAbort(Abort):
122 125 """raised when a validation hook fails, aborting an operation
123 126
124 127 Exists to allow more specialized catching."""
125 128
126 129
127 130 class ConfigError(Abort):
128 131 """Exception raised when parsing config files"""
129 132
130 133
131 134 class UpdateAbort(Abort):
132 135 """Raised when an update is aborted for destination issue"""
133 136
134 137
135 138 class MergeDestAbort(Abort):
136 139 """Raised when an update is aborted for destination issues"""
137 140
138 141
139 142 class NoMergeDestAbort(MergeDestAbort):
140 143 """Raised when an update is aborted because there is nothing to merge"""
141 144
142 145
143 146 class ManyMergeDestAbort(MergeDestAbort):
144 147 """Raised when an update is aborted because destination is ambiguous"""
145 148
146 149
147 150 class ResponseExpected(Abort):
148 151 """Raised when an EOF is received for a prompt"""
149 152
150 153 def __init__(self):
151 154 from .i18n import _
152 155
153 156 Abort.__init__(self, _(b'response expected'))
154 157
155 158
156 159 class OutOfBandError(Hint, Exception):
157 160 """Exception raised when a remote repo reports failure"""
158 161
159 162 __bytes__ = _tobytes
160 163
161 164
162 165 class ParseError(Hint, Exception):
163 166 """Raised when parsing config files and {rev,file}sets (msg[, pos])"""
164 167
165 168 __bytes__ = _tobytes
166 169
167 170
168 171 class PatchError(Exception):
169 172 __bytes__ = _tobytes
170 173
171 174
172 175 class UnknownIdentifier(ParseError):
173 176 """Exception raised when a {rev,file}set references an unknown identifier"""
174 177
175 178 def __init__(self, function, symbols):
176 179 from .i18n import _
177 180
178 181 ParseError.__init__(self, _(b"unknown identifier: %s") % function)
179 182 self.function = function
180 183 self.symbols = symbols
181 184
182 185
183 186 class RepoError(Hint, Exception):
184 187 __bytes__ = _tobytes
185 188
186 189
187 190 class RepoLookupError(RepoError):
188 191 pass
189 192
190 193
191 194 class FilteredRepoLookupError(RepoLookupError):
192 195 pass
193 196
194 197
195 198 class CapabilityError(RepoError):
196 199 pass
197 200
198 201
199 202 class RequirementError(RepoError):
200 203 """Exception raised if .hg/requires has an unknown entry."""
201 204
202 205
203 206 class StdioError(IOError):
204 207 """Raised if I/O to stdout or stderr fails"""
205 208
206 209 def __init__(self, err):
207 210 IOError.__init__(self, err.errno, err.strerror)
208 211
209 212 # no __bytes__() because error message is derived from the standard IOError
210 213
211 214
212 215 class UnsupportedMergeRecords(Abort):
213 216 def __init__(self, recordtypes):
214 217 from .i18n import _
215 218
216 219 self.recordtypes = sorted(recordtypes)
217 220 s = b' '.join(self.recordtypes)
218 221 Abort.__init__(
219 222 self,
220 223 _(b'unsupported merge state records: %s') % s,
221 224 hint=_(
222 225 b'see https://mercurial-scm.org/wiki/MergeStateRecords for '
223 226 b'more information'
224 227 ),
225 228 )
226 229
227 230
228 231 class UnknownVersion(Abort):
229 232 """generic exception for aborting from an encounter with an unknown version
230 233 """
231 234
232 235 def __init__(self, msg, hint=None, version=None):
233 236 self.version = version
234 237 super(UnknownVersion, self).__init__(msg, hint=hint)
235 238
236 239
237 240 class LockError(IOError):
238 241 def __init__(self, errno, strerror, filename, desc):
239 242 IOError.__init__(self, errno, strerror, filename)
240 243 self.desc = desc
241 244
242 245 # no __bytes__() because error message is derived from the standard IOError
243 246
244 247
245 248 class LockHeld(LockError):
246 249 def __init__(self, errno, filename, desc, locker):
247 250 LockError.__init__(self, errno, b'Lock held', filename, desc)
248 251 self.locker = locker
249 252
250 253
251 254 class LockUnavailable(LockError):
252 255 pass
253 256
254 257
255 258 # LockError is for errors while acquiring the lock -- this is unrelated
256 259 class LockInheritanceContractViolation(RuntimeError):
257 260 __bytes__ = _tobytes
258 261
259 262
260 263 class ResponseError(Exception):
261 264 """Raised to print an error with part of output and exit."""
262 265
263 266 __bytes__ = _tobytes
264 267
265 268
266 269 class UnknownCommand(Exception):
267 270 """Exception raised if command is not in the command table."""
268 271
269 272 __bytes__ = _tobytes
270 273
271 274
272 275 class AmbiguousCommand(Exception):
273 276 """Exception raised if command shortcut matches more than one command."""
274 277
275 278 __bytes__ = _tobytes
276 279
277 280
278 281 # derived from KeyboardInterrupt to simplify some breakout code
279 282 class SignalInterrupt(KeyboardInterrupt):
280 283 """Exception raised on SIGTERM and SIGHUP."""
281 284
282 285
283 286 class SignatureError(Exception):
284 287 __bytes__ = _tobytes
285 288
286 289
287 290 class PushRaced(RuntimeError):
288 291 """An exception raised during unbundling that indicate a push race"""
289 292
290 293 __bytes__ = _tobytes
291 294
292 295
293 296 class ProgrammingError(Hint, RuntimeError):
294 297 """Raised if a mercurial (core or extension) developer made a mistake"""
295 298
296 299 def __init__(self, msg, *args, **kwargs):
297 300 # On Python 3, turn the message back into a string since this is
298 301 # an internal-only error that won't be printed except in a
299 302 # stack traces.
300 303 msg = pycompat.sysstr(msg)
301 304 super(ProgrammingError, self).__init__(msg, *args, **kwargs)
302 305
303 306 __bytes__ = _tobytes
304 307
305 308
306 309 class WdirUnsupported(Exception):
307 310 """An exception which is raised when 'wdir()' is not supported"""
308 311
309 312 __bytes__ = _tobytes
310 313
311 314
312 315 # bundle2 related errors
313 316 class BundleValueError(ValueError):
314 317 """error raised when bundle2 cannot be processed"""
315 318
316 319 __bytes__ = _tobytes
317 320
318 321
319 322 class BundleUnknownFeatureError(BundleValueError):
320 323 def __init__(self, parttype=None, params=(), values=()):
321 324 self.parttype = parttype
322 325 self.params = params
323 326 self.values = values
324 327 if self.parttype is None:
325 328 msg = b'Stream Parameter'
326 329 else:
327 330 msg = parttype
328 331 entries = self.params
329 332 if self.params and self.values:
330 333 assert len(self.params) == len(self.values)
331 334 entries = []
332 335 for idx, par in enumerate(self.params):
333 336 val = self.values[idx]
334 337 if val is None:
335 338 entries.append(val)
336 339 else:
337 340 entries.append(b"%s=%r" % (par, pycompat.maybebytestr(val)))
338 341 if entries:
339 342 msg = b'%s - %s' % (msg, b', '.join(entries))
340 343 ValueError.__init__(self, msg)
341 344
342 345
343 346 class ReadOnlyPartError(RuntimeError):
344 347 """error raised when code tries to alter a part being generated"""
345 348
346 349 __bytes__ = _tobytes
347 350
348 351
349 352 class PushkeyFailed(Abort):
350 353 """error raised when a pushkey part failed to update a value"""
351 354
352 355 def __init__(
353 356 self, partid, namespace=None, key=None, new=None, old=None, ret=None
354 357 ):
355 358 self.partid = partid
356 359 self.namespace = namespace
357 360 self.key = key
358 361 self.new = new
359 362 self.old = old
360 363 self.ret = ret
361 364 # no i18n expected to be processed into a better message
362 365 Abort.__init__(
363 366 self, b'failed to update value for "%s/%s"' % (namespace, key)
364 367 )
365 368
366 369
367 370 class CensoredNodeError(StorageError):
368 371 """error raised when content verification fails on a censored node
369 372
370 373 Also contains the tombstone data substituted for the uncensored data.
371 374 """
372 375
373 376 def __init__(self, filename, node, tombstone):
374 377 from .node import short
375 378
376 379 StorageError.__init__(self, b'%s:%s' % (filename, short(node)))
377 380 self.tombstone = tombstone
378 381
379 382
380 383 class CensoredBaseError(StorageError):
381 384 """error raised when a delta is rejected because its base is censored
382 385
383 386 A delta based on a censored revision must be formed as single patch
384 387 operation which replaces the entire base with new content. This ensures
385 388 the delta may be applied by clones which have not censored the base.
386 389 """
387 390
388 391
389 392 class InvalidBundleSpecification(Exception):
390 393 """error raised when a bundle specification is invalid.
391 394
392 395 This is used for syntax errors as opposed to support errors.
393 396 """
394 397
395 398 __bytes__ = _tobytes
396 399
397 400
398 401 class UnsupportedBundleSpecification(Exception):
399 402 """error raised when a bundle specification is not supported."""
400 403
401 404 __bytes__ = _tobytes
402 405
403 406
404 407 class CorruptedState(Exception):
405 408 """error raised when a command is not able to read its state from file"""
406 409
407 410 __bytes__ = _tobytes
408 411
409 412
410 413 class PeerTransportError(Abort):
411 414 """Transport-level I/O error when communicating with a peer repo."""
412 415
413 416
414 417 class InMemoryMergeConflictsError(Exception):
415 418 """Exception raised when merge conflicts arose during an in-memory merge."""
416 419
417 420 __bytes__ = _tobytes
418 421
419 422
420 423 class WireprotoCommandError(Exception):
421 424 """Represents an error during execution of a wire protocol command.
422 425
423 426 Should only be thrown by wire protocol version 2 commands.
424 427
425 428 The error is a formatter string and an optional iterable of arguments.
426 429 """
427 430
428 431 def __init__(self, message, args=None):
429 432 self.message = message
430 433 self.messageargs = args
@@ -1,304 +1,304 b''
1 1 # Create server
2 2 $ hg init server
3 3 $ cd server
4 4 $ cat >> .hg/hgrc << EOF
5 5 > [extensions]
6 6 > extension=$TESTDIR/flagprocessorext.py
7 7 > EOF
8 8 $ cd ../
9 9
10 10 # Clone server and enable extensions
11 11 $ hg clone -q server client
12 12 $ cd client
13 13 $ cat >> .hg/hgrc << EOF
14 14 > [extensions]
15 15 > extension=$TESTDIR/flagprocessorext.py
16 16 > EOF
17 17
18 18 # Commit file that will trigger the noop extension
19 19 $ echo '[NOOP]' > noop
20 20 $ hg commit -Aqm "noop"
21 21
22 22 # Commit file that will trigger the base64 extension
23 23 $ echo '[BASE64]' > base64
24 24 $ hg commit -Aqm 'base64'
25 25
26 26 # Commit file that will trigger the gzip extension
27 27 $ echo '[GZIP]' > gzip
28 28 $ hg commit -Aqm 'gzip'
29 29
30 30 # Commit file that will trigger noop and base64
31 31 $ echo '[NOOP][BASE64]' > noop-base64
32 32 $ hg commit -Aqm 'noop+base64'
33 33
34 34 # Commit file that will trigger noop and gzip
35 35 $ echo '[NOOP][GZIP]' > noop-gzip
36 36 $ hg commit -Aqm 'noop+gzip'
37 37
38 38 # Commit file that will trigger base64 and gzip
39 39 $ echo '[BASE64][GZIP]' > base64-gzip
40 40 $ hg commit -Aqm 'base64+gzip'
41 41
42 42 # Commit file that will trigger base64, gzip and noop
43 43 $ echo '[BASE64][GZIP][NOOP]' > base64-gzip-noop
44 44 $ hg commit -Aqm 'base64+gzip+noop'
45 45
46 46 # TEST: ensure the revision data is consistent
47 47 $ hg cat noop
48 48 [NOOP]
49 49 $ hg debugdata noop 0
50 50 [NOOP]
51 51
52 52 $ hg cat -r . base64
53 53 [BASE64]
54 54 $ hg debugdata base64 0
55 55 W0JBU0U2NF0K (no-eol)
56 56
57 57 $ hg cat -r . gzip
58 58 [GZIP]
59 59 $ hg debugdata gzip 0
60 60 x\x9c\x8bv\x8f\xf2\x0c\x88\xe5\x02\x00\x08\xc8\x01\xfd (no-eol) (esc)
61 61
62 62 $ hg cat -r . noop-base64
63 63 [NOOP][BASE64]
64 64 $ hg debugdata noop-base64 0
65 65 W05PT1BdW0JBU0U2NF0K (no-eol)
66 66
67 67 $ hg cat -r . noop-gzip
68 68 [NOOP][GZIP]
69 69 $ hg debugdata noop-gzip 0
70 70 x\x9c\x8b\xf6\xf3\xf7\x0f\x88\x8dv\x8f\xf2\x0c\x88\xe5\x02\x00\x1dH\x03\xf1 (no-eol) (esc)
71 71
72 72 $ hg cat -r . base64-gzip
73 73 [BASE64][GZIP]
74 74 $ hg debugdata base64-gzip 0
75 75 eJyLdnIMdjUziY12j/IMiOUCACLBBDo= (no-eol)
76 76
77 77 $ hg cat -r . base64-gzip-noop
78 78 [BASE64][GZIP][NOOP]
79 79 $ hg debugdata base64-gzip-noop 0
80 80 eJyLdnIMdjUziY12j/IMiI328/cPiOUCAESjBi4= (no-eol)
81 81
82 82 # Push to the server
83 83 $ hg push
84 84 pushing to $TESTTMP/server
85 85 searching for changes
86 86 adding changesets
87 87 adding manifests
88 88 adding file changes
89 89 added 7 changesets with 7 changes to 7 files
90 90
91 91 Ensure the data got to the server OK
92 92
93 93 $ cd ../server
94 94 $ hg cat -r 6e48f4215d24 noop
95 95 [NOOP]
96 96 $ hg debugdata noop 0
97 97 [NOOP]
98 98
99 99 $ hg cat -r 6e48f4215d24 base64
100 100 [BASE64]
101 101 $ hg debugdata base64 0
102 102 W0JBU0U2NF0K (no-eol)
103 103
104 104 $ hg cat -r 6e48f4215d24 gzip
105 105 [GZIP]
106 106 $ hg debugdata gzip 0
107 107 x\x9c\x8bv\x8f\xf2\x0c\x88\xe5\x02\x00\x08\xc8\x01\xfd (no-eol) (esc)
108 108
109 109 $ hg cat -r 6e48f4215d24 noop-base64
110 110 [NOOP][BASE64]
111 111 $ hg debugdata noop-base64 0
112 112 W05PT1BdW0JBU0U2NF0K (no-eol)
113 113
114 114 $ hg cat -r 6e48f4215d24 noop-gzip
115 115 [NOOP][GZIP]
116 116 $ hg debugdata noop-gzip 0
117 117 x\x9c\x8b\xf6\xf3\xf7\x0f\x88\x8dv\x8f\xf2\x0c\x88\xe5\x02\x00\x1dH\x03\xf1 (no-eol) (esc)
118 118
119 119 $ hg cat -r 6e48f4215d24 base64-gzip
120 120 [BASE64][GZIP]
121 121 $ hg debugdata base64-gzip 0
122 122 eJyLdnIMdjUziY12j/IMiOUCACLBBDo= (no-eol)
123 123
124 124 $ hg cat -r 6e48f4215d24 base64-gzip-noop
125 125 [BASE64][GZIP][NOOP]
126 126 $ hg debugdata base64-gzip-noop 0
127 127 eJyLdnIMdjUziY12j/IMiI328/cPiOUCAESjBi4= (no-eol)
128 128
129 129 # Initialize new client (not cloning) and setup extension
130 130 $ cd ..
131 131 $ hg init client2
132 132 $ cd client2
133 133 $ cat >> .hg/hgrc << EOF
134 134 > [paths]
135 135 > default = $TESTTMP/server
136 136 > [extensions]
137 137 > extension=$TESTDIR/flagprocessorext.py
138 138 > EOF
139 139
140 140 # Pull from server and update to latest revision
141 141 $ hg pull default
142 142 pulling from $TESTTMP/server
143 143 requesting all changes
144 144 adding changesets
145 145 adding manifests
146 146 adding file changes
147 147 added 7 changesets with 7 changes to 7 files
148 148 new changesets 07b1b9442c5b:6e48f4215d24
149 149 (run 'hg update' to get a working copy)
150 150 $ hg update
151 151 7 files updated, 0 files merged, 0 files removed, 0 files unresolved
152 152
153 153 # TEST: ensure the revision data is consistent
154 154 $ hg cat noop
155 155 [NOOP]
156 156 $ hg debugdata noop 0
157 157 [NOOP]
158 158
159 159 $ hg cat -r . base64
160 160 [BASE64]
161 161 $ hg debugdata base64 0
162 162 W0JBU0U2NF0K (no-eol)
163 163
164 164 $ hg cat -r . gzip
165 165 [GZIP]
166 166 $ hg debugdata gzip 0
167 167 x\x9c\x8bv\x8f\xf2\x0c\x88\xe5\x02\x00\x08\xc8\x01\xfd (no-eol) (esc)
168 168
169 169 $ hg cat -r . noop-base64
170 170 [NOOP][BASE64]
171 171 $ hg debugdata noop-base64 0
172 172 W05PT1BdW0JBU0U2NF0K (no-eol)
173 173
174 174 $ hg cat -r . noop-gzip
175 175 [NOOP][GZIP]
176 176 $ hg debugdata noop-gzip 0
177 177 x\x9c\x8b\xf6\xf3\xf7\x0f\x88\x8dv\x8f\xf2\x0c\x88\xe5\x02\x00\x1dH\x03\xf1 (no-eol) (esc)
178 178
179 179 $ hg cat -r . base64-gzip
180 180 [BASE64][GZIP]
181 181 $ hg debugdata base64-gzip 0
182 182 eJyLdnIMdjUziY12j/IMiOUCACLBBDo= (no-eol)
183 183
184 184 $ hg cat -r . base64-gzip-noop
185 185 [BASE64][GZIP][NOOP]
186 186 $ hg debugdata base64-gzip-noop 0
187 187 eJyLdnIMdjUziY12j/IMiI328/cPiOUCAESjBi4= (no-eol)
188 188
189 189 # TEST: ensure a missing processor is handled
190 190 $ echo '[FAIL][BASE64][GZIP][NOOP]' > fail-base64-gzip-noop
191 191 $ hg commit -Aqm 'fail+base64+gzip+noop'
192 192 abort: missing processor for flag '0x1'!
193 193 [255]
194 194 $ rm fail-base64-gzip-noop
195 195
196 196 # TEST: ensure we cannot register several flag processors on the same flag
197 197 $ cat >> .hg/hgrc << EOF
198 198 > [extensions]
199 199 > extension=$TESTDIR/flagprocessorext.py
200 200 > duplicate=$TESTDIR/flagprocessorext.py
201 201 > EOF
202 202 $ hg debugrebuilddirstate
203 203 Traceback (most recent call last):
204 204 File "*/mercurial/extensions.py", line *, in _runextsetup (glob)
205 205 extsetup(ui)
206 206 File "*/tests/flagprocessorext.py", line *, in extsetup (glob)
207 207 REVIDX_NOOP, (noopdonothingread, noopdonothing, validatehash,)
208 208 File "*/mercurial/revlogutils/flagutil.py", line *, in addflagprocessor (glob)
209 209 insertflagprocessor(flag, processor, flagprocessors)
210 210 File "*/mercurial/revlogutils/flagutil.py", line *, in insertflagprocessor (glob)
211 211 raise error.Abort(msg)
212 mercurial.error.Abort: b"cannot register multiple processors on flag '0x8'." (py3 !)
212 mercurial.error.Abort: cannot register multiple processors on flag '0x8'. (py3 !)
213 213 Abort: cannot register multiple processors on flag '0x8'. (no-py3 !)
214 214 *** failed to set up extension duplicate: cannot register multiple processors on flag '0x8'.
215 215 $ hg st 2>&1 | egrep 'cannot register multiple processors|flagprocessorext'
216 216 File "*/tests/flagprocessorext.py", line *, in extsetup (glob)
217 mercurial.error.Abort: b"cannot register multiple processors on flag '0x8'." (py3 !)
217 mercurial.error.Abort: cannot register multiple processors on flag '0x8'. (py3 !)
218 218 Abort: cannot register multiple processors on flag '0x8'. (no-py3 !)
219 219 *** failed to set up extension duplicate: cannot register multiple processors on flag '0x8'.
220 220 File "*/tests/flagprocessorext.py", line *, in b64decode (glob)
221 221
222 222 $ cd ..
223 223
224 224 # TEST: bundle repo
225 225 $ hg init bundletest
226 226 $ cd bundletest
227 227
228 228 $ cat >> .hg/hgrc << EOF
229 229 > [extensions]
230 230 > flagprocessor=$TESTDIR/flagprocessorext.py
231 231 > EOF
232 232
233 233 $ for i in 0 single two three 4; do
234 234 > echo '[BASE64]a-bit-longer-'$i > base64
235 235 > hg commit -m base64-$i -A base64
236 236 > done
237 237
238 238 $ hg update 2 -q
239 239 $ echo '[BASE64]a-bit-longer-branching' > base64
240 240 $ hg commit -q -m branching
241 241
242 242 #if repobundlerepo
243 243 $ hg bundle --base 1 bundle.hg
244 244 4 changesets found
245 245 $ hg --config extensions.strip= strip -r 2 --no-backup --force -q
246 246 $ hg -R bundle.hg log --stat -T '{rev} {desc}\n' base64
247 247 5 branching
248 248 base64 | 2 +-
249 249 1 files changed, 1 insertions(+), 1 deletions(-)
250 250
251 251 4 base64-4
252 252 base64 | 2 +-
253 253 1 files changed, 1 insertions(+), 1 deletions(-)
254 254
255 255 3 base64-three
256 256 base64 | 2 +-
257 257 1 files changed, 1 insertions(+), 1 deletions(-)
258 258
259 259 2 base64-two
260 260 base64 | 2 +-
261 261 1 files changed, 1 insertions(+), 1 deletions(-)
262 262
263 263 1 base64-single
264 264 base64 | 2 +-
265 265 1 files changed, 1 insertions(+), 1 deletions(-)
266 266
267 267 0 base64-0
268 268 base64 | 1 +
269 269 1 files changed, 1 insertions(+), 0 deletions(-)
270 270
271 271
272 272 $ hg bundle -R bundle.hg --base 1 bundle-again.hg -q
273 273 $ hg -R bundle-again.hg log --stat -T '{rev} {desc}\n' base64
274 274 5 branching
275 275 base64 | 2 +-
276 276 1 files changed, 1 insertions(+), 1 deletions(-)
277 277
278 278 4 base64-4
279 279 base64 | 2 +-
280 280 1 files changed, 1 insertions(+), 1 deletions(-)
281 281
282 282 3 base64-three
283 283 base64 | 2 +-
284 284 1 files changed, 1 insertions(+), 1 deletions(-)
285 285
286 286 2 base64-two
287 287 base64 | 2 +-
288 288 1 files changed, 1 insertions(+), 1 deletions(-)
289 289
290 290 1 base64-single
291 291 base64 | 2 +-
292 292 1 files changed, 1 insertions(+), 1 deletions(-)
293 293
294 294 0 base64-0
295 295 base64 | 1 +
296 296 1 files changed, 1 insertions(+), 0 deletions(-)
297 297
298 298 $ rm bundle.hg bundle-again.hg
299 299 #endif
300 300
301 301 # TEST: hg status
302 302
303 303 $ hg status
304 304 $ hg diff
@@ -1,1390 +1,1390 b''
1 1 commit hooks can see env vars
2 2 (and post-transaction one are run unlocked)
3 3
4 4
5 5 $ cat > $TESTTMP/txnabort.checkargs.py <<EOF
6 6 > from mercurial import pycompat
7 7 > def showargs(ui, repo, hooktype, **kwargs):
8 8 > kwargs = pycompat.byteskwargs(kwargs)
9 9 > ui.write(b'%s Python hook: %s\n' % (hooktype,
10 10 > b','.join(sorted(kwargs))))
11 11 > EOF
12 12
13 13 $ hg init a
14 14 $ cd a
15 15 $ cat > .hg/hgrc <<EOF
16 16 > [hooks]
17 17 > commit = sh -c "HG_LOCAL= HG_TAG= printenv.py --line commit"
18 18 > commit.b = sh -c "HG_LOCAL= HG_TAG= printenv.py --line commit.b"
19 19 > precommit = sh -c "HG_LOCAL= HG_NODE= HG_TAG= printenv.py --line precommit"
20 20 > pretxncommit = sh -c "HG_LOCAL= HG_TAG= printenv.py --line pretxncommit"
21 21 > pretxncommit.tip = hg -q tip
22 22 > pre-identify = sh -c "printenv.py --line pre-identify 1"
23 23 > pre-cat = sh -c "printenv.py --line pre-cat"
24 24 > post-cat = sh -c "printenv.py --line post-cat"
25 25 > pretxnopen = sh -c "HG_LOCAL= HG_TAG= printenv.py --line pretxnopen"
26 26 > pretxnclose = sh -c "HG_LOCAL= HG_TAG= printenv.py --line pretxnclose"
27 27 > txnclose = sh -c "HG_LOCAL= HG_TAG= printenv.py --line txnclose"
28 28 > txnabort.0 = python:$TESTTMP/txnabort.checkargs.py:showargs
29 29 > txnabort.1 = sh -c "HG_LOCAL= HG_TAG= printenv.py --line txnabort"
30 30 > txnclose.checklock = sh -c "hg debuglock > /dev/null"
31 31 > EOF
32 32 $ echo a > a
33 33 $ hg add a
34 34 $ hg commit -m a
35 35 precommit hook: HG_HOOKNAME=precommit
36 36 HG_HOOKTYPE=precommit
37 37 HG_PARENT1=0000000000000000000000000000000000000000
38 38
39 39 pretxnopen hook: HG_HOOKNAME=pretxnopen
40 40 HG_HOOKTYPE=pretxnopen
41 41 HG_TXNID=TXN:$ID$
42 42 HG_TXNNAME=commit
43 43
44 44 pretxncommit hook: HG_HOOKNAME=pretxncommit
45 45 HG_HOOKTYPE=pretxncommit
46 46 HG_NODE=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
47 47 HG_PARENT1=0000000000000000000000000000000000000000
48 48 HG_PENDING=$TESTTMP/a
49 49
50 50 0:cb9a9f314b8b
51 51 pretxnclose hook: HG_HOOKNAME=pretxnclose
52 52 HG_HOOKTYPE=pretxnclose
53 53 HG_PENDING=$TESTTMP/a
54 54 HG_PHASES_MOVED=1
55 55 HG_TXNID=TXN:$ID$
56 56 HG_TXNNAME=commit
57 57
58 58 txnclose hook: HG_HOOKNAME=txnclose
59 59 HG_HOOKTYPE=txnclose
60 60 HG_PHASES_MOVED=1
61 61 HG_TXNID=TXN:$ID$
62 62 HG_TXNNAME=commit
63 63
64 64 commit hook: HG_HOOKNAME=commit
65 65 HG_HOOKTYPE=commit
66 66 HG_NODE=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
67 67 HG_PARENT1=0000000000000000000000000000000000000000
68 68
69 69 commit.b hook: HG_HOOKNAME=commit.b
70 70 HG_HOOKTYPE=commit
71 71 HG_NODE=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
72 72 HG_PARENT1=0000000000000000000000000000000000000000
73 73
74 74
75 75 $ hg clone . ../b
76 76 updating to branch default
77 77 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
78 78 $ cd ../b
79 79
80 80 changegroup hooks can see env vars
81 81
82 82 $ cat > .hg/hgrc <<EOF
83 83 > [hooks]
84 84 > prechangegroup = sh -c "printenv.py --line prechangegroup"
85 85 > changegroup = sh -c "printenv.py --line changegroup"
86 86 > incoming = sh -c "printenv.py --line incoming"
87 87 > EOF
88 88
89 89 pretxncommit and commit hooks can see both parents of merge
90 90
91 91 $ cd ../a
92 92 $ echo b >> a
93 93 $ hg commit -m a1 -d "1 0"
94 94 precommit hook: HG_HOOKNAME=precommit
95 95 HG_HOOKTYPE=precommit
96 96 HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
97 97
98 98 pretxnopen hook: HG_HOOKNAME=pretxnopen
99 99 HG_HOOKTYPE=pretxnopen
100 100 HG_TXNID=TXN:$ID$
101 101 HG_TXNNAME=commit
102 102
103 103 pretxncommit hook: HG_HOOKNAME=pretxncommit
104 104 HG_HOOKTYPE=pretxncommit
105 105 HG_NODE=ab228980c14deea8b9555d91c9581127383e40fd
106 106 HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
107 107 HG_PENDING=$TESTTMP/a
108 108
109 109 1:ab228980c14d
110 110 pretxnclose hook: HG_HOOKNAME=pretxnclose
111 111 HG_HOOKTYPE=pretxnclose
112 112 HG_PENDING=$TESTTMP/a
113 113 HG_TXNID=TXN:$ID$
114 114 HG_TXNNAME=commit
115 115
116 116 txnclose hook: HG_HOOKNAME=txnclose
117 117 HG_HOOKTYPE=txnclose
118 118 HG_TXNID=TXN:$ID$
119 119 HG_TXNNAME=commit
120 120
121 121 commit hook: HG_HOOKNAME=commit
122 122 HG_HOOKTYPE=commit
123 123 HG_NODE=ab228980c14deea8b9555d91c9581127383e40fd
124 124 HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
125 125
126 126 commit.b hook: HG_HOOKNAME=commit.b
127 127 HG_HOOKTYPE=commit
128 128 HG_NODE=ab228980c14deea8b9555d91c9581127383e40fd
129 129 HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
130 130
131 131 $ hg update -C 0
132 132 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
133 133 $ echo b > b
134 134 $ hg add b
135 135 $ hg commit -m b -d '1 0'
136 136 precommit hook: HG_HOOKNAME=precommit
137 137 HG_HOOKTYPE=precommit
138 138 HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
139 139
140 140 pretxnopen hook: HG_HOOKNAME=pretxnopen
141 141 HG_HOOKTYPE=pretxnopen
142 142 HG_TXNID=TXN:$ID$
143 143 HG_TXNNAME=commit
144 144
145 145 pretxncommit hook: HG_HOOKNAME=pretxncommit
146 146 HG_HOOKTYPE=pretxncommit
147 147 HG_NODE=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2
148 148 HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
149 149 HG_PENDING=$TESTTMP/a
150 150
151 151 2:ee9deb46ab31
152 152 pretxnclose hook: HG_HOOKNAME=pretxnclose
153 153 HG_HOOKTYPE=pretxnclose
154 154 HG_PENDING=$TESTTMP/a
155 155 HG_TXNID=TXN:$ID$
156 156 HG_TXNNAME=commit
157 157
158 158 created new head
159 159 txnclose hook: HG_HOOKNAME=txnclose
160 160 HG_HOOKTYPE=txnclose
161 161 HG_TXNID=TXN:$ID$
162 162 HG_TXNNAME=commit
163 163
164 164 commit hook: HG_HOOKNAME=commit
165 165 HG_HOOKTYPE=commit
166 166 HG_NODE=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2
167 167 HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
168 168
169 169 commit.b hook: HG_HOOKNAME=commit.b
170 170 HG_HOOKTYPE=commit
171 171 HG_NODE=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2
172 172 HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
173 173
174 174 $ hg merge 1
175 175 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
176 176 (branch merge, don't forget to commit)
177 177 $ hg commit -m merge -d '2 0'
178 178 precommit hook: HG_HOOKNAME=precommit
179 179 HG_HOOKTYPE=precommit
180 180 HG_PARENT1=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2
181 181 HG_PARENT2=ab228980c14deea8b9555d91c9581127383e40fd
182 182
183 183 pretxnopen hook: HG_HOOKNAME=pretxnopen
184 184 HG_HOOKTYPE=pretxnopen
185 185 HG_TXNID=TXN:$ID$
186 186 HG_TXNNAME=commit
187 187
188 188 pretxncommit hook: HG_HOOKNAME=pretxncommit
189 189 HG_HOOKTYPE=pretxncommit
190 190 HG_NODE=07f3376c1e655977439df2a814e3cc14b27abac2
191 191 HG_PARENT1=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2
192 192 HG_PARENT2=ab228980c14deea8b9555d91c9581127383e40fd
193 193 HG_PENDING=$TESTTMP/a
194 194
195 195 3:07f3376c1e65
196 196 pretxnclose hook: HG_HOOKNAME=pretxnclose
197 197 HG_HOOKTYPE=pretxnclose
198 198 HG_PENDING=$TESTTMP/a
199 199 HG_TXNID=TXN:$ID$
200 200 HG_TXNNAME=commit
201 201
202 202 txnclose hook: HG_HOOKNAME=txnclose
203 203 HG_HOOKTYPE=txnclose
204 204 HG_TXNID=TXN:$ID$
205 205 HG_TXNNAME=commit
206 206
207 207 commit hook: HG_HOOKNAME=commit
208 208 HG_HOOKTYPE=commit
209 209 HG_NODE=07f3376c1e655977439df2a814e3cc14b27abac2
210 210 HG_PARENT1=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2
211 211 HG_PARENT2=ab228980c14deea8b9555d91c9581127383e40fd
212 212
213 213 commit.b hook: HG_HOOKNAME=commit.b
214 214 HG_HOOKTYPE=commit
215 215 HG_NODE=07f3376c1e655977439df2a814e3cc14b27abac2
216 216 HG_PARENT1=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2
217 217 HG_PARENT2=ab228980c14deea8b9555d91c9581127383e40fd
218 218
219 219
220 220 test generic hooks
221 221
222 222 $ hg id
223 223 pre-identify hook: HG_ARGS=id
224 224 HG_HOOKNAME=pre-identify
225 225 HG_HOOKTYPE=pre-identify
226 226 HG_OPTS={'bookmarks': None, 'branch': None, 'id': None, 'insecure': None, 'num': None, 'remotecmd': '', 'rev': '', 'ssh': '', 'tags': None, 'template': ''}
227 227 HG_PATS=[]
228 228
229 229 abort: pre-identify hook exited with status 1
230 230 [255]
231 231 $ hg cat b
232 232 pre-cat hook: HG_ARGS=cat b
233 233 HG_HOOKNAME=pre-cat
234 234 HG_HOOKTYPE=pre-cat
235 235 HG_OPTS={'decode': None, 'exclude': [], 'include': [], 'output': '', 'rev': '', 'template': ''}
236 236 HG_PATS=['b']
237 237
238 238 b
239 239 post-cat hook: HG_ARGS=cat b
240 240 HG_HOOKNAME=post-cat
241 241 HG_HOOKTYPE=post-cat
242 242 HG_OPTS={'decode': None, 'exclude': [], 'include': [], 'output': '', 'rev': '', 'template': ''}
243 243 HG_PATS=['b']
244 244 HG_RESULT=0
245 245
246 246
247 247 $ cd ../b
248 248 $ hg pull ../a
249 249 pulling from ../a
250 250 searching for changes
251 251 prechangegroup hook: HG_HOOKNAME=prechangegroup
252 252 HG_HOOKTYPE=prechangegroup
253 253 HG_SOURCE=pull
254 254 HG_TXNID=TXN:$ID$
255 255 HG_TXNNAME=pull
256 256 file:/*/$TESTTMP/a (glob)
257 257 HG_URL=file:$TESTTMP/a
258 258
259 259 adding changesets
260 260 adding manifests
261 261 adding file changes
262 262 added 3 changesets with 2 changes to 2 files
263 263 new changesets ab228980c14d:07f3376c1e65
264 264 changegroup hook: HG_HOOKNAME=changegroup
265 265 HG_HOOKTYPE=changegroup
266 266 HG_NODE=ab228980c14deea8b9555d91c9581127383e40fd
267 267 HG_NODE_LAST=07f3376c1e655977439df2a814e3cc14b27abac2
268 268 HG_SOURCE=pull
269 269 HG_TXNID=TXN:$ID$
270 270 HG_TXNNAME=pull
271 271 file:/*/$TESTTMP/a (glob)
272 272 HG_URL=file:$TESTTMP/a
273 273
274 274 incoming hook: HG_HOOKNAME=incoming
275 275 HG_HOOKTYPE=incoming
276 276 HG_NODE=ab228980c14deea8b9555d91c9581127383e40fd
277 277 HG_SOURCE=pull
278 278 HG_TXNID=TXN:$ID$
279 279 HG_TXNNAME=pull
280 280 file:/*/$TESTTMP/a (glob)
281 281 HG_URL=file:$TESTTMP/a
282 282
283 283 incoming hook: HG_HOOKNAME=incoming
284 284 HG_HOOKTYPE=incoming
285 285 HG_NODE=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2
286 286 HG_SOURCE=pull
287 287 HG_TXNID=TXN:$ID$
288 288 HG_TXNNAME=pull
289 289 file:/*/$TESTTMP/a (glob)
290 290 HG_URL=file:$TESTTMP/a
291 291
292 292 incoming hook: HG_HOOKNAME=incoming
293 293 HG_HOOKTYPE=incoming
294 294 HG_NODE=07f3376c1e655977439df2a814e3cc14b27abac2
295 295 HG_SOURCE=pull
296 296 HG_TXNID=TXN:$ID$
297 297 HG_TXNNAME=pull
298 298 file:/*/$TESTTMP/a (glob)
299 299 HG_URL=file:$TESTTMP/a
300 300
301 301 (run 'hg update' to get a working copy)
302 302
303 303 tag hooks can see env vars
304 304
305 305 $ cd ../a
306 306 $ cat >> .hg/hgrc <<EOF
307 307 > pretag = sh -c "printenv.py --line pretag"
308 308 > tag = sh -c "HG_PARENT1= HG_PARENT2= printenv.py --line tag"
309 309 > EOF
310 310 $ hg tag -d '3 0' a
311 311 pretag hook: HG_HOOKNAME=pretag
312 312 HG_HOOKTYPE=pretag
313 313 HG_LOCAL=0
314 314 HG_NODE=07f3376c1e655977439df2a814e3cc14b27abac2
315 315 HG_TAG=a
316 316
317 317 precommit hook: HG_HOOKNAME=precommit
318 318 HG_HOOKTYPE=precommit
319 319 HG_PARENT1=07f3376c1e655977439df2a814e3cc14b27abac2
320 320
321 321 pretxnopen hook: HG_HOOKNAME=pretxnopen
322 322 HG_HOOKTYPE=pretxnopen
323 323 HG_TXNID=TXN:$ID$
324 324 HG_TXNNAME=commit
325 325
326 326 pretxncommit hook: HG_HOOKNAME=pretxncommit
327 327 HG_HOOKTYPE=pretxncommit
328 328 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10
329 329 HG_PARENT1=07f3376c1e655977439df2a814e3cc14b27abac2
330 330 HG_PENDING=$TESTTMP/a
331 331
332 332 4:539e4b31b6dc
333 333 pretxnclose hook: HG_HOOKNAME=pretxnclose
334 334 HG_HOOKTYPE=pretxnclose
335 335 HG_PENDING=$TESTTMP/a
336 336 HG_TXNID=TXN:$ID$
337 337 HG_TXNNAME=commit
338 338
339 339 tag hook: HG_HOOKNAME=tag
340 340 HG_HOOKTYPE=tag
341 341 HG_LOCAL=0
342 342 HG_NODE=07f3376c1e655977439df2a814e3cc14b27abac2
343 343 HG_TAG=a
344 344
345 345 txnclose hook: HG_HOOKNAME=txnclose
346 346 HG_HOOKTYPE=txnclose
347 347 HG_TXNID=TXN:$ID$
348 348 HG_TXNNAME=commit
349 349
350 350 commit hook: HG_HOOKNAME=commit
351 351 HG_HOOKTYPE=commit
352 352 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10
353 353 HG_PARENT1=07f3376c1e655977439df2a814e3cc14b27abac2
354 354
355 355 commit.b hook: HG_HOOKNAME=commit.b
356 356 HG_HOOKTYPE=commit
357 357 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10
358 358 HG_PARENT1=07f3376c1e655977439df2a814e3cc14b27abac2
359 359
360 360 $ hg tag -l la
361 361 pretag hook: HG_HOOKNAME=pretag
362 362 HG_HOOKTYPE=pretag
363 363 HG_LOCAL=1
364 364 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10
365 365 HG_TAG=la
366 366
367 367 tag hook: HG_HOOKNAME=tag
368 368 HG_HOOKTYPE=tag
369 369 HG_LOCAL=1
370 370 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10
371 371 HG_TAG=la
372 372
373 373
374 374 pretag hook can forbid tagging
375 375
376 376 $ cat >> .hg/hgrc <<EOF
377 377 > pretag.forbid = sh -c "printenv.py --line pretag.forbid 1"
378 378 > EOF
379 379 $ hg tag -d '4 0' fa
380 380 pretag hook: HG_HOOKNAME=pretag
381 381 HG_HOOKTYPE=pretag
382 382 HG_LOCAL=0
383 383 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10
384 384 HG_TAG=fa
385 385
386 386 pretag.forbid hook: HG_HOOKNAME=pretag.forbid
387 387 HG_HOOKTYPE=pretag
388 388 HG_LOCAL=0
389 389 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10
390 390 HG_TAG=fa
391 391
392 392 abort: pretag.forbid hook exited with status 1
393 393 [255]
394 394 $ hg tag -l fla
395 395 pretag hook: HG_HOOKNAME=pretag
396 396 HG_HOOKTYPE=pretag
397 397 HG_LOCAL=1
398 398 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10
399 399 HG_TAG=fla
400 400
401 401 pretag.forbid hook: HG_HOOKNAME=pretag.forbid
402 402 HG_HOOKTYPE=pretag
403 403 HG_LOCAL=1
404 404 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10
405 405 HG_TAG=fla
406 406
407 407 abort: pretag.forbid hook exited with status 1
408 408 [255]
409 409
410 410 pretxncommit hook can see changeset, can roll back txn, changeset no
411 411 more there after
412 412
413 413 $ cat >> .hg/hgrc <<EOF
414 414 > pretxncommit.forbid0 = sh -c "hg tip -q"
415 415 > pretxncommit.forbid1 = sh -c "printenv.py --line pretxncommit.forbid 1"
416 416 > EOF
417 417 $ echo z > z
418 418 $ hg add z
419 419 $ hg -q tip
420 420 4:539e4b31b6dc
421 421 $ hg commit -m 'fail' -d '4 0'
422 422 precommit hook: HG_HOOKNAME=precommit
423 423 HG_HOOKTYPE=precommit
424 424 HG_PARENT1=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10
425 425
426 426 pretxnopen hook: HG_HOOKNAME=pretxnopen
427 427 HG_HOOKTYPE=pretxnopen
428 428 HG_TXNID=TXN:$ID$
429 429 HG_TXNNAME=commit
430 430
431 431 pretxncommit hook: HG_HOOKNAME=pretxncommit
432 432 HG_HOOKTYPE=pretxncommit
433 433 HG_NODE=6f611f8018c10e827fee6bd2bc807f937e761567
434 434 HG_PARENT1=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10
435 435 HG_PENDING=$TESTTMP/a
436 436
437 437 5:6f611f8018c1
438 438 5:6f611f8018c1
439 439 pretxncommit.forbid hook: HG_HOOKNAME=pretxncommit.forbid1
440 440 HG_HOOKTYPE=pretxncommit
441 441 HG_NODE=6f611f8018c10e827fee6bd2bc807f937e761567
442 442 HG_PARENT1=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10
443 443 HG_PENDING=$TESTTMP/a
444 444
445 445 transaction abort!
446 446 txnabort Python hook: txnid,txnname
447 447 txnabort hook: HG_HOOKNAME=txnabort.1
448 448 HG_HOOKTYPE=txnabort
449 449 HG_TXNID=TXN:$ID$
450 450 HG_TXNNAME=commit
451 451
452 452 rollback completed
453 453 abort: pretxncommit.forbid1 hook exited with status 1
454 454 [255]
455 455 $ hg -q tip
456 456 4:539e4b31b6dc
457 457
458 458 (Check that no 'changelog.i.a' file were left behind)
459 459
460 460 $ ls -1 .hg/store/
461 461 00changelog.i
462 462 00manifest.i
463 463 data
464 464 fncache (repofncache !)
465 465 journal.phaseroots
466 466 phaseroots
467 467 undo
468 468 undo.backup.fncache (repofncache !)
469 469 undo.backupfiles
470 470 undo.phaseroots
471 471
472 472
473 473 precommit hook can prevent commit
474 474
475 475 $ cat >> .hg/hgrc <<EOF
476 476 > precommit.forbid = sh -c "printenv.py --line precommit.forbid 1"
477 477 > EOF
478 478 $ hg commit -m 'fail' -d '4 0'
479 479 precommit hook: HG_HOOKNAME=precommit
480 480 HG_HOOKTYPE=precommit
481 481 HG_PARENT1=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10
482 482
483 483 precommit.forbid hook: HG_HOOKNAME=precommit.forbid
484 484 HG_HOOKTYPE=precommit
485 485 HG_PARENT1=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10
486 486
487 487 abort: precommit.forbid hook exited with status 1
488 488 [255]
489 489 $ hg -q tip
490 490 4:539e4b31b6dc
491 491
492 492 preupdate hook can prevent update
493 493
494 494 $ cat >> .hg/hgrc <<EOF
495 495 > preupdate = sh -c "printenv.py --line preupdate"
496 496 > EOF
497 497 $ hg update 1
498 498 preupdate hook: HG_HOOKNAME=preupdate
499 499 HG_HOOKTYPE=preupdate
500 500 HG_PARENT1=ab228980c14d
501 501
502 502 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
503 503
504 504 update hook
505 505
506 506 $ cat >> .hg/hgrc <<EOF
507 507 > update = sh -c "printenv.py --line update"
508 508 > EOF
509 509 $ hg update
510 510 preupdate hook: HG_HOOKNAME=preupdate
511 511 HG_HOOKTYPE=preupdate
512 512 HG_PARENT1=539e4b31b6dc
513 513
514 514 update hook: HG_ERROR=0
515 515 HG_HOOKNAME=update
516 516 HG_HOOKTYPE=update
517 517 HG_PARENT1=539e4b31b6dc
518 518
519 519 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
520 520
521 521 pushkey hook
522 522
523 523 $ cat >> .hg/hgrc <<EOF
524 524 > pushkey = sh -c "printenv.py --line pushkey"
525 525 > EOF
526 526 $ cd ../b
527 527 $ hg bookmark -r null foo
528 528 $ hg push -B foo ../a
529 529 pushing to ../a
530 530 searching for changes
531 531 no changes found
532 532 pretxnopen hook: HG_HOOKNAME=pretxnopen
533 533 HG_HOOKTYPE=pretxnopen
534 534 HG_TXNID=TXN:$ID$
535 535 HG_TXNNAME=push
536 536
537 537 pretxnclose hook: HG_BOOKMARK_MOVED=1
538 538 HG_BUNDLE2=1
539 539 HG_HOOKNAME=pretxnclose
540 540 HG_HOOKTYPE=pretxnclose
541 541 HG_PENDING=$TESTTMP/a
542 542 HG_SOURCE=push
543 543 HG_TXNID=TXN:$ID$
544 544 HG_TXNNAME=push
545 545 HG_URL=file:$TESTTMP/a
546 546
547 547 pushkey hook: HG_BUNDLE2=1
548 548 HG_HOOKNAME=pushkey
549 549 HG_HOOKTYPE=pushkey
550 550 HG_KEY=foo
551 551 HG_NAMESPACE=bookmarks
552 552 HG_NEW=0000000000000000000000000000000000000000
553 553 HG_PUSHKEYCOMPAT=1
554 554 HG_SOURCE=push
555 555 HG_TXNID=TXN:$ID$
556 556 HG_TXNNAME=push
557 557 HG_URL=file:$TESTTMP/a
558 558
559 559 txnclose hook: HG_BOOKMARK_MOVED=1
560 560 HG_BUNDLE2=1
561 561 HG_HOOKNAME=txnclose
562 562 HG_HOOKTYPE=txnclose
563 563 HG_SOURCE=push
564 564 HG_TXNID=TXN:$ID$
565 565 HG_TXNNAME=push
566 566 HG_URL=file:$TESTTMP/a
567 567
568 568 exporting bookmark foo
569 569 [1]
570 570 $ cd ../a
571 571
572 572 listkeys hook
573 573
574 574 $ cat >> .hg/hgrc <<EOF
575 575 > listkeys = sh -c "printenv.py --line listkeys"
576 576 > EOF
577 577 $ hg bookmark -r null bar
578 578 pretxnopen hook: HG_HOOKNAME=pretxnopen
579 579 HG_HOOKTYPE=pretxnopen
580 580 HG_TXNID=TXN:$ID$
581 581 HG_TXNNAME=bookmark
582 582
583 583 pretxnclose hook: HG_BOOKMARK_MOVED=1
584 584 HG_HOOKNAME=pretxnclose
585 585 HG_HOOKTYPE=pretxnclose
586 586 HG_PENDING=$TESTTMP/a
587 587 HG_TXNID=TXN:$ID$
588 588 HG_TXNNAME=bookmark
589 589
590 590 txnclose hook: HG_BOOKMARK_MOVED=1
591 591 HG_HOOKNAME=txnclose
592 592 HG_HOOKTYPE=txnclose
593 593 HG_TXNID=TXN:$ID$
594 594 HG_TXNNAME=bookmark
595 595
596 596 $ cd ../b
597 597 $ hg pull -B bar ../a
598 598 pulling from ../a
599 599 listkeys hook: HG_HOOKNAME=listkeys
600 600 HG_HOOKTYPE=listkeys
601 601 HG_NAMESPACE=bookmarks
602 602 HG_VALUES={'bar': '0000000000000000000000000000000000000000', 'foo': '0000000000000000000000000000000000000000'}
603 603
604 604 no changes found
605 605 adding remote bookmark bar
606 606 $ cd ../a
607 607
608 608 test that prepushkey can prevent incoming keys
609 609
610 610 $ cat >> .hg/hgrc <<EOF
611 611 > prepushkey = sh -c "printenv.py --line prepushkey.forbid 1"
612 612 > EOF
613 613 $ cd ../b
614 614 $ hg bookmark -r null baz
615 615 $ hg push -B baz ../a
616 616 pushing to ../a
617 617 searching for changes
618 618 listkeys hook: HG_HOOKNAME=listkeys
619 619 HG_HOOKTYPE=listkeys
620 620 HG_NAMESPACE=phases
621 621 HG_VALUES={'cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b': '1', 'publishing': 'True'}
622 622
623 623 listkeys hook: HG_HOOKNAME=listkeys
624 624 HG_HOOKTYPE=listkeys
625 625 HG_NAMESPACE=bookmarks
626 626 HG_VALUES={'bar': '0000000000000000000000000000000000000000', 'foo': '0000000000000000000000000000000000000000'}
627 627
628 628 no changes found
629 629 pretxnopen hook: HG_HOOKNAME=pretxnopen
630 630 HG_HOOKTYPE=pretxnopen
631 631 HG_TXNID=TXN:$ID$
632 632 HG_TXNNAME=push
633 633
634 634 prepushkey.forbid hook: HG_BUNDLE2=1
635 635 HG_HOOKNAME=prepushkey
636 636 HG_HOOKTYPE=prepushkey
637 637 HG_KEY=baz
638 638 HG_NAMESPACE=bookmarks
639 639 HG_NEW=0000000000000000000000000000000000000000
640 640 HG_PUSHKEYCOMPAT=1
641 641 HG_SOURCE=push
642 642 HG_TXNID=TXN:$ID$
643 643 HG_TXNNAME=push
644 644 HG_URL=file:$TESTTMP/a
645 645
646 646 abort: prepushkey hook exited with status 1
647 647 [255]
648 648 $ cd ../a
649 649
650 650 test that prelistkeys can prevent listing keys
651 651
652 652 $ cat >> .hg/hgrc <<EOF
653 653 > prelistkeys = sh -c "printenv.py --line prelistkeys.forbid 1"
654 654 > EOF
655 655 $ hg bookmark -r null quux
656 656 pretxnopen hook: HG_HOOKNAME=pretxnopen
657 657 HG_HOOKTYPE=pretxnopen
658 658 HG_TXNID=TXN:$ID$
659 659 HG_TXNNAME=bookmark
660 660
661 661 pretxnclose hook: HG_BOOKMARK_MOVED=1
662 662 HG_HOOKNAME=pretxnclose
663 663 HG_HOOKTYPE=pretxnclose
664 664 HG_PENDING=$TESTTMP/a
665 665 HG_TXNID=TXN:$ID$
666 666 HG_TXNNAME=bookmark
667 667
668 668 txnclose hook: HG_BOOKMARK_MOVED=1
669 669 HG_HOOKNAME=txnclose
670 670 HG_HOOKTYPE=txnclose
671 671 HG_TXNID=TXN:$ID$
672 672 HG_TXNNAME=bookmark
673 673
674 674 $ cd ../b
675 675 $ hg pull -B quux ../a
676 676 pulling from ../a
677 677 prelistkeys.forbid hook: HG_HOOKNAME=prelistkeys
678 678 HG_HOOKTYPE=prelistkeys
679 679 HG_NAMESPACE=bookmarks
680 680
681 681 abort: prelistkeys hook exited with status 1
682 682 [255]
683 683 $ cd ../a
684 684 $ rm .hg/hgrc
685 685
686 686 prechangegroup hook can prevent incoming changes
687 687
688 688 $ cd ../b
689 689 $ hg -q tip
690 690 3:07f3376c1e65
691 691 $ cat > .hg/hgrc <<EOF
692 692 > [hooks]
693 693 > prechangegroup.forbid = sh -c "printenv.py --line prechangegroup.forbid 1"
694 694 > EOF
695 695 $ hg pull ../a
696 696 pulling from ../a
697 697 searching for changes
698 698 prechangegroup.forbid hook: HG_HOOKNAME=prechangegroup.forbid
699 699 HG_HOOKTYPE=prechangegroup
700 700 HG_SOURCE=pull
701 701 HG_TXNID=TXN:$ID$
702 702 HG_TXNNAME=pull
703 703 file:/*/$TESTTMP/a (glob)
704 704 HG_URL=file:$TESTTMP/a
705 705
706 706 abort: prechangegroup.forbid hook exited with status 1
707 707 [255]
708 708
709 709 pretxnchangegroup hook can see incoming changes, can roll back txn,
710 710 incoming changes no longer there after
711 711
712 712 $ cat > .hg/hgrc <<EOF
713 713 > [hooks]
714 714 > pretxnchangegroup.forbid0 = hg tip -q
715 715 > pretxnchangegroup.forbid1 = sh -c "printenv.py --line pretxnchangegroup.forbid 1"
716 716 > EOF
717 717 $ hg pull ../a
718 718 pulling from ../a
719 719 searching for changes
720 720 adding changesets
721 721 adding manifests
722 722 adding file changes
723 723 4:539e4b31b6dc
724 724 pretxnchangegroup.forbid hook: HG_HOOKNAME=pretxnchangegroup.forbid1
725 725 HG_HOOKTYPE=pretxnchangegroup
726 726 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10
727 727 HG_NODE_LAST=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10
728 728 HG_PENDING=$TESTTMP/b
729 729 HG_SOURCE=pull
730 730 HG_TXNID=TXN:$ID$
731 731 HG_TXNNAME=pull
732 732 file:/*/$TESTTMP/a (glob)
733 733 HG_URL=file:$TESTTMP/a
734 734
735 735 transaction abort!
736 736 rollback completed
737 737 abort: pretxnchangegroup.forbid1 hook exited with status 1
738 738 [255]
739 739 $ hg -q tip
740 740 3:07f3376c1e65
741 741
742 742 outgoing hooks can see env vars
743 743
744 744 $ rm .hg/hgrc
745 745 $ cat > ../a/.hg/hgrc <<EOF
746 746 > [hooks]
747 747 > preoutgoing = sh -c "printenv.py --line preoutgoing"
748 748 > outgoing = sh -c "printenv.py --line outgoing"
749 749 > EOF
750 750 $ hg pull ../a
751 751 pulling from ../a
752 752 searching for changes
753 753 preoutgoing hook: HG_HOOKNAME=preoutgoing
754 754 HG_HOOKTYPE=preoutgoing
755 755 HG_SOURCE=pull
756 756
757 757 outgoing hook: HG_HOOKNAME=outgoing
758 758 HG_HOOKTYPE=outgoing
759 759 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10
760 760 HG_SOURCE=pull
761 761
762 762 adding changesets
763 763 adding manifests
764 764 adding file changes
765 765 adding remote bookmark quux
766 766 added 1 changesets with 1 changes to 1 files
767 767 new changesets 539e4b31b6dc
768 768 (run 'hg update' to get a working copy)
769 769 $ hg rollback
770 770 repository tip rolled back to revision 3 (undo pull)
771 771
772 772 preoutgoing hook can prevent outgoing changes
773 773
774 774 $ cat >> ../a/.hg/hgrc <<EOF
775 775 > preoutgoing.forbid = sh -c "printenv.py --line preoutgoing.forbid 1"
776 776 > EOF
777 777 $ hg pull ../a
778 778 pulling from ../a
779 779 searching for changes
780 780 preoutgoing hook: HG_HOOKNAME=preoutgoing
781 781 HG_HOOKTYPE=preoutgoing
782 782 HG_SOURCE=pull
783 783
784 784 preoutgoing.forbid hook: HG_HOOKNAME=preoutgoing.forbid
785 785 HG_HOOKTYPE=preoutgoing
786 786 HG_SOURCE=pull
787 787
788 788 abort: preoutgoing.forbid hook exited with status 1
789 789 [255]
790 790
791 791 outgoing hooks work for local clones
792 792
793 793 $ cd ..
794 794 $ cat > a/.hg/hgrc <<EOF
795 795 > [hooks]
796 796 > preoutgoing = sh -c "printenv.py --line preoutgoing"
797 797 > outgoing = sh -c "printenv.py --line outgoing"
798 798 > EOF
799 799 $ hg clone a c
800 800 preoutgoing hook: HG_HOOKNAME=preoutgoing
801 801 HG_HOOKTYPE=preoutgoing
802 802 HG_SOURCE=clone
803 803
804 804 outgoing hook: HG_HOOKNAME=outgoing
805 805 HG_HOOKTYPE=outgoing
806 806 HG_NODE=0000000000000000000000000000000000000000
807 807 HG_SOURCE=clone
808 808
809 809 updating to branch default
810 810 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
811 811 $ rm -rf c
812 812
813 813 preoutgoing hook can prevent outgoing changes for local clones
814 814
815 815 $ cat >> a/.hg/hgrc <<EOF
816 816 > preoutgoing.forbid = sh -c "printenv.py --line preoutgoing.forbid 1"
817 817 > EOF
818 818 $ hg clone a zzz
819 819 preoutgoing hook: HG_HOOKNAME=preoutgoing
820 820 HG_HOOKTYPE=preoutgoing
821 821 HG_SOURCE=clone
822 822
823 823 preoutgoing.forbid hook: HG_HOOKNAME=preoutgoing.forbid
824 824 HG_HOOKTYPE=preoutgoing
825 825 HG_SOURCE=clone
826 826
827 827 abort: preoutgoing.forbid hook exited with status 1
828 828 [255]
829 829
830 830 $ cd "$TESTTMP/b"
831 831
832 832 $ cat > hooktests.py <<EOF
833 833 > from __future__ import print_function
834 834 > from mercurial import (
835 835 > error,
836 836 > pycompat,
837 837 > )
838 838 >
839 839 > uncallable = 0
840 840 >
841 841 > def printargs(ui, args):
842 842 > a = list(pycompat.byteskwargs(args).items())
843 843 > a.sort()
844 844 > ui.write(b'hook args:\n')
845 845 > for k, v in a:
846 846 > ui.write(b' %s %s\n' % (k, v))
847 847 >
848 848 > def passhook(ui, repo, **args):
849 849 > printargs(ui, args)
850 850 >
851 851 > def failhook(ui, repo, **args):
852 852 > printargs(ui, args)
853 853 > return True
854 854 >
855 855 > class LocalException(Exception):
856 856 > pass
857 857 >
858 858 > def raisehook(**args):
859 859 > raise LocalException('exception from hook')
860 860 >
861 861 > def aborthook(**args):
862 862 > raise error.Abort(b'raise abort from hook')
863 863 >
864 864 > def brokenhook(**args):
865 865 > return 1 + {}
866 866 >
867 867 > def verbosehook(ui, **args):
868 868 > ui.note(b'verbose output from hook\n')
869 869 >
870 870 > def printtags(ui, repo, **args):
871 871 > ui.write(b'[%s]\n' % b', '.join(sorted(repo.tags())))
872 872 >
873 873 > class container(object):
874 874 > unreachable = 1
875 875 > EOF
876 876
877 877 $ cat > syntaxerror.py << NO_CHECK_EOF
878 878 > (foo
879 879 > NO_CHECK_EOF
880 880
881 881 test python hooks
882 882
883 883 #if windows
884 884 $ PYTHONPATH="$TESTTMP/b;$PYTHONPATH"
885 885 #else
886 886 $ PYTHONPATH="$TESTTMP/b:$PYTHONPATH"
887 887 #endif
888 888 $ export PYTHONPATH
889 889
890 890 $ echo '[hooks]' > ../a/.hg/hgrc
891 891 $ echo 'preoutgoing.broken = python:hooktests.brokenhook' >> ../a/.hg/hgrc
892 892 $ hg pull ../a 2>&1 | grep 'raised an exception'
893 893 error: preoutgoing.broken hook raised an exception: unsupported operand type(s) for +: 'int' and 'dict'
894 894
895 895 $ echo '[hooks]' > ../a/.hg/hgrc
896 896 $ echo 'preoutgoing.raise = python:hooktests.raisehook' >> ../a/.hg/hgrc
897 897 $ hg pull ../a 2>&1 | grep 'raised an exception'
898 898 error: preoutgoing.raise hook raised an exception: exception from hook
899 899
900 900 $ echo '[hooks]' > ../a/.hg/hgrc
901 901 $ echo 'preoutgoing.abort = python:hooktests.aborthook' >> ../a/.hg/hgrc
902 902 $ hg pull ../a
903 903 pulling from ../a
904 904 searching for changes
905 905 error: preoutgoing.abort hook failed: raise abort from hook
906 906 abort: raise abort from hook
907 907 [255]
908 908
909 909 $ echo '[hooks]' > ../a/.hg/hgrc
910 910 $ echo 'preoutgoing.fail = python:hooktests.failhook' >> ../a/.hg/hgrc
911 911 $ hg pull ../a
912 912 pulling from ../a
913 913 searching for changes
914 914 hook args:
915 915 hooktype preoutgoing
916 916 source pull
917 917 abort: preoutgoing.fail hook failed
918 918 [255]
919 919
920 920 $ echo '[hooks]' > ../a/.hg/hgrc
921 921 $ echo 'preoutgoing.uncallable = python:hooktests.uncallable' >> ../a/.hg/hgrc
922 922 $ hg pull ../a
923 923 pulling from ../a
924 924 searching for changes
925 925 abort: preoutgoing.uncallable hook is invalid: "hooktests.uncallable" is not callable
926 926 [255]
927 927
928 928 $ echo '[hooks]' > ../a/.hg/hgrc
929 929 $ echo 'preoutgoing.nohook = python:hooktests.nohook' >> ../a/.hg/hgrc
930 930 $ hg pull ../a
931 931 pulling from ../a
932 932 searching for changes
933 933 abort: preoutgoing.nohook hook is invalid: "hooktests.nohook" is not defined
934 934 [255]
935 935
936 936 $ echo '[hooks]' > ../a/.hg/hgrc
937 937 $ echo 'preoutgoing.nomodule = python:nomodule' >> ../a/.hg/hgrc
938 938 $ hg pull ../a
939 939 pulling from ../a
940 940 searching for changes
941 941 abort: preoutgoing.nomodule hook is invalid: "nomodule" not in a module
942 942 [255]
943 943
944 944 $ echo '[hooks]' > ../a/.hg/hgrc
945 945 $ echo 'preoutgoing.badmodule = python:nomodule.nowhere' >> ../a/.hg/hgrc
946 946 $ hg pull ../a
947 947 pulling from ../a
948 948 searching for changes
949 949 abort: preoutgoing.badmodule hook is invalid: import of "nomodule" failed
950 950 (run with --traceback for stack trace)
951 951 [255]
952 952
953 953 $ echo '[hooks]' > ../a/.hg/hgrc
954 954 $ echo 'preoutgoing.unreachable = python:hooktests.container.unreachable' >> ../a/.hg/hgrc
955 955 $ hg pull ../a
956 956 pulling from ../a
957 957 searching for changes
958 958 abort: preoutgoing.unreachable hook is invalid: import of "hooktests.container" failed
959 959 (run with --traceback for stack trace)
960 960 [255]
961 961
962 962 $ echo '[hooks]' > ../a/.hg/hgrc
963 963 $ echo 'preoutgoing.syntaxerror = python:syntaxerror.syntaxerror' >> ../a/.hg/hgrc
964 964 $ hg pull ../a
965 965 pulling from ../a
966 966 searching for changes
967 967 abort: preoutgoing.syntaxerror hook is invalid: import of "syntaxerror" failed
968 968 (run with --traceback for stack trace)
969 969 [255]
970 970
971 971 $ hg pull ../a --traceback 2>&1 | egrep 'pulling|searching|^exception|Traceback|SyntaxError|ImportError|ModuleNotFoundError|HookLoadError|abort'
972 972 pulling from ../a
973 973 searching for changes
974 974 exception from first failed import attempt:
975 975 Traceback (most recent call last):
976 976 SyntaxError: * (glob)
977 977 exception from second failed import attempt:
978 978 Traceback (most recent call last): (py3 !)
979 979 SyntaxError: * (glob) (py3 !)
980 980 Traceback (most recent call last):
981 981 ImportError: No module named hgext_syntaxerror (no-py3 !)
982 982 ImportError: No module named 'hgext_syntaxerror' (py3 no-py36 !)
983 983 ModuleNotFoundError: No module named 'hgext_syntaxerror' (py36 !)
984 984 Traceback (most recent call last):
985 985 SyntaxError: * (glob) (py3 !)
986 986 Traceback (most recent call last): (py3 !)
987 987 ImportError: No module named 'hgext_syntaxerror' (py3 no-py36 !)
988 988 ModuleNotFoundError: No module named 'hgext_syntaxerror' (py36 !)
989 989 Traceback (most recent call last): (py3 !)
990 990 HookLoadError: preoutgoing.syntaxerror hook is invalid: import of "syntaxerror" failed (no-py3 !)
991 mercurial.error.HookLoadError: b'preoutgoing.syntaxerror hook is invalid: import of "syntaxerror" failed' (py3 !)
991 mercurial.error.HookLoadError: preoutgoing.syntaxerror hook is invalid: import of "syntaxerror" failed (py3 !)
992 992 abort: preoutgoing.syntaxerror hook is invalid: import of "syntaxerror" failed
993 993
994 994 $ echo '[hooks]' > ../a/.hg/hgrc
995 995 $ echo 'preoutgoing.pass = python:hooktests.passhook' >> ../a/.hg/hgrc
996 996 $ hg pull ../a
997 997 pulling from ../a
998 998 searching for changes
999 999 hook args:
1000 1000 hooktype preoutgoing
1001 1001 source pull
1002 1002 adding changesets
1003 1003 adding manifests
1004 1004 adding file changes
1005 1005 adding remote bookmark quux
1006 1006 added 1 changesets with 1 changes to 1 files
1007 1007 new changesets 539e4b31b6dc
1008 1008 (run 'hg update' to get a working copy)
1009 1009
1010 1010 post- python hooks that fail to *run* don't cause an abort
1011 1011 $ rm ../a/.hg/hgrc
1012 1012 $ echo '[hooks]' > .hg/hgrc
1013 1013 $ echo 'post-pull.broken = python:hooktests.brokenhook' >> .hg/hgrc
1014 1014 $ hg pull ../a
1015 1015 pulling from ../a
1016 1016 searching for changes
1017 1017 no changes found
1018 1018 error: post-pull.broken hook raised an exception: unsupported operand type(s) for +: 'int' and 'dict'
1019 1019 (run with --traceback for stack trace)
1020 1020
1021 1021 but post- python hooks that fail to *load* do
1022 1022 $ echo '[hooks]' > .hg/hgrc
1023 1023 $ echo 'post-pull.nomodule = python:nomodule' >> .hg/hgrc
1024 1024 $ hg pull ../a
1025 1025 pulling from ../a
1026 1026 searching for changes
1027 1027 no changes found
1028 1028 abort: post-pull.nomodule hook is invalid: "nomodule" not in a module
1029 1029 [255]
1030 1030
1031 1031 $ echo '[hooks]' > .hg/hgrc
1032 1032 $ echo 'post-pull.badmodule = python:nomodule.nowhere' >> .hg/hgrc
1033 1033 $ hg pull ../a
1034 1034 pulling from ../a
1035 1035 searching for changes
1036 1036 no changes found
1037 1037 abort: post-pull.badmodule hook is invalid: import of "nomodule" failed
1038 1038 (run with --traceback for stack trace)
1039 1039 [255]
1040 1040
1041 1041 $ echo '[hooks]' > .hg/hgrc
1042 1042 $ echo 'post-pull.nohook = python:hooktests.nohook' >> .hg/hgrc
1043 1043 $ hg pull ../a
1044 1044 pulling from ../a
1045 1045 searching for changes
1046 1046 no changes found
1047 1047 abort: post-pull.nohook hook is invalid: "hooktests.nohook" is not defined
1048 1048 [255]
1049 1049
1050 1050 make sure --traceback works
1051 1051
1052 1052 $ echo '[hooks]' > .hg/hgrc
1053 1053 $ echo 'commit.abort = python:hooktests.aborthook' >> .hg/hgrc
1054 1054
1055 1055 $ echo aa > a
1056 1056 $ hg --traceback commit -d '0 0' -ma 2>&1 | grep '^Traceback'
1057 1057 Traceback (most recent call last):
1058 1058
1059 1059 $ cd ..
1060 1060 $ hg init c
1061 1061 $ cd c
1062 1062
1063 1063 $ cat > hookext.py <<EOF
1064 1064 > def autohook(ui, **args):
1065 1065 > ui.write(b'Automatically installed hook\n')
1066 1066 >
1067 1067 > def reposetup(ui, repo):
1068 1068 > repo.ui.setconfig(b"hooks", b"commit.auto", autohook)
1069 1069 > EOF
1070 1070 $ echo '[extensions]' >> .hg/hgrc
1071 1071 $ echo 'hookext = hookext.py' >> .hg/hgrc
1072 1072
1073 1073 $ touch foo
1074 1074 $ hg add foo
1075 1075 $ hg ci -d '0 0' -m 'add foo'
1076 1076 Automatically installed hook
1077 1077 $ echo >> foo
1078 1078 $ hg ci --debug -d '0 0' -m 'change foo'
1079 1079 committing files:
1080 1080 foo
1081 1081 committing manifest
1082 1082 committing changelog
1083 1083 updating the branch cache
1084 1084 committed changeset 1:52998019f6252a2b893452765fcb0a47351a5708
1085 1085 calling hook commit.auto: hgext_hookext.autohook
1086 1086 Automatically installed hook
1087 1087
1088 1088 $ hg showconfig hooks
1089 1089 hooks.commit.auto=<function autohook at *> (glob)
1090 1090
1091 1091 test python hook configured with python:[file]:[hook] syntax
1092 1092
1093 1093 $ cd ..
1094 1094 $ mkdir d
1095 1095 $ cd d
1096 1096 $ hg init repo
1097 1097 $ mkdir hooks
1098 1098
1099 1099 $ cd hooks
1100 1100 $ cat > testhooks.py <<EOF
1101 1101 > def testhook(ui, **args):
1102 1102 > ui.write(b'hook works\n')
1103 1103 > EOF
1104 1104 $ echo '[hooks]' > ../repo/.hg/hgrc
1105 1105 $ echo "pre-commit.test = python:`pwd`/testhooks.py:testhook" >> ../repo/.hg/hgrc
1106 1106
1107 1107 $ cd ../repo
1108 1108 $ hg commit -d '0 0'
1109 1109 hook works
1110 1110 nothing changed
1111 1111 [1]
1112 1112
1113 1113 $ echo '[hooks]' > .hg/hgrc
1114 1114 $ echo "update.ne = python:`pwd`/nonexistent.py:testhook" >> .hg/hgrc
1115 1115 $ echo "pre-identify.npmd = python:`pwd`/:no_python_module_dir" >> .hg/hgrc
1116 1116
1117 1117 $ hg up null
1118 1118 loading update.ne hook failed:
1119 1119 abort: $ENOENT$: '$TESTTMP/d/repo/nonexistent.py'
1120 1120 [255]
1121 1121
1122 1122 $ hg id
1123 1123 loading pre-identify.npmd hook failed:
1124 1124 abort: No module named repo! (no-py3 !)
1125 1125 abort: No module named 'repo'! (py3 !)
1126 1126 [255]
1127 1127
1128 1128 $ cd ../../b
1129 1129
1130 1130 make sure --traceback works on hook import failure
1131 1131
1132 1132 $ cat > importfail.py <<EOF
1133 1133 > import somebogusmodule
1134 1134 > # dereference something in the module to force demandimport to load it
1135 1135 > somebogusmodule.whatever
1136 1136 > EOF
1137 1137
1138 1138 $ echo '[hooks]' > .hg/hgrc
1139 1139 $ echo 'precommit.importfail = python:importfail.whatever' >> .hg/hgrc
1140 1140
1141 1141 $ echo a >> a
1142 1142 $ hg --traceback commit -ma 2>&1 | egrep '^exception|ImportError|ModuleNotFoundError|Traceback|HookLoadError|abort'
1143 1143 exception from first failed import attempt:
1144 1144 Traceback (most recent call last):
1145 1145 ImportError: No module named somebogusmodule (no-py3 !)
1146 1146 ImportError: No module named 'somebogusmodule' (py3 no-py36 !)
1147 1147 ModuleNotFoundError: No module named 'somebogusmodule' (py36 !)
1148 1148 exception from second failed import attempt:
1149 1149 Traceback (most recent call last): (py3 !)
1150 1150 ImportError: No module named 'somebogusmodule' (py3 no-py36 !)
1151 1151 ModuleNotFoundError: No module named 'somebogusmodule' (py36 !)
1152 1152 Traceback (most recent call last): (py3 !)
1153 1153 ImportError: No module named 'hgext_importfail' (py3 no-py36 !)
1154 1154 ModuleNotFoundError: No module named 'hgext_importfail' (py36 !)
1155 1155 Traceback (most recent call last): (py3 !)
1156 1156 ImportError: No module named 'somebogusmodule' (py3 no-py36 !)
1157 1157 ModuleNotFoundError: No module named 'somebogusmodule' (py36 !)
1158 1158 Traceback (most recent call last):
1159 1159 ImportError: No module named hgext_importfail (no-py3 !)
1160 1160 ImportError: No module named 'hgext_importfail' (py3 no-py36 !)
1161 1161 ModuleNotFoundError: No module named 'hgext_importfail' (py36 !)
1162 1162 Traceback (most recent call last):
1163 1163 HookLoadError: precommit.importfail hook is invalid: import of "importfail" failed (no-py3 !)
1164 mercurial.error.HookLoadError: b'precommit.importfail hook is invalid: import of "importfail" failed' (py3 !)
1164 mercurial.error.HookLoadError: precommit.importfail hook is invalid: import of "importfail" failed (py3 !)
1165 1165 abort: precommit.importfail hook is invalid: import of "importfail" failed
1166 1166
1167 1167 Issue1827: Hooks Update & Commit not completely post operation
1168 1168
1169 1169 commit and update hooks should run after command completion. The largefiles
1170 1170 use demonstrates a recursive wlock, showing the hook doesn't run until the
1171 1171 final release (and dirstate flush).
1172 1172
1173 1173 $ echo '[hooks]' > .hg/hgrc
1174 1174 $ echo 'commit = hg id' >> .hg/hgrc
1175 1175 $ echo 'update = hg id' >> .hg/hgrc
1176 1176 $ echo bb > a
1177 1177 $ hg ci -ma
1178 1178 223eafe2750c tip
1179 1179 $ hg up 0 --config extensions.largefiles=
1180 1180 The fsmonitor extension is incompatible with the largefiles extension and has been disabled. (fsmonitor !)
1181 1181 cb9a9f314b8b
1182 1182 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1183 1183
1184 1184 make sure --verbose (and --quiet/--debug etc.) are propagated to the local ui
1185 1185 that is passed to pre/post hooks
1186 1186
1187 1187 $ echo '[hooks]' > .hg/hgrc
1188 1188 $ echo 'pre-identify = python:hooktests.verbosehook' >> .hg/hgrc
1189 1189 $ hg id
1190 1190 cb9a9f314b8b
1191 1191 $ hg id --verbose
1192 1192 calling hook pre-identify: hooktests.verbosehook
1193 1193 verbose output from hook
1194 1194 cb9a9f314b8b
1195 1195
1196 1196 Ensure hooks can be prioritized
1197 1197
1198 1198 $ echo '[hooks]' > .hg/hgrc
1199 1199 $ echo 'pre-identify.a = python:hooktests.verbosehook' >> .hg/hgrc
1200 1200 $ echo 'pre-identify.b = python:hooktests.verbosehook' >> .hg/hgrc
1201 1201 $ echo 'priority.pre-identify.b = 1' >> .hg/hgrc
1202 1202 $ echo 'pre-identify.c = python:hooktests.verbosehook' >> .hg/hgrc
1203 1203 $ hg id --verbose
1204 1204 calling hook pre-identify.b: hooktests.verbosehook
1205 1205 verbose output from hook
1206 1206 calling hook pre-identify.a: hooktests.verbosehook
1207 1207 verbose output from hook
1208 1208 calling hook pre-identify.c: hooktests.verbosehook
1209 1209 verbose output from hook
1210 1210 cb9a9f314b8b
1211 1211
1212 1212 new tags must be visible in pretxncommit (issue3210)
1213 1213
1214 1214 $ echo 'pretxncommit.printtags = python:hooktests.printtags' >> .hg/hgrc
1215 1215 $ hg tag -f foo
1216 1216 [a, foo, tip]
1217 1217
1218 1218 post-init hooks must not crash (issue4983)
1219 1219 This also creates the `to` repo for the next test block.
1220 1220
1221 1221 $ cd ..
1222 1222 $ cat << EOF >> hgrc-with-post-init-hook
1223 1223 > [hooks]
1224 1224 > post-init = sh -c "printenv.py --line post-init"
1225 1225 > EOF
1226 1226 $ HGRCPATH=hgrc-with-post-init-hook hg init to
1227 1227 post-init hook: HG_ARGS=init to
1228 1228 HG_HOOKNAME=post-init
1229 1229 HG_HOOKTYPE=post-init
1230 1230 HG_OPTS={'insecure': None, 'remotecmd': '', 'ssh': ''}
1231 1231 HG_PATS=['to']
1232 1232 HG_RESULT=0
1233 1233
1234 1234
1235 1235 new commits must be visible in pretxnchangegroup (issue3428)
1236 1236
1237 1237 $ echo '[hooks]' >> to/.hg/hgrc
1238 1238 $ echo 'prechangegroup = hg --traceback tip' >> to/.hg/hgrc
1239 1239 $ echo 'pretxnchangegroup = hg --traceback tip' >> to/.hg/hgrc
1240 1240 $ echo a >> to/a
1241 1241 $ hg --cwd to ci -Ama
1242 1242 adding a
1243 1243 $ hg clone to from
1244 1244 updating to branch default
1245 1245 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1246 1246 $ echo aa >> from/a
1247 1247 $ hg --cwd from ci -mb
1248 1248 $ hg --cwd from push
1249 1249 pushing to $TESTTMP/to
1250 1250 searching for changes
1251 1251 changeset: 0:cb9a9f314b8b
1252 1252 tag: tip
1253 1253 user: test
1254 1254 date: Thu Jan 01 00:00:00 1970 +0000
1255 1255 summary: a
1256 1256
1257 1257 adding changesets
1258 1258 adding manifests
1259 1259 adding file changes
1260 1260 changeset: 1:9836a07b9b9d
1261 1261 tag: tip
1262 1262 user: test
1263 1263 date: Thu Jan 01 00:00:00 1970 +0000
1264 1264 summary: b
1265 1265
1266 1266 added 1 changesets with 1 changes to 1 files
1267 1267
1268 1268 pretxnclose hook failure should abort the transaction
1269 1269
1270 1270 $ hg init txnfailure
1271 1271 $ cd txnfailure
1272 1272 $ touch a && hg commit -Aqm a
1273 1273 $ cat >> .hg/hgrc <<EOF
1274 1274 > [hooks]
1275 1275 > pretxnclose.error = exit 1
1276 1276 > EOF
1277 1277 $ hg strip -r 0 --config extensions.strip=
1278 1278 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
1279 1279 saved backup bundle to * (glob)
1280 1280 transaction abort!
1281 1281 rollback completed
1282 1282 strip failed, backup bundle stored in * (glob)
1283 1283 abort: pretxnclose.error hook exited with status 1
1284 1284 [255]
1285 1285 $ hg recover
1286 1286 no interrupted transaction available
1287 1287 [1]
1288 1288 $ cd ..
1289 1289
1290 1290 check whether HG_PENDING makes pending changes only in related
1291 1291 repositories visible to an external hook.
1292 1292
1293 1293 (emulate a transaction running concurrently by copied
1294 1294 .hg/store/00changelog.i.a in subsequent test)
1295 1295
1296 1296 $ cat > $TESTTMP/savepending.sh <<EOF
1297 1297 > cp .hg/store/00changelog.i.a .hg/store/00changelog.i.a.saved
1298 1298 > exit 1 # to avoid adding new revision for subsequent tests
1299 1299 > EOF
1300 1300 $ cd a
1301 1301 $ hg tip -q
1302 1302 4:539e4b31b6dc
1303 1303 $ hg --config hooks.pretxnclose="sh $TESTTMP/savepending.sh" commit -m "invisible"
1304 1304 transaction abort!
1305 1305 rollback completed
1306 1306 abort: pretxnclose hook exited with status 1
1307 1307 [255]
1308 1308 $ cp .hg/store/00changelog.i.a.saved .hg/store/00changelog.i.a
1309 1309
1310 1310 (check (in)visibility of new changeset while transaction running in
1311 1311 repo)
1312 1312
1313 1313 $ cat > $TESTTMP/checkpending.sh <<EOF
1314 1314 > echo '@a'
1315 1315 > hg -R "$TESTTMP/a" tip -q
1316 1316 > echo '@a/nested'
1317 1317 > hg -R "$TESTTMP/a/nested" tip -q
1318 1318 > exit 1 # to avoid adding new revision for subsequent tests
1319 1319 > EOF
1320 1320 $ hg init nested
1321 1321 $ cd nested
1322 1322 $ echo a > a
1323 1323 $ hg add a
1324 1324 $ hg --config hooks.pretxnclose="sh $TESTTMP/checkpending.sh" commit -m '#0'
1325 1325 @a
1326 1326 4:539e4b31b6dc
1327 1327 @a/nested
1328 1328 0:bf5e395ced2c
1329 1329 transaction abort!
1330 1330 rollback completed
1331 1331 abort: pretxnclose hook exited with status 1
1332 1332 [255]
1333 1333
1334 1334 Hook from untrusted hgrc are reported as failure
1335 1335 ================================================
1336 1336
1337 1337 $ cat << EOF > $TESTTMP/untrusted.py
1338 1338 > from mercurial import scmutil, util
1339 1339 > def uisetup(ui):
1340 1340 > class untrustedui(ui.__class__):
1341 1341 > def _trusted(self, fp, f):
1342 1342 > if util.normpath(fp.name).endswith(b'untrusted/.hg/hgrc'):
1343 1343 > return False
1344 1344 > return super(untrustedui, self)._trusted(fp, f)
1345 1345 > ui.__class__ = untrustedui
1346 1346 > EOF
1347 1347 $ cat << EOF >> $HGRCPATH
1348 1348 > [extensions]
1349 1349 > untrusted=$TESTTMP/untrusted.py
1350 1350 > EOF
1351 1351 $ hg init untrusted
1352 1352 $ cd untrusted
1353 1353
1354 1354 Non-blocking hook
1355 1355 -----------------
1356 1356
1357 1357 $ cat << EOF >> .hg/hgrc
1358 1358 > [hooks]
1359 1359 > txnclose.testing=echo txnclose hook called
1360 1360 > EOF
1361 1361 $ touch a && hg commit -Aqm a
1362 1362 warning: untrusted hook txnclose.testing not executed
1363 1363 $ hg log
1364 1364 changeset: 0:3903775176ed
1365 1365 tag: tip
1366 1366 user: test
1367 1367 date: Thu Jan 01 00:00:00 1970 +0000
1368 1368 summary: a
1369 1369
1370 1370
1371 1371 Non-blocking hook
1372 1372 -----------------
1373 1373
1374 1374 $ cat << EOF >> .hg/hgrc
1375 1375 > [hooks]
1376 1376 > pretxnclose.testing=echo pre-txnclose hook called
1377 1377 > EOF
1378 1378 $ touch b && hg commit -Aqm a
1379 1379 transaction abort!
1380 1380 rollback completed
1381 1381 abort: untrusted hook pretxnclose.testing not executed
1382 1382 (see 'hg help config.trusted')
1383 1383 [255]
1384 1384 $ hg log
1385 1385 changeset: 0:3903775176ed
1386 1386 tag: tip
1387 1387 user: test
1388 1388 date: Thu Jan 01 00:00:00 1970 +0000
1389 1389 summary: a
1390 1390
@@ -1,508 +1,508 b''
1 1 #require serve no-reposimplestore no-chg
2 2
3 3 $ cat >> $HGRCPATH <<EOF
4 4 > [extensions]
5 5 > lfs=
6 6 > [lfs]
7 7 > track=all()
8 8 > [web]
9 9 > push_ssl = False
10 10 > allow-push = *
11 11 > EOF
12 12
13 13 Serving LFS files can experimentally be turned off. The long term solution is
14 14 to support the 'verify' action in both client and server, so that the server can
15 15 tell the client to store files elsewhere.
16 16
17 17 $ hg init server
18 18 $ hg --config "lfs.usercache=$TESTTMP/servercache" \
19 19 > --config experimental.lfs.serve=False -R server serve -d \
20 20 > -p $HGPORT --pid-file=hg.pid -A $TESTTMP/access.log -E $TESTTMP/errors.log
21 21 $ cat hg.pid >> $DAEMON_PIDS
22 22
23 23 Uploads fail...
24 24
25 25 $ hg init client
26 26 $ echo 'this-is-an-lfs-file' > client/lfs.bin
27 27 $ hg -R client ci -Am 'initial commit'
28 28 adding lfs.bin
29 29 $ hg -R client push http://localhost:$HGPORT
30 30 pushing to http://localhost:$HGPORT/
31 31 searching for changes
32 32 abort: LFS HTTP error: HTTP Error 400: no such method: .git!
33 33 (check that lfs serving is enabled on http://localhost:$HGPORT/.git/info/lfs and "upload" is supported)
34 34 [255]
35 35
36 36 ... so do a local push to make the data available. Remove the blob from the
37 37 default cache, so it attempts to download.
38 38 $ hg --config "lfs.usercache=$TESTTMP/servercache" \
39 39 > --config "lfs.url=null://" \
40 40 > -R client push -q server
41 41 $ mv `hg config lfs.usercache` $TESTTMP/servercache
42 42
43 43 Downloads fail...
44 44
45 45 $ hg clone http://localhost:$HGPORT httpclone
46 46 (remote is using large file support (lfs); lfs will be enabled for this repository)
47 47 requesting all changes
48 48 adding changesets
49 49 adding manifests
50 50 adding file changes
51 51 added 1 changesets with 1 changes to 1 files
52 52 new changesets 525251863cad
53 53 updating to branch default
54 54 abort: LFS HTTP error: HTTP Error 400: no such method: .git!
55 55 (check that lfs serving is enabled on http://localhost:$HGPORT/.git/info/lfs and "download" is supported)
56 56 [255]
57 57
58 58 $ "$PYTHON" $RUNTESTDIR/killdaemons.py $DAEMON_PIDS
59 59
60 60 $ cat $TESTTMP/access.log $TESTTMP/errors.log
61 61 $LOCALIP - - [$LOGDATE$] "GET /?cmd=capabilities HTTP/1.1" 200 - (glob)
62 62 $LOCALIP - - [$LOGDATE$] "GET /?cmd=batch HTTP/1.1" 200 - x-hgarg-1:cmds=heads+%3Bknown+nodes%3D525251863cad618e55d483555f3d00a2ca99597e x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull (glob)
63 63 $LOCALIP - - [$LOGDATE$] "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=phases x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull (glob)
64 64 $LOCALIP - - [$LOGDATE$] "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=bookmarks x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull (glob)
65 65 $LOCALIP - - [$LOGDATE$] "POST /.git/info/lfs/objects/batch HTTP/1.1" 400 - (glob)
66 66 $LOCALIP - - [$LOGDATE$] "GET /?cmd=capabilities HTTP/1.1" 200 - (glob)
67 67 $LOCALIP - - [$LOGDATE$] "GET /?cmd=batch HTTP/1.1" 200 - x-hgarg-1:cmds=heads+%3Bknown+nodes%3D x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull (glob)
68 68 $LOCALIP - - [$LOGDATE$] "GET /?cmd=getbundle HTTP/1.1" 200 - x-hgarg-1:bookmarks=1&bundlecaps=HG20%2Cbundle2%3DHG20%250Abookmarks%250Achangegroup%253D01%252C02%252C03%250Adigests%253Dmd5%252Csha1%252Csha512%250Aerror%253Dabort%252Cunsupportedcontent%252Cpushraced%252Cpushkey%250Ahgtagsfnodes%250Alistkeys%250Aphases%253Dheads%250Apushkey%250Aremote-changegroup%253Dhttp%252Chttps%250Arev-branch-cache%250Astream%253Dv2&cg=1&common=0000000000000000000000000000000000000000&heads=525251863cad618e55d483555f3d00a2ca99597e&listkeys=bookmarks&phases=1 x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull (glob)
69 69 $LOCALIP - - [$LOGDATE$] "POST /.git/info/lfs/objects/batch HTTP/1.1" 400 - (glob)
70 70
71 71 $ rm -f $TESTTMP/access.log $TESTTMP/errors.log
72 72 $ hg --config "lfs.usercache=$TESTTMP/servercache" -R server serve -d \
73 73 > -p $HGPORT --pid-file=hg.pid --prefix=subdir/mount/point \
74 74 > -A $TESTTMP/access.log -E $TESTTMP/errors.log
75 75 $ cat hg.pid >> $DAEMON_PIDS
76 76
77 77 Reasonable hint for a misconfigured blob server
78 78
79 79 $ hg -R httpclone update default --config lfs.url=http://localhost:$HGPORT/missing
80 80 abort: LFS HTTP error: HTTP Error 404: Not Found!
81 81 (the "lfs.url" config may be used to override http://localhost:$HGPORT/missing)
82 82 [255]
83 83
84 84 $ hg -R httpclone update default --config lfs.url=http://localhost:$HGPORT2/missing
85 85 abort: LFS error: *onnection *refused*! (glob) (?)
86 86 abort: LFS error: $EADDRNOTAVAIL$! (glob) (?)
87 87 abort: LFS error: No route to host! (?)
88 88 (the "lfs.url" config may be used to override http://localhost:$HGPORT2/missing)
89 89 [255]
90 90
91 91 Blob URIs are correct when --prefix is used
92 92
93 93 $ hg clone --debug http://localhost:$HGPORT/subdir/mount/point cloned2
94 94 using http://localhost:$HGPORT/subdir/mount/point
95 95 sending capabilities command
96 96 (remote is using large file support (lfs); lfs will be enabled for this repository)
97 97 query 1; heads
98 98 sending batch command
99 99 requesting all changes
100 100 sending getbundle command
101 101 bundle2-input-bundle: with-transaction
102 102 bundle2-input-part: "changegroup" (params: 1 mandatory 1 advisory) supported
103 103 adding changesets
104 104 add changeset 525251863cad
105 105 adding manifests
106 106 adding file changes
107 107 adding lfs.bin revisions
108 108 bundle2-input-part: total payload size 648
109 109 bundle2-input-part: "listkeys" (params: 1 mandatory) supported
110 110 bundle2-input-part: "phase-heads" supported
111 111 bundle2-input-part: total payload size 24
112 112 bundle2-input-part: "cache:rev-branch-cache" (advisory) supported
113 113 bundle2-input-part: total payload size 39
114 114 bundle2-input-bundle: 4 parts total
115 115 checking for updated bookmarks
116 116 updating the branch cache
117 117 added 1 changesets with 1 changes to 1 files
118 118 new changesets 525251863cad
119 119 updating to branch default
120 120 resolving manifests
121 121 branchmerge: False, force: False, partial: False
122 122 ancestor: 000000000000, local: 000000000000+, remote: 525251863cad
123 123 lfs: assuming remote store: http://localhost:$HGPORT/subdir/mount/point/.git/info/lfs
124 124 Status: 200
125 125 Content-Length: 371
126 126 Content-Type: application/vnd.git-lfs+json
127 127 Date: $HTTP_DATE$
128 128 Server: testing stub value
129 129 {
130 130 "objects": [
131 131 {
132 132 "actions": {
133 133 "download": {
134 134 "expires_at": "$ISO_8601_DATE_TIME$"
135 135 "header": {
136 136 "Accept": "application/vnd.git-lfs"
137 137 }
138 138 "href": "http://localhost:$HGPORT/subdir/mount/point/.hg/lfs/objects/f03217a32529a28a42d03b1244fe09b6e0f9fd06d7b966d4d50567be2abe6c0e"
139 139 }
140 140 }
141 141 "oid": "f03217a32529a28a42d03b1244fe09b6e0f9fd06d7b966d4d50567be2abe6c0e"
142 142 "size": 20
143 143 }
144 144 ]
145 145 "transfer": "basic"
146 146 }
147 147 lfs: downloading f03217a32529a28a42d03b1244fe09b6e0f9fd06d7b966d4d50567be2abe6c0e (20 bytes)
148 148 Status: 200
149 149 Content-Length: 20
150 150 Content-Type: application/octet-stream
151 151 Date: $HTTP_DATE$
152 152 Server: testing stub value
153 153 lfs: adding f03217a32529a28a42d03b1244fe09b6e0f9fd06d7b966d4d50567be2abe6c0e to the usercache
154 154 lfs: processed: f03217a32529a28a42d03b1244fe09b6e0f9fd06d7b966d4d50567be2abe6c0e
155 155 lfs: downloaded 1 files (20 bytes)
156 156 lfs.bin: remote created -> g
157 157 getting lfs.bin
158 158 lfs: found f03217a32529a28a42d03b1244fe09b6e0f9fd06d7b966d4d50567be2abe6c0e in the local lfs store
159 159 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
160 160 (sent 3 HTTP requests and * bytes; received * bytes in responses) (glob)
161 161
162 162 $ "$PYTHON" $RUNTESTDIR/killdaemons.py $DAEMON_PIDS
163 163
164 164 $ cat $TESTTMP/access.log $TESTTMP/errors.log
165 165 $LOCALIP - - [$LOGDATE$] "POST /missing/objects/batch HTTP/1.1" 404 - (glob)
166 166 $LOCALIP - - [$LOGDATE$] "GET /subdir/mount/point?cmd=capabilities HTTP/1.1" 200 - (glob)
167 167 $LOCALIP - - [$LOGDATE$] "GET /subdir/mount/point?cmd=batch HTTP/1.1" 200 - x-hgarg-1:cmds=heads+%3Bknown+nodes%3D x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull (glob)
168 168 $LOCALIP - - [$LOGDATE$] "GET /subdir/mount/point?cmd=getbundle HTTP/1.1" 200 - x-hgarg-1:bookmarks=1&bundlecaps=HG20%2Cbundle2%3DHG20%250Abookmarks%250Achangegroup%253D01%252C02%252C03%250Adigests%253Dmd5%252Csha1%252Csha512%250Aerror%253Dabort%252Cunsupportedcontent%252Cpushraced%252Cpushkey%250Ahgtagsfnodes%250Alistkeys%250Aphases%253Dheads%250Apushkey%250Aremote-changegroup%253Dhttp%252Chttps%250Arev-branch-cache%250Astream%253Dv2&cg=1&common=0000000000000000000000000000000000000000&heads=525251863cad618e55d483555f3d00a2ca99597e&listkeys=bookmarks&phases=1 x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull (glob)
169 169 $LOCALIP - - [$LOGDATE$] "POST /subdir/mount/point/.git/info/lfs/objects/batch HTTP/1.1" 200 - (glob)
170 170 $LOCALIP - - [$LOGDATE$] "GET /subdir/mount/point/.hg/lfs/objects/f03217a32529a28a42d03b1244fe09b6e0f9fd06d7b966d4d50567be2abe6c0e HTTP/1.1" 200 - (glob)
171 171
172 172 Blobs that already exist in the usercache are linked into the repo store, even
173 173 though the client doesn't send the blob.
174 174
175 175 $ hg init server2
176 176 $ hg --config "lfs.usercache=$TESTTMP/servercache" -R server2 serve -d \
177 177 > -p $HGPORT --pid-file=hg.pid \
178 178 > -A $TESTTMP/access.log -E $TESTTMP/errors.log
179 179 $ cat hg.pid >> $DAEMON_PIDS
180 180
181 181 $ hg --config "lfs.usercache=$TESTTMP/servercache" -R cloned2 --debug \
182 182 > push http://localhost:$HGPORT | grep '^[{} ]'
183 183 {
184 184 "objects": [
185 185 {
186 186 "oid": "f03217a32529a28a42d03b1244fe09b6e0f9fd06d7b966d4d50567be2abe6c0e"
187 187 "size": 20
188 188 }
189 189 ]
190 190 "transfer": "basic"
191 191 }
192 192 $ find server2/.hg/store/lfs/objects | sort
193 193 server2/.hg/store/lfs/objects
194 194 server2/.hg/store/lfs/objects/f0
195 195 server2/.hg/store/lfs/objects/f0/3217a32529a28a42d03b1244fe09b6e0f9fd06d7b966d4d50567be2abe6c0e
196 196 $ "$PYTHON" $RUNTESTDIR/killdaemons.py $DAEMON_PIDS
197 197 $ cat $TESTTMP/errors.log
198 198
199 199 $ cat >> $TESTTMP/lfsstoreerror.py <<EOF
200 200 > import errno
201 201 > from hgext.lfs import blobstore
202 202 >
203 203 > _numverifies = 0
204 204 > _readerr = True
205 205 >
206 206 > def reposetup(ui, repo):
207 207 > # Nothing to do with a remote repo
208 208 > if not repo.local():
209 209 > return
210 210 >
211 211 > store = repo.svfs.lfslocalblobstore
212 212 > class badstore(store.__class__):
213 213 > def download(self, oid, src):
214 214 > '''Called in the server to handle reading from the client in a
215 215 > PUT request.'''
216 216 > origread = src.read
217 217 > def _badread(nbytes):
218 218 > # Simulate bad data/checksum failure from the client
219 219 > return b'0' * len(origread(nbytes))
220 220 > src.read = _badread
221 221 > super(badstore, self).download(oid, src)
222 222 >
223 223 > def _read(self, vfs, oid, verify):
224 224 > '''Called in the server to read data for a GET request, and then
225 225 > calls self._verify() on it before returning.'''
226 226 > global _readerr
227 227 > # One time simulation of a read error
228 228 > if _readerr:
229 229 > _readerr = False
230 230 > raise IOError(errno.EIO, r'%s: I/O error' % oid.decode("utf-8"))
231 231 > # Simulate corrupt content on client download
232 232 > blobstore._verify(oid, b'dummy content')
233 233 >
234 234 > def verify(self, oid):
235 235 > '''Called in the server to populate the Batch API response,
236 236 > letting the client re-upload if the file is corrupt.'''
237 237 > # Fail verify in Batch API for one clone command and one push
238 238 > # command with an IOError. Then let it through to access other
239 239 > # functions. Checksum failure is tested elsewhere.
240 240 > global _numverifies
241 241 > _numverifies += 1
242 242 > if _numverifies <= 2:
243 243 > raise IOError(errno.EIO, r'%s: I/O error' % oid.decode("utf-8"))
244 244 > return super(badstore, self).verify(oid)
245 245 >
246 246 > store.__class__ = badstore
247 247 > EOF
248 248
249 249 $ rm -rf `hg config lfs.usercache`
250 250 $ rm -f $TESTTMP/access.log $TESTTMP/errors.log
251 251 $ hg --config "lfs.usercache=$TESTTMP/servercache" \
252 252 > --config extensions.lfsstoreerror=$TESTTMP/lfsstoreerror.py \
253 253 > -R server serve -d \
254 254 > -p $HGPORT1 --pid-file=hg.pid -A $TESTTMP/access.log -E $TESTTMP/errors.log
255 255 $ cat hg.pid >> $DAEMON_PIDS
256 256
257 257 Test an I/O error in localstore.verify() (Batch API) with GET
258 258
259 259 $ hg clone http://localhost:$HGPORT1 httpclone2
260 260 (remote is using large file support (lfs); lfs will be enabled for this repository)
261 261 requesting all changes
262 262 adding changesets
263 263 adding manifests
264 264 adding file changes
265 265 added 1 changesets with 1 changes to 1 files
266 266 new changesets 525251863cad
267 267 updating to branch default
268 268 abort: LFS server error for "lfs.bin": Internal server error!
269 269 [255]
270 270
271 271 Test an I/O error in localstore.verify() (Batch API) with PUT
272 272
273 273 $ echo foo > client/lfs.bin
274 274 $ hg -R client ci -m 'mod lfs'
275 275 $ hg -R client push http://localhost:$HGPORT1
276 276 pushing to http://localhost:$HGPORT1/
277 277 searching for changes
278 278 abort: LFS server error for "unknown": Internal server error!
279 279 [255]
280 280 TODO: figure out how to associate the file name in the error above
281 281
282 282 Test a bad checksum sent by the client in the transfer API
283 283
284 284 $ hg -R client push http://localhost:$HGPORT1
285 285 pushing to http://localhost:$HGPORT1/
286 286 searching for changes
287 287 abort: LFS HTTP error: HTTP Error 422: corrupt blob (oid=b5bb9d8014a0f9b1d61e21e796d78dccdf1352f23cd32812f4850b878ae4944c, action=upload)!
288 288 [255]
289 289
290 290 $ echo 'test lfs file' > server/lfs3.bin
291 291 $ hg --config experimental.lfs.disableusercache=True \
292 292 > -R server ci -Aqm 'another lfs file'
293 293 $ hg -R client pull -q http://localhost:$HGPORT1
294 294
295 295 Test an I/O error during the processing of the GET request
296 296
297 297 $ hg --config lfs.url=http://localhost:$HGPORT1/.git/info/lfs \
298 298 > -R client update -r tip
299 299 abort: LFS HTTP error: HTTP Error 500: Internal Server Error (oid=276f73cfd75f9fb519810df5f5d96d6594ca2521abd86cbcd92122f7d51a1f3d, action=download)!
300 300 [255]
301 301
302 302 Test a checksum failure during the processing of the GET request
303 303
304 304 $ hg --config lfs.url=http://localhost:$HGPORT1/.git/info/lfs \
305 305 > -R client update -r tip
306 306 abort: LFS HTTP error: HTTP Error 422: corrupt blob (oid=276f73cfd75f9fb519810df5f5d96d6594ca2521abd86cbcd92122f7d51a1f3d, action=download)!
307 307 [255]
308 308
309 309 $ "$PYTHON" $RUNTESTDIR/killdaemons.py $DAEMON_PIDS
310 310
311 311 $ cat $TESTTMP/access.log
312 312 $LOCALIP - - [$LOGDATE$] "GET /?cmd=capabilities HTTP/1.1" 200 - (glob)
313 313 $LOCALIP - - [$LOGDATE$] "GET /?cmd=batch HTTP/1.1" 200 - x-hgarg-1:cmds=heads+%3Bknown+nodes%3D x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull (glob)
314 314 $LOCALIP - - [$LOGDATE$] "GET /?cmd=getbundle HTTP/1.1" 200 - x-hgarg-1:bookmarks=1&bundlecaps=HG20%2Cbundle2%3DHG20%250Abookmarks%250Achangegroup%253D01%252C02%252C03%250Adigests%253Dmd5%252Csha1%252Csha512%250Aerror%253Dabort%252Cunsupportedcontent%252Cpushraced%252Cpushkey%250Ahgtagsfnodes%250Alistkeys%250Aphases%253Dheads%250Apushkey%250Aremote-changegroup%253Dhttp%252Chttps%250Arev-branch-cache%250Astream%253Dv2&cg=1&common=0000000000000000000000000000000000000000&heads=525251863cad618e55d483555f3d00a2ca99597e&listkeys=bookmarks&phases=1 x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull (glob)
315 315 $LOCALIP - - [$LOGDATE$] "POST /.git/info/lfs/objects/batch HTTP/1.1" 200 - (glob)
316 316 $LOCALIP - - [$LOGDATE$] "GET /?cmd=capabilities HTTP/1.1" 200 - (glob)
317 317 $LOCALIP - - [$LOGDATE$] "GET /?cmd=batch HTTP/1.1" 200 - x-hgarg-1:cmds=heads+%3Bknown+nodes%3D392c05922088bacf8e68a6939b480017afbf245d x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull (glob)
318 318 $LOCALIP - - [$LOGDATE$] "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=phases x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull (glob)
319 319 $LOCALIP - - [$LOGDATE$] "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=bookmarks x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull (glob)
320 320 $LOCALIP - - [$LOGDATE$] "GET /?cmd=branchmap HTTP/1.1" 200 - x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull (glob)
321 321 $LOCALIP - - [$LOGDATE$] "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=bookmarks x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull (glob)
322 322 $LOCALIP - - [$LOGDATE$] "POST /.git/info/lfs/objects/batch HTTP/1.1" 200 - (glob)
323 323 $LOCALIP - - [$LOGDATE$] "GET /?cmd=capabilities HTTP/1.1" 200 - (glob)
324 324 $LOCALIP - - [$LOGDATE$] "GET /?cmd=batch HTTP/1.1" 200 - x-hgarg-1:cmds=heads+%3Bknown+nodes%3D392c05922088bacf8e68a6939b480017afbf245d x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull (glob)
325 325 $LOCALIP - - [$LOGDATE$] "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=phases x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull (glob)
326 326 $LOCALIP - - [$LOGDATE$] "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=bookmarks x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull (glob)
327 327 $LOCALIP - - [$LOGDATE$] "GET /?cmd=branchmap HTTP/1.1" 200 - x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull (glob)
328 328 $LOCALIP - - [$LOGDATE$] "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=bookmarks x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull (glob)
329 329 $LOCALIP - - [$LOGDATE$] "POST /.git/info/lfs/objects/batch HTTP/1.1" 200 - (glob)
330 330 $LOCALIP - - [$LOGDATE$] "PUT /.hg/lfs/objects/b5bb9d8014a0f9b1d61e21e796d78dccdf1352f23cd32812f4850b878ae4944c HTTP/1.1" 422 - (glob)
331 331 $LOCALIP - - [$LOGDATE$] "GET /?cmd=capabilities HTTP/1.1" 200 - (glob)
332 332 $LOCALIP - - [$LOGDATE$] "GET /?cmd=batch HTTP/1.1" 200 - x-hgarg-1:cmds=heads+%3Bknown+nodes%3D392c05922088bacf8e68a6939b480017afbf245d x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull (glob)
333 333 $LOCALIP - - [$LOGDATE$] "GET /?cmd=getbundle HTTP/1.1" 200 - x-hgarg-1:bookmarks=1&bundlecaps=HG20%2Cbundle2%3DHG20%250Abookmarks%250Achangegroup%253D01%252C02%252C03%250Adigests%253Dmd5%252Csha1%252Csha512%250Aerror%253Dabort%252Cunsupportedcontent%252Cpushraced%252Cpushkey%250Ahgtagsfnodes%250Alistkeys%250Aphases%253Dheads%250Apushkey%250Aremote-changegroup%253Dhttp%252Chttps%250Arev-branch-cache%250Astream%253Dv2&cg=1&common=525251863cad618e55d483555f3d00a2ca99597e&heads=506bf3d83f78c54b89e81c6411adee19fdf02156+525251863cad618e55d483555f3d00a2ca99597e&listkeys=bookmarks&phases=1 x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull (glob)
334 334 $LOCALIP - - [$LOGDATE$] "POST /.git/info/lfs/objects/batch HTTP/1.1" 200 - (glob)
335 335 $LOCALIP - - [$LOGDATE$] "GET /.hg/lfs/objects/276f73cfd75f9fb519810df5f5d96d6594ca2521abd86cbcd92122f7d51a1f3d HTTP/1.1" 500 - (glob)
336 336 $LOCALIP - - [$LOGDATE$] "POST /.git/info/lfs/objects/batch HTTP/1.1" 200 - (glob)
337 337 $LOCALIP - - [$LOGDATE$] "GET /.hg/lfs/objects/276f73cfd75f9fb519810df5f5d96d6594ca2521abd86cbcd92122f7d51a1f3d HTTP/1.1" 422 - (glob)
338 338
339 339 $ grep -v ' File "' $TESTTMP/errors.log
340 340 $LOCALIP - - [$ERRDATE$] HG error: Exception happened while processing request '/.git/info/lfs/objects/batch': (glob)
341 341 $LOCALIP - - [$ERRDATE$] HG error: Traceback (most recent call last): (glob)
342 342 $LOCALIP - - [$ERRDATE$] HG error: verifies = store.verify(oid) (glob)
343 343 $LOCALIP - - [$ERRDATE$] HG error: raise IOError(errno.EIO, r'%s: I/O error' % oid.decode("utf-8")) (glob)
344 344 $LOCALIP - - [$ERRDATE$] HG error: *Error: [Errno 5] f03217a32529a28a42d03b1244fe09b6e0f9fd06d7b966d4d50567be2abe6c0e: I/O error (glob)
345 345 $LOCALIP - - [$ERRDATE$] HG error: (glob)
346 346 $LOCALIP - - [$ERRDATE$] HG error: Exception happened while processing request '/.git/info/lfs/objects/batch': (glob)
347 347 $LOCALIP - - [$ERRDATE$] HG error: Traceback (most recent call last): (glob)
348 348 $LOCALIP - - [$ERRDATE$] HG error: verifies = store.verify(oid) (glob)
349 349 $LOCALIP - - [$ERRDATE$] HG error: raise IOError(errno.EIO, r'%s: I/O error' % oid.decode("utf-8")) (glob)
350 350 $LOCALIP - - [$ERRDATE$] HG error: *Error: [Errno 5] b5bb9d8014a0f9b1d61e21e796d78dccdf1352f23cd32812f4850b878ae4944c: I/O error (glob)
351 351 $LOCALIP - - [$ERRDATE$] HG error: (glob)
352 352 $LOCALIP - - [$ERRDATE$] HG error: Exception happened while processing request '/.hg/lfs/objects/b5bb9d8014a0f9b1d61e21e796d78dccdf1352f23cd32812f4850b878ae4944c': (glob)
353 353 $LOCALIP - - [$ERRDATE$] HG error: Traceback (most recent call last): (glob)
354 354 $LOCALIP - - [$ERRDATE$] HG error: localstore.download(oid, req.bodyfh) (glob)
355 355 $LOCALIP - - [$ERRDATE$] HG error: super(badstore, self).download(oid, src) (glob)
356 356 $LOCALIP - - [$ERRDATE$] HG error: _(b'corrupt remote lfs object: %s') % oid (glob)
357 357 $LOCALIP - - [$ERRDATE$] HG error: LfsCorruptionError: corrupt remote lfs object: b5bb9d8014a0f9b1d61e21e796d78dccdf1352f23cd32812f4850b878ae4944c (no-py3 !)
358 $LOCALIP - - [$ERRDATE$] HG error: hgext.lfs.blobstore.LfsCorruptionError: b'corrupt remote lfs object: b5bb9d8014a0f9b1d61e21e796d78dccdf1352f23cd32812f4850b878ae4944c' (py3 !)
358 $LOCALIP - - [$ERRDATE$] HG error: hgext.lfs.blobstore.LfsCorruptionError: corrupt remote lfs object: b5bb9d8014a0f9b1d61e21e796d78dccdf1352f23cd32812f4850b878ae4944c (py3 !)
359 359 $LOCALIP - - [$ERRDATE$] HG error: (glob)
360 360 $LOCALIP - - [$ERRDATE$] Exception happened during processing request '/.hg/lfs/objects/276f73cfd75f9fb519810df5f5d96d6594ca2521abd86cbcd92122f7d51a1f3d': (glob)
361 361 Traceback (most recent call last):
362 362 self.do_write()
363 363 self.do_hgweb()
364 364 for chunk in self.server.application(env, self._start_response):
365 365 for r in self._runwsgi(req, res, repo):
366 366 rctx, req, res, self.check_perm
367 367 return func(*(args + a), **kw) (no-py3 !)
368 368 rctx.repo, req, res, lambda perm: checkperm(rctx, req, perm)
369 369 res.setbodybytes(localstore.read(oid))
370 370 blob = self._read(self.vfs, oid, verify)
371 371 raise IOError(errno.EIO, r'%s: I/O error' % oid.decode("utf-8"))
372 372 *Error: [Errno 5] 276f73cfd75f9fb519810df5f5d96d6594ca2521abd86cbcd92122f7d51a1f3d: I/O error (glob)
373 373
374 374 $LOCALIP - - [$ERRDATE$] HG error: Exception happened while processing request '/.hg/lfs/objects/276f73cfd75f9fb519810df5f5d96d6594ca2521abd86cbcd92122f7d51a1f3d': (glob)
375 375 $LOCALIP - - [$ERRDATE$] HG error: Traceback (most recent call last): (glob)
376 376 $LOCALIP - - [$ERRDATE$] HG error: res.setbodybytes(localstore.read(oid)) (glob)
377 377 $LOCALIP - - [$ERRDATE$] HG error: blob = self._read(self.vfs, oid, verify) (glob)
378 378 $LOCALIP - - [$ERRDATE$] HG error: blobstore._verify(oid, b'dummy content') (glob)
379 379 $LOCALIP - - [$ERRDATE$] HG error: hint=_(b'run hg verify'), (glob)
380 380 $LOCALIP - - [$ERRDATE$] HG error: LfsCorruptionError: detected corrupt lfs object: 276f73cfd75f9fb519810df5f5d96d6594ca2521abd86cbcd92122f7d51a1f3d (no-py3 !)
381 $LOCALIP - - [$ERRDATE$] HG error: hgext.lfs.blobstore.LfsCorruptionError: b'detected corrupt lfs object: 276f73cfd75f9fb519810df5f5d96d6594ca2521abd86cbcd92122f7d51a1f3d' (py3 !)
381 $LOCALIP - - [$ERRDATE$] HG error: hgext.lfs.blobstore.LfsCorruptionError: detected corrupt lfs object: 276f73cfd75f9fb519810df5f5d96d6594ca2521abd86cbcd92122f7d51a1f3d (py3 !)
382 382 $LOCALIP - - [$ERRDATE$] HG error: (glob)
383 383
384 384 Basic Authorization headers are returned by the Batch API, and sent back with
385 385 the GET/PUT request.
386 386
387 387 $ rm -f $TESTTMP/access.log $TESTTMP/errors.log
388 388
389 389 $ cat >> $HGRCPATH << EOF
390 390 > [experimental]
391 391 > lfs.disableusercache = True
392 392 > [auth]
393 393 > l.schemes=http
394 394 > l.prefix=lo
395 395 > l.username=user
396 396 > l.password=pass
397 397 > EOF
398 398
399 399 $ hg --config extensions.x=$TESTDIR/httpserverauth.py \
400 400 > -R server serve -d -p $HGPORT1 --pid-file=hg.pid \
401 401 > -A $TESTTMP/access.log -E $TESTTMP/errors.log
402 402 $ mv hg.pid $DAEMON_PIDS
403 403
404 404 $ hg clone --debug http://localhost:$HGPORT1 auth_clone | egrep '^[{}]| '
405 405 {
406 406 "objects": [
407 407 {
408 408 "actions": {
409 409 "download": {
410 410 "expires_at": "$ISO_8601_DATE_TIME$"
411 411 "header": {
412 412 "Accept": "application/vnd.git-lfs"
413 413 "Authorization": "Basic dXNlcjpwYXNz"
414 414 }
415 415 "href": "http://localhost:$HGPORT1/.hg/lfs/objects/276f73cfd75f9fb519810df5f5d96d6594ca2521abd86cbcd92122f7d51a1f3d"
416 416 }
417 417 }
418 418 "oid": "276f73cfd75f9fb519810df5f5d96d6594ca2521abd86cbcd92122f7d51a1f3d"
419 419 "size": 14
420 420 }
421 421 ]
422 422 "transfer": "basic"
423 423 }
424 424
425 425 $ echo 'another blob' > auth_clone/lfs.blob
426 426 $ hg -R auth_clone ci -Aqm 'add blob'
427 427
428 428 $ cat > use_digests.py << EOF
429 429 > from mercurial import (
430 430 > exthelper,
431 431 > url,
432 432 > )
433 433 >
434 434 > eh = exthelper.exthelper()
435 435 > uisetup = eh.finaluisetup
436 436 >
437 437 > @eh.wrapfunction(url, 'opener')
438 438 > def urlopener(orig, *args, **kwargs):
439 439 > opener = orig(*args, **kwargs)
440 440 > opener.addheaders.append((r'X-HgTest-AuthType', r'Digest'))
441 441 > return opener
442 442 > EOF
443 443
444 444 Test that Digest Auth fails gracefully before testing the successful Basic Auth
445 445
446 446 $ hg -R auth_clone push --config extensions.x=use_digests.py
447 447 pushing to http://localhost:$HGPORT1/
448 448 searching for changes
449 449 abort: LFS HTTP error: HTTP Error 401: the server must support Basic Authentication!
450 450 (api=http://localhost:$HGPORT1/.git/info/lfs/objects/batch, action=upload)
451 451 [255]
452 452
453 453 $ hg -R auth_clone --debug push | egrep '^[{}]| '
454 454 {
455 455 "objects": [
456 456 {
457 457 "actions": {
458 458 "upload": {
459 459 "expires_at": "$ISO_8601_DATE_TIME$"
460 460 "header": {
461 461 "Accept": "application/vnd.git-lfs"
462 462 "Authorization": "Basic dXNlcjpwYXNz"
463 463 }
464 464 "href": "http://localhost:$HGPORT1/.hg/lfs/objects/df14287d8d75f076a6459e7a3703ca583ca9fb3f4918caed10c77ac8622d49b3"
465 465 }
466 466 }
467 467 "oid": "df14287d8d75f076a6459e7a3703ca583ca9fb3f4918caed10c77ac8622d49b3"
468 468 "size": 13
469 469 }
470 470 ]
471 471 "transfer": "basic"
472 472 }
473 473
474 474 $ "$PYTHON" $RUNTESTDIR/killdaemons.py $DAEMON_PIDS
475 475
476 476 $ cat $TESTTMP/access.log $TESTTMP/errors.log
477 477 $LOCALIP - - [$LOGDATE$] "GET /?cmd=capabilities HTTP/1.1" 401 - (glob)
478 478 $LOCALIP - - [$LOGDATE$] "GET /?cmd=capabilities HTTP/1.1" 200 - (glob)
479 479 $LOCALIP - - [$LOGDATE$] "GET /?cmd=batch HTTP/1.1" 200 - x-hgarg-1:cmds=heads+%3Bknown+nodes%3D x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull (glob)
480 480 $LOCALIP - - [$LOGDATE$] "GET /?cmd=getbundle HTTP/1.1" 200 - x-hgarg-1:bookmarks=1&bundlecaps=HG20%2Cbundle2%3DHG20%250Abookmarks%250Achangegroup%253D01%252C02%252C03%250Adigests%253Dmd5%252Csha1%252Csha512%250Aerror%253Dabort%252Cunsupportedcontent%252Cpushraced%252Cpushkey%250Ahgtagsfnodes%250Alistkeys%250Aphases%253Dheads%250Apushkey%250Aremote-changegroup%253Dhttp%252Chttps%250Arev-branch-cache%250Astream%253Dv2&cg=1&common=0000000000000000000000000000000000000000&heads=506bf3d83f78c54b89e81c6411adee19fdf02156+525251863cad618e55d483555f3d00a2ca99597e&listkeys=bookmarks&phases=1 x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull (glob)
481 481 $LOCALIP - - [$LOGDATE$] "POST /.git/info/lfs/objects/batch HTTP/1.1" 401 - (glob)
482 482 $LOCALIP - - [$LOGDATE$] "POST /.git/info/lfs/objects/batch HTTP/1.1" 200 - (glob)
483 483 $LOCALIP - - [$LOGDATE$] "GET /.hg/lfs/objects/276f73cfd75f9fb519810df5f5d96d6594ca2521abd86cbcd92122f7d51a1f3d HTTP/1.1" 200 - (glob)
484 484 $LOCALIP - - [$LOGDATE$] "GET /?cmd=capabilities HTTP/1.1" 401 - x-hgtest-authtype:Digest (glob)
485 485 $LOCALIP - - [$LOGDATE$] "GET /?cmd=capabilities HTTP/1.1" 200 - x-hgtest-authtype:Digest (glob)
486 486 $LOCALIP - - [$LOGDATE$] "GET /?cmd=batch HTTP/1.1" 401 - x-hgarg-1:cmds=heads+%3Bknown+nodes%3D525251863cad618e55d483555f3d00a2ca99597e+4d9397055dc0c205f3132f331f36353ab1a525a3 x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull x-hgtest-authtype:Digest (glob)
487 487 $LOCALIP - - [$LOGDATE$] "GET /?cmd=batch HTTP/1.1" 200 - x-hgarg-1:cmds=heads+%3Bknown+nodes%3D525251863cad618e55d483555f3d00a2ca99597e+4d9397055dc0c205f3132f331f36353ab1a525a3 x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull x-hgtest-authtype:Digest (glob)
488 488 $LOCALIP - - [$LOGDATE$] "GET /?cmd=listkeys HTTP/1.1" 401 - x-hgarg-1:namespace=phases x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull x-hgtest-authtype:Digest (glob)
489 489 $LOCALIP - - [$LOGDATE$] "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=phases x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull x-hgtest-authtype:Digest (glob)
490 490 $LOCALIP - - [$LOGDATE$] "GET /?cmd=listkeys HTTP/1.1" 401 - x-hgarg-1:namespace=bookmarks x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull x-hgtest-authtype:Digest (glob)
491 491 $LOCALIP - - [$LOGDATE$] "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=bookmarks x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull x-hgtest-authtype:Digest (glob)
492 492 $LOCALIP - - [$LOGDATE$] "GET /?cmd=branchmap HTTP/1.1" 401 - x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull x-hgtest-authtype:Digest (glob)
493 493 $LOCALIP - - [$LOGDATE$] "GET /?cmd=branchmap HTTP/1.1" 200 - x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull x-hgtest-authtype:Digest (glob)
494 494 $LOCALIP - - [$LOGDATE$] "GET /?cmd=listkeys HTTP/1.1" 401 - x-hgarg-1:namespace=bookmarks x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull x-hgtest-authtype:Digest (glob)
495 495 $LOCALIP - - [$LOGDATE$] "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=bookmarks x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull x-hgtest-authtype:Digest (glob)
496 496 $LOCALIP - - [$LOGDATE$] "POST /.git/info/lfs/objects/batch HTTP/1.1" 401 - x-hgtest-authtype:Digest (glob)
497 497 $LOCALIP - - [$LOGDATE$] "GET /?cmd=capabilities HTTP/1.1" 401 - (glob)
498 498 $LOCALIP - - [$LOGDATE$] "GET /?cmd=capabilities HTTP/1.1" 200 - (glob)
499 499 $LOCALIP - - [$LOGDATE$] "GET /?cmd=batch HTTP/1.1" 200 - x-hgarg-1:cmds=heads+%3Bknown+nodes%3D525251863cad618e55d483555f3d00a2ca99597e+4d9397055dc0c205f3132f331f36353ab1a525a3 x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull (glob)
500 500 $LOCALIP - - [$LOGDATE$] "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=phases x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull (glob)
501 501 $LOCALIP - - [$LOGDATE$] "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=bookmarks x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull (glob)
502 502 $LOCALIP - - [$LOGDATE$] "GET /?cmd=branchmap HTTP/1.1" 200 - x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull (glob)
503 503 $LOCALIP - - [$LOGDATE$] "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=bookmarks x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull (glob)
504 504 $LOCALIP - - [$LOGDATE$] "POST /.git/info/lfs/objects/batch HTTP/1.1" 401 - (glob)
505 505 $LOCALIP - - [$LOGDATE$] "POST /.git/info/lfs/objects/batch HTTP/1.1" 200 - (glob)
506 506 $LOCALIP - - [$LOGDATE$] "PUT /.hg/lfs/objects/df14287d8d75f076a6459e7a3703ca583ca9fb3f4918caed10c77ac8622d49b3 HTTP/1.1" 201 - (glob)
507 507 $LOCALIP - - [$LOGDATE$] "POST /?cmd=unbundle HTTP/1.1" 200 - x-hgarg-1:heads=666f726365 x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull (glob)
508 508 $LOCALIP - - [$LOGDATE$] "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=phases x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull (glob)
@@ -1,130 +1,130 b''
1 1 Test UI worker interaction
2 2
3 3 $ cat > t.py <<EOF
4 4 > from __future__ import absolute_import, print_function
5 5 > import time
6 6 > from mercurial import (
7 7 > error,
8 8 > registrar,
9 9 > ui as uimod,
10 10 > worker,
11 11 > )
12 12 > def abort(ui, args):
13 13 > if args[0] == 0:
14 14 > # by first worker for test stability
15 15 > raise error.Abort(b'known exception')
16 16 > return runme(ui, [])
17 17 > def exc(ui, args):
18 18 > if args[0] == 0:
19 19 > # by first worker for test stability
20 20 > raise Exception('unknown exception')
21 21 > return runme(ui, [])
22 22 > def runme(ui, args):
23 23 > for arg in args:
24 24 > ui.status(b'run\n')
25 25 > yield 1, arg
26 26 > time.sleep(0.1) # easier to trigger killworkers code path
27 27 > functable = {
28 28 > b'abort': abort,
29 29 > b'exc': exc,
30 30 > b'runme': runme,
31 31 > }
32 32 > cmdtable = {}
33 33 > command = registrar.command(cmdtable)
34 34 > @command(b'test', [], b'hg test [COST] [FUNC]')
35 35 > def t(ui, repo, cost=1.0, func=b'runme'):
36 36 > cost = float(cost)
37 37 > func = functable[func]
38 38 > ui.status(b'start\n')
39 39 > runs = worker.worker(ui, cost, func, (ui,), range(8))
40 40 > for n, i in runs:
41 41 > pass
42 42 > ui.status(b'done\n')
43 43 > EOF
44 44 $ abspath=`pwd`/t.py
45 45 $ hg init
46 46
47 47 Run tests with worker enable by forcing a heigh cost
48 48
49 49 $ hg --config "extensions.t=$abspath" test 100000.0
50 50 start
51 51 run
52 52 run
53 53 run
54 54 run
55 55 run
56 56 run
57 57 run
58 58 run
59 59 done
60 60
61 61 Run tests without worker by forcing a low cost
62 62
63 63 $ hg --config "extensions.t=$abspath" test 0.0000001
64 64 start
65 65 run
66 66 run
67 67 run
68 68 run
69 69 run
70 70 run
71 71 run
72 72 run
73 73 done
74 74
75 75 #if no-windows
76 76
77 77 Known exception should be caught, but printed if --traceback is enabled
78 78
79 79 $ hg --config "extensions.t=$abspath" --config 'worker.numcpus=8' \
80 80 > test 100000.0 abort 2>&1
81 81 start
82 82 abort: known exception
83 83 [255]
84 84
85 85 $ hg --config "extensions.t=$abspath" --config 'worker.numcpus=8' \
86 86 > test 100000.0 abort --traceback 2>&1 | egrep '(SystemExit|Abort)'
87 87 raise error.Abort(b'known exception')
88 mercurial.error.Abort: b'known exception' (py3 !)
88 mercurial.error.Abort: known exception (py3 !)
89 89 Abort: known exception (no-py3 !)
90 90 SystemExit: 255
91 91
92 92 Traceback must be printed for unknown exceptions
93 93
94 94 $ hg --config "extensions.t=$abspath" --config 'worker.numcpus=8' \
95 95 > test 100000.0 exc 2>&1 | grep '^Exception'
96 96 Exception: unknown exception
97 97
98 98 Workers should not do cleanups in all cases
99 99
100 100 $ cat > $TESTTMP/detectcleanup.py <<EOF
101 101 > from __future__ import absolute_import
102 102 > import atexit
103 103 > import os
104 104 > import time
105 105 > oldfork = os.fork
106 106 > count = 0
107 107 > parentpid = os.getpid()
108 108 > def delayedfork():
109 109 > global count
110 110 > count += 1
111 111 > pid = oldfork()
112 112 > # make it easier to test SIGTERM hitting other workers when they have
113 113 > # not set up error handling yet.
114 114 > if count > 1 and pid == 0:
115 115 > time.sleep(0.1)
116 116 > return pid
117 117 > os.fork = delayedfork
118 118 > def cleanup():
119 119 > if os.getpid() != parentpid:
120 120 > os.write(1, 'should never happen\n')
121 121 > atexit.register(cleanup)
122 122 > EOF
123 123
124 124 $ hg --config "extensions.t=$abspath" --config worker.numcpus=8 --config \
125 125 > "extensions.d=$TESTTMP/detectcleanup.py" test 100000 abort
126 126 start
127 127 abort: known exception
128 128 [255]
129 129
130 130 #endif
General Comments 0
You need to be logged in to leave comments. Login now