##// END OF EJS Templates
Merge
Bryan O'Sullivan -
r17713:2c638277 merge default
parent child Browse files
Show More
@@ -1,453 +1,454 b''
1 1 #!/usr/bin/env python
2 2 #
3 3 # check-code - a style and portability checker for Mercurial
4 4 #
5 5 # Copyright 2010 Matt Mackall <mpm@selenic.com>
6 6 #
7 7 # This software may be used and distributed according to the terms of the
8 8 # GNU General Public License version 2 or any later version.
9 9
10 10 import re, glob, os, sys
11 11 import keyword
12 12 import optparse
13 13
14 14 def repquote(m):
15 15 t = re.sub(r"\w", "x", m.group('text'))
16 16 t = re.sub(r"[^\s\nx]", "o", t)
17 17 return m.group('quote') + t + m.group('quote')
18 18
19 19 def reppython(m):
20 20 comment = m.group('comment')
21 21 if comment:
22 22 return "#" * len(comment)
23 23 return repquote(m)
24 24
25 25 def repcomment(m):
26 26 return m.group(1) + "#" * len(m.group(2))
27 27
28 28 def repccomment(m):
29 29 t = re.sub(r"((?<=\n) )|\S", "x", m.group(2))
30 30 return m.group(1) + t + "*/"
31 31
32 32 def repcallspaces(m):
33 33 t = re.sub(r"\n\s+", "\n", m.group(2))
34 34 return m.group(1) + t
35 35
36 36 def repinclude(m):
37 37 return m.group(1) + "<foo>"
38 38
39 39 def rephere(m):
40 40 t = re.sub(r"\S", "x", m.group(2))
41 41 return m.group(1) + t
42 42
43 43
44 44 testpats = [
45 45 [
46 46 (r'pushd|popd', "don't use 'pushd' or 'popd', use 'cd'"),
47 47 (r'\W\$?\(\([^\)\n]*\)\)', "don't use (()) or $(()), use 'expr'"),
48 48 (r'grep.*-q', "don't use 'grep -q', redirect to /dev/null"),
49 49 (r'sed.*-i', "don't use 'sed -i', use a temporary file"),
50 50 (r'\becho\b.*\\n', "don't use 'echo \\n', use printf"),
51 51 (r'echo -n', "don't use 'echo -n', use printf"),
52 52 (r'(^| )wc[^|]*$\n(?!.*\(re\))', "filter wc output"),
53 53 (r'head -c', "don't use 'head -c', use 'dd'"),
54 54 (r'sha1sum', "don't use sha1sum, use $TESTDIR/md5sum.py"),
55 55 (r'ls.*-\w*R', "don't use 'ls -R', use 'find'"),
56 56 (r'printf.*\\([1-9]|0\d)', "don't use 'printf \NNN', use Python"),
57 57 (r'printf.*\\x', "don't use printf \\x, use Python"),
58 58 (r'\$\(.*\)', "don't use $(expr), use `expr`"),
59 59 (r'rm -rf \*', "don't use naked rm -rf, target a directory"),
60 60 (r'(^|\|\s*)grep (-\w\s+)*[^|]*[(|]\w',
61 61 "use egrep for extended grep syntax"),
62 62 (r'/bin/', "don't use explicit paths for tools"),
63 63 (r'[^\n]\Z', "no trailing newline"),
64 64 (r'export.*=', "don't export and assign at once"),
65 65 (r'^source\b', "don't use 'source', use '.'"),
66 66 (r'touch -d', "don't use 'touch -d', use 'touch -t' instead"),
67 67 (r'ls +[^|\n-]+ +-', "options to 'ls' must come before filenames"),
68 68 (r'[^>\n]>\s*\$HGRCPATH', "don't overwrite $HGRCPATH, append to it"),
69 69 (r'^stop\(\)', "don't use 'stop' as a shell function name"),
70 70 (r'(\[|\btest\b).*-e ', "don't use 'test -e', use 'test -f'"),
71 71 (r'^alias\b.*=', "don't use alias, use a function"),
72 72 (r'if\s*!', "don't use '!' to negate exit status"),
73 73 (r'/dev/u?random', "don't use entropy, use /dev/zero"),
74 74 (r'do\s*true;\s*done', "don't use true as loop body, use sleep 0"),
75 75 (r'^( *)\t', "don't use tabs to indent"),
76 76 ],
77 77 # warnings
78 78 [
79 79 (r'^function', "don't use 'function', use old style"),
80 80 (r'^diff.*-\w*N', "don't use 'diff -N'"),
81 81 (r'\$PWD', "don't use $PWD, use `pwd`"),
82 82 (r'^([^"\'\n]|("[^"\n]*")|(\'[^\'\n]*\'))*\^', "^ must be quoted"),
83 83 ]
84 84 ]
85 85
86 86 testfilters = [
87 87 (r"( *)(#([^\n]*\S)?)", repcomment),
88 88 (r"<<(\S+)((.|\n)*?\n\1)", rephere),
89 89 ]
90 90
91 91 uprefix = r"^ \$ "
92 92 utestpats = [
93 93 [
94 94 (r'^(\S.*|| [$>] .*)[ \t]\n', "trailing whitespace on non-output"),
95 95 (uprefix + r'.*\|\s*sed[^|>\n]*\n',
96 96 "use regex test output patterns instead of sed"),
97 97 (uprefix + r'(true|exit 0)', "explicit zero exit unnecessary"),
98 98 (uprefix + r'.*(?<!\[)\$\?', "explicit exit code checks unnecessary"),
99 99 (uprefix + r'.*\|\| echo.*(fail|error)',
100 100 "explicit exit code checks unnecessary"),
101 101 (uprefix + r'set -e', "don't use set -e"),
102 102 (uprefix + r'\s', "don't indent commands, use > for continued lines"),
103 103 (r'^ saved backup bundle to \$TESTTMP.*\.hg$',
104 104 "use (glob) to match Windows paths too"),
105 105 ],
106 106 # warnings
107 107 []
108 108 ]
109 109
110 110 for i in [0, 1]:
111 111 for p, m in testpats[i]:
112 112 if p.startswith(r'^'):
113 113 p = r"^ [$>] (%s)" % p[1:]
114 114 else:
115 115 p = r"^ [$>] .*(%s)" % p
116 116 utestpats[i].append((p, m))
117 117
118 118 utestfilters = [
119 (r"<<(\S+)((.|\n)*?\n > \1)", rephere),
119 120 (r"( *)(#([^\n]*\S)?)", repcomment),
120 121 ]
121 122
122 123 pypats = [
123 124 [
124 125 (r'^\s*def\s*\w+\s*\(.*,\s*\(',
125 126 "tuple parameter unpacking not available in Python 3+"),
126 127 (r'lambda\s*\(.*,.*\)',
127 128 "tuple parameter unpacking not available in Python 3+"),
128 129 (r'(?<!def)\s+(cmp)\(', "cmp is not available in Python 3+"),
129 130 (r'\breduce\s*\(.*', "reduce is not available in Python 3+"),
130 131 (r'\.has_key\b', "dict.has_key is not available in Python 3+"),
131 132 (r'^\s*\t', "don't use tabs"),
132 133 (r'\S;\s*\n', "semicolon"),
133 134 (r'[^_]_\("[^"]+"\s*%', "don't use % inside _()"),
134 135 (r"[^_]_\('[^']+'\s*%", "don't use % inside _()"),
135 136 (r'\w,\w', "missing whitespace after ,"),
136 137 (r'\w[+/*\-<>]\w', "missing whitespace in expression"),
137 138 (r'^\s+\w+=\w+[^,)\n]$', "missing whitespace in assignment"),
138 139 (r'(\s+)try:\n((?:\n|\1\s.*\n)+?)\1except.*?:\n'
139 140 r'((?:\n|\1\s.*\n)+?)\1finally:', 'no try/except/finally in Python 2.4'),
140 141 (r'(\s+)try:\n((?:\n|\1\s.*\n)*?)\1\s*yield\b.*?'
141 142 r'((?:\n|\1\s.*\n)+?)\1finally:',
142 143 'no yield inside try/finally in Python 2.4'),
143 144 (r'.{81}', "line too long"),
144 145 (r' x+[xo][\'"]\n\s+[\'"]x', 'string join across lines with no space'),
145 146 (r'[^\n]\Z', "no trailing newline"),
146 147 (r'(\S[ \t]+|^[ \t]+)\n', "trailing whitespace"),
147 148 # (r'^\s+[^_ \n][^_. \n]+_[^_\n]+\s*=',
148 149 # "don't use underbars in identifiers"),
149 150 (r'^\s+(self\.)?[A-za-z][a-z0-9]+[A-Z]\w* = ',
150 151 "don't use camelcase in identifiers"),
151 152 (r'^\s*(if|while|def|class|except|try)\s[^[\n]*:\s*[^\\n]#\s]+',
152 153 "linebreak after :"),
153 154 (r'class\s[^( \n]+:', "old-style class, use class foo(object)"),
154 155 (r'class\s[^( \n]+\(\):',
155 156 "class foo() not available in Python 2.4, use class foo(object)"),
156 157 (r'\b(%s)\(' % '|'.join(keyword.kwlist),
157 158 "Python keyword is not a function"),
158 159 (r',]', "unneeded trailing ',' in list"),
159 160 # (r'class\s[A-Z][^\(]*\((?!Exception)',
160 161 # "don't capitalize non-exception classes"),
161 162 # (r'in range\(', "use xrange"),
162 163 # (r'^\s*print\s+', "avoid using print in core and extensions"),
163 164 (r'[\x80-\xff]', "non-ASCII character literal"),
164 165 (r'("\')\.format\(', "str.format() not available in Python 2.4"),
165 166 (r'^\s*with\s+', "with not available in Python 2.4"),
166 167 (r'\.isdisjoint\(', "set.isdisjoint not available in Python 2.4"),
167 168 (r'^\s*except.* as .*:', "except as not available in Python 2.4"),
168 169 (r'^\s*os\.path\.relpath', "relpath not available in Python 2.4"),
169 170 (r'(?<!def)\s+(any|all|format)\(',
170 171 "any/all/format not available in Python 2.4"),
171 172 (r'(?<!def)\s+(callable)\(',
172 173 "callable not available in Python 3, use getattr(f, '__call__', None)"),
173 174 (r'if\s.*\selse', "if ... else form not available in Python 2.4"),
174 175 (r'^\s*(%s)\s\s' % '|'.join(keyword.kwlist),
175 176 "gratuitous whitespace after Python keyword"),
176 177 (r'([\(\[][ \t]\S)|(\S[ \t][\)\]])', "gratuitous whitespace in () or []"),
177 178 # (r'\s\s=', "gratuitous whitespace before ="),
178 179 (r'[^>< ](\+=|-=|!=|<>|<=|>=|<<=|>>=|%=)\S',
179 180 "missing whitespace around operator"),
180 181 (r'[^>< ](\+=|-=|!=|<>|<=|>=|<<=|>>=|%=)\s',
181 182 "missing whitespace around operator"),
182 183 (r'\s(\+=|-=|!=|<>|<=|>=|<<=|>>=|%=)\S',
183 184 "missing whitespace around operator"),
184 185 (r'[^^+=*/!<>&| %-](\s=|=\s)[^= ]',
185 186 "wrong whitespace around ="),
186 187 (r'raise Exception', "don't raise generic exceptions"),
187 188 (r' is\s+(not\s+)?["\'0-9-]', "object comparison with literal"),
188 189 (r' [=!]=\s+(True|False|None)',
189 190 "comparison with singleton, use 'is' or 'is not' instead"),
190 191 (r'^\s*(while|if) [01]:',
191 192 "use True/False for constant Boolean expression"),
192 193 (r'(?:(?<!def)\s+|\()hasattr',
193 194 'hasattr(foo, bar) is broken, use util.safehasattr(foo, bar) instead'),
194 195 (r'opener\([^)]*\).read\(',
195 196 "use opener.read() instead"),
196 197 (r'BaseException', 'not in Python 2.4, use Exception'),
197 198 (r'os\.path\.relpath', 'os.path.relpath is not in Python 2.5'),
198 199 (r'opener\([^)]*\).write\(',
199 200 "use opener.write() instead"),
200 201 (r'[\s\(](open|file)\([^)]*\)\.read\(',
201 202 "use util.readfile() instead"),
202 203 (r'[\s\(](open|file)\([^)]*\)\.write\(',
203 204 "use util.readfile() instead"),
204 205 (r'^[\s\(]*(open(er)?|file)\([^)]*\)',
205 206 "always assign an opened file to a variable, and close it afterwards"),
206 207 (r'[\s\(](open|file)\([^)]*\)\.',
207 208 "always assign an opened file to a variable, and close it afterwards"),
208 209 (r'(?i)descendent', "the proper spelling is descendAnt"),
209 210 (r'\.debug\(\_', "don't mark debug messages for translation"),
210 211 (r'\.strip\(\)\.split\(\)', "no need to strip before splitting"),
211 212 (r'^\s*except\s*:', "warning: naked except clause", r'#.*re-raises'),
212 213 (r':\n( )*( ){1,3}[^ ]', "must indent 4 spaces"),
213 214 ],
214 215 # warnings
215 216 [
216 217 (r'ui\.(status|progress|write|note|warn)\([\'\"]x',
217 218 "warning: unwrapped ui message"),
218 219 ]
219 220 ]
220 221
221 222 pyfilters = [
222 223 (r"""(?msx)(?P<comment>\#.*?$)|
223 224 ((?P<quote>('''|\"\"\"|(?<!')'(?!')|(?<!")"(?!")))
224 225 (?P<text>(([^\\]|\\.)*?))
225 226 (?P=quote))""", reppython),
226 227 ]
227 228
228 229 cpats = [
229 230 [
230 231 (r'//', "don't use //-style comments"),
231 232 (r'^ ', "don't use spaces to indent"),
232 233 (r'\S\t', "don't use tabs except for indent"),
233 234 (r'(\S[ \t]+|^[ \t]+)\n', "trailing whitespace"),
234 235 (r'.{81}', "line too long"),
235 236 (r'(while|if|do|for)\(', "use space after while/if/do/for"),
236 237 (r'return\(', "return is not a function"),
237 238 (r' ;', "no space before ;"),
238 239 (r'\w+\* \w+', "use int *foo, not int* foo"),
239 240 (r'\([^\)]+\) \w+', "use (int)foo, not (int) foo"),
240 241 (r'\w+ (\+\+|--)', "use foo++, not foo ++"),
241 242 (r'\w,\w', "missing whitespace after ,"),
242 243 (r'^[^#]\w[+/*]\w', "missing whitespace in expression"),
243 244 (r'^#\s+\w', "use #foo, not # foo"),
244 245 (r'[^\n]\Z', "no trailing newline"),
245 246 (r'^\s*#import\b', "use only #include in standard C code"),
246 247 ],
247 248 # warnings
248 249 []
249 250 ]
250 251
251 252 cfilters = [
252 253 (r'(/\*)(((\*(?!/))|[^*])*)\*/', repccomment),
253 254 (r'''(?P<quote>(?<!")")(?P<text>([^"]|\\")+)"(?!")''', repquote),
254 255 (r'''(#\s*include\s+<)([^>]+)>''', repinclude),
255 256 (r'(\()([^)]+\))', repcallspaces),
256 257 ]
257 258
258 259 inutilpats = [
259 260 [
260 261 (r'\bui\.', "don't use ui in util"),
261 262 ],
262 263 # warnings
263 264 []
264 265 ]
265 266
266 267 inrevlogpats = [
267 268 [
268 269 (r'\brepo\.', "don't use repo in revlog"),
269 270 ],
270 271 # warnings
271 272 []
272 273 ]
273 274
274 275 checks = [
275 276 ('python', r'.*\.(py|cgi)$', pyfilters, pypats),
276 277 ('test script', r'(.*/)?test-[^.~]*$', testfilters, testpats),
277 278 ('c', r'.*\.c$', cfilters, cpats),
278 279 ('unified test', r'.*\.t$', utestfilters, utestpats),
279 280 ('layering violation repo in revlog', r'mercurial/revlog\.py', pyfilters,
280 281 inrevlogpats),
281 282 ('layering violation ui in util', r'mercurial/util\.py', pyfilters,
282 283 inutilpats),
283 284 ]
284 285
285 286 class norepeatlogger(object):
286 287 def __init__(self):
287 288 self._lastseen = None
288 289
289 290 def log(self, fname, lineno, line, msg, blame):
290 291 """print error related a to given line of a given file.
291 292
292 293 The faulty line will also be printed but only once in the case
293 294 of multiple errors.
294 295
295 296 :fname: filename
296 297 :lineno: line number
297 298 :line: actual content of the line
298 299 :msg: error message
299 300 """
300 301 msgid = fname, lineno, line
301 302 if msgid != self._lastseen:
302 303 if blame:
303 304 print "%s:%d (%s):" % (fname, lineno, blame)
304 305 else:
305 306 print "%s:%d:" % (fname, lineno)
306 307 print " > %s" % line
307 308 self._lastseen = msgid
308 309 print " " + msg
309 310
310 311 _defaultlogger = norepeatlogger()
311 312
312 313 def getblame(f):
313 314 lines = []
314 315 for l in os.popen('hg annotate -un %s' % f):
315 316 start, line = l.split(':', 1)
316 317 user, rev = start.split()
317 318 lines.append((line[1:-1], user, rev))
318 319 return lines
319 320
320 321 def checkfile(f, logfunc=_defaultlogger.log, maxerr=None, warnings=False,
321 322 blame=False, debug=False, lineno=True):
322 323 """checks style and portability of a given file
323 324
324 325 :f: filepath
325 326 :logfunc: function used to report error
326 327 logfunc(filename, linenumber, linecontent, errormessage)
327 328 :maxerr: number of error to display before aborting.
328 329 Set to false (default) to report all errors
329 330
330 331 return True if no error is found, False otherwise.
331 332 """
332 333 blamecache = None
333 334 result = True
334 335 for name, match, filters, pats in checks:
335 336 if debug:
336 337 print name, f
337 338 fc = 0
338 339 if not re.match(match, f):
339 340 if debug:
340 341 print "Skipping %s for %s it doesn't match %s" % (
341 342 name, match, f)
342 343 continue
343 344 fp = open(f)
344 345 pre = post = fp.read()
345 346 fp.close()
346 347 if "no-" + "check-code" in pre:
347 348 if debug:
348 349 print "Skipping %s for %s it has no- and check-code" % (
349 350 name, f)
350 351 break
351 352 for p, r in filters:
352 353 post = re.sub(p, r, post)
353 354 if warnings:
354 355 pats = pats[0] + pats[1]
355 356 else:
356 357 pats = pats[0]
357 358 # print post # uncomment to show filtered version
358 359
359 360 if debug:
360 361 print "Checking %s for %s" % (name, f)
361 362
362 363 prelines = None
363 364 errors = []
364 365 for pat in pats:
365 366 if len(pat) == 3:
366 367 p, msg, ignore = pat
367 368 else:
368 369 p, msg = pat
369 370 ignore = None
370 371
371 372 # fix-up regexes for multi-line searches
372 373 po = p
373 374 # \s doesn't match \n
374 375 p = re.sub(r'(?<!\\)\\s', r'[ \\t]', p)
375 376 # [^...] doesn't match newline
376 377 p = re.sub(r'(?<!\\)\[\^', r'[^\\n', p)
377 378
378 379 #print po, '=>', p
379 380
380 381 pos = 0
381 382 n = 0
382 383 for m in re.finditer(p, post, re.MULTILINE):
383 384 if prelines is None:
384 385 prelines = pre.splitlines()
385 386 postlines = post.splitlines(True)
386 387
387 388 start = m.start()
388 389 while n < len(postlines):
389 390 step = len(postlines[n])
390 391 if pos + step > start:
391 392 break
392 393 pos += step
393 394 n += 1
394 395 l = prelines[n]
395 396
396 397 if "check-code" + "-ignore" in l:
397 398 if debug:
398 399 print "Skipping %s for %s:%s (check-code -ignore)" % (
399 400 name, f, n)
400 401 continue
401 402 elif ignore and re.search(ignore, l, re.MULTILINE):
402 403 continue
403 404 bd = ""
404 405 if blame:
405 406 bd = 'working directory'
406 407 if not blamecache:
407 408 blamecache = getblame(f)
408 409 if n < len(blamecache):
409 410 bl, bu, br = blamecache[n]
410 411 if bl == l:
411 412 bd = '%s@%s' % (bu, br)
412 413 errors.append((f, lineno and n + 1, l, msg, bd))
413 414 result = False
414 415
415 416 errors.sort()
416 417 for e in errors:
417 418 logfunc(*e)
418 419 fc += 1
419 420 if maxerr and fc >= maxerr:
420 421 print " (too many errors, giving up)"
421 422 break
422 423
423 424 return result
424 425
425 426 if __name__ == "__main__":
426 427 parser = optparse.OptionParser("%prog [options] [files]")
427 428 parser.add_option("-w", "--warnings", action="store_true",
428 429 help="include warning-level checks")
429 430 parser.add_option("-p", "--per-file", type="int",
430 431 help="max warnings per file")
431 432 parser.add_option("-b", "--blame", action="store_true",
432 433 help="use annotate to generate blame info")
433 434 parser.add_option("", "--debug", action="store_true",
434 435 help="show debug information")
435 436 parser.add_option("", "--nolineno", action="store_false",
436 437 dest='lineno', help="don't show line numbers")
437 438
438 439 parser.set_defaults(per_file=15, warnings=False, blame=False, debug=False,
439 440 lineno=True)
440 441 (options, args) = parser.parse_args()
441 442
442 443 if len(args) == 0:
443 444 check = glob.glob("*")
444 445 else:
445 446 check = args
446 447
447 448 ret = 0
448 449 for f in check:
449 450 if not checkfile(f, maxerr=options.per_file, warnings=options.warnings,
450 451 blame=options.blame, debug=options.debug,
451 452 lineno=options.lineno):
452 453 ret = 1
453 454 sys.exit(ret)
@@ -1,117 +1,122 b''
1 1 # fancyopts.py - better command line parsing
2 2 #
3 3 # Copyright 2005-2009 Matt Mackall <mpm@selenic.com> and others
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 import getopt
8 import getopt, util
9 from i18n import _
9 10
10 11 def gnugetopt(args, options, longoptions):
11 12 """Parse options mostly like getopt.gnu_getopt.
12 13
13 14 This is different from getopt.gnu_getopt in that an argument of - will
14 15 become an argument of - instead of vanishing completely.
15 16 """
16 17 extraargs = []
17 18 if '--' in args:
18 19 stopindex = args.index('--')
19 20 extraargs = args[stopindex + 1:]
20 21 args = args[:stopindex]
21 22 opts, parseargs = getopt.getopt(args, options, longoptions)
22 23 args = []
23 24 while parseargs:
24 25 arg = parseargs.pop(0)
25 26 if arg and arg[0] == '-' and len(arg) > 1:
26 27 parseargs.insert(0, arg)
27 28 topts, newparseargs = getopt.getopt(parseargs, options, longoptions)
28 29 opts = opts + topts
29 30 parseargs = newparseargs
30 31 else:
31 32 args.append(arg)
32 33 args.extend(extraargs)
33 34 return opts, args
34 35
35 36
36 37 def fancyopts(args, options, state, gnu=False):
37 38 """
38 39 read args, parse options, and store options in state
39 40
40 41 each option is a tuple of:
41 42
42 43 short option or ''
43 44 long option
44 45 default value
45 46 description
46 47 option value label(optional)
47 48
48 49 option types include:
49 50
50 51 boolean or none - option sets variable in state to true
51 52 string - parameter string is stored in state
52 53 list - parameter string is added to a list
53 54 integer - parameter strings is stored as int
54 55 function - call function with parameter
55 56
56 57 non-option args are returned
57 58 """
58 59 namelist = []
59 60 shortlist = ''
60 61 argmap = {}
61 62 defmap = {}
62 63
63 64 for option in options:
64 65 if len(option) == 5:
65 66 short, name, default, comment, dummy = option
66 67 else:
67 68 short, name, default, comment = option
68 69 # convert opts to getopt format
69 70 oname = name
70 71 name = name.replace('-', '_')
71 72
72 73 argmap['-' + short] = argmap['--' + oname] = name
73 74 defmap[name] = default
74 75
75 76 # copy defaults to state
76 77 if isinstance(default, list):
77 78 state[name] = default[:]
78 79 elif getattr(default, '__call__', False):
79 80 state[name] = None
80 81 else:
81 82 state[name] = default
82 83
83 84 # does it take a parameter?
84 85 if not (default is None or default is True or default is False):
85 86 if short:
86 87 short += ':'
87 88 if oname:
88 89 oname += '='
89 90 if short:
90 91 shortlist += short
91 92 if name:
92 93 namelist.append(oname)
93 94
94 95 # parse arguments
95 96 if gnu:
96 97 parse = gnugetopt
97 98 else:
98 99 parse = getopt.getopt
99 100 opts, args = parse(args, shortlist, namelist)
100 101
101 102 # transfer result to state
102 103 for opt, val in opts:
103 104 name = argmap[opt]
104 105 t = type(defmap[name])
105 106 if t is type(fancyopts):
106 107 state[name] = defmap[name](val)
107 108 elif t is type(1):
108 state[name] = int(val)
109 try:
110 state[name] = int(val)
111 except ValueError:
112 raise util.Abort(_('invalid value %r for option %s, '
113 'expected int') % (val, opt))
109 114 elif t is type(''):
110 115 state[name] = val
111 116 elif t is type([]):
112 117 state[name].append(val)
113 118 elif t is type(None) or t is type(False):
114 119 state[name] = True
115 120
116 121 # return unparsed args
117 122 return args
@@ -1,183 +1,170 b''
1 1 $ check_code="$TESTDIR"/../contrib/check-code.py
2 2 $ cd "$TESTDIR"/..
3 3 $ if hg identify -q > /dev/null; then :
4 4 > else
5 5 > echo "skipped: not a Mercurial working dir" >&2
6 6 > exit 80
7 7 > fi
8 8 $ hg manifest | xargs "$check_code" || echo 'FAILURE IS NOT AN OPTION!!!'
9 9
10 10 $ hg manifest | xargs "$check_code" --warnings --nolineno --per-file=0 || true
11 11 hgext/convert/cvsps.py:0:
12 12 > ui.write('Ancestors: %s\n' % (','.join(r)))
13 13 warning: unwrapped ui message
14 14 hgext/convert/cvsps.py:0:
15 15 > ui.write('Parent: %d\n' % cs.parents[0].id)
16 16 warning: unwrapped ui message
17 17 hgext/convert/cvsps.py:0:
18 18 > ui.write('Parents: %s\n' %
19 19 warning: unwrapped ui message
20 20 hgext/convert/cvsps.py:0:
21 21 > ui.write('Branchpoints: %s \n' % ', '.join(branchpoints))
22 22 warning: unwrapped ui message
23 23 hgext/convert/cvsps.py:0:
24 24 > ui.write('Author: %s\n' % cs.author)
25 25 warning: unwrapped ui message
26 26 hgext/convert/cvsps.py:0:
27 27 > ui.write('Branch: %s\n' % (cs.branch or 'HEAD'))
28 28 warning: unwrapped ui message
29 29 hgext/convert/cvsps.py:0:
30 30 > ui.write('Date: %s\n' % util.datestr(cs.date,
31 31 warning: unwrapped ui message
32 32 hgext/convert/cvsps.py:0:
33 33 > ui.write('Log:\n')
34 34 warning: unwrapped ui message
35 35 hgext/convert/cvsps.py:0:
36 36 > ui.write('Members: \n')
37 37 warning: unwrapped ui message
38 38 hgext/convert/cvsps.py:0:
39 39 > ui.write('PatchSet %d \n' % cs.id)
40 40 warning: unwrapped ui message
41 41 hgext/convert/cvsps.py:0:
42 42 > ui.write('Tag%s: %s \n' % (['', 's'][len(cs.tags) > 1],
43 43 warning: unwrapped ui message
44 44 hgext/hgk.py:0:
45 45 > ui.write("parent %s\n" % p)
46 46 warning: unwrapped ui message
47 47 hgext/hgk.py:0:
48 48 > ui.write('k=%s\nv=%s\n' % (name, value))
49 49 warning: unwrapped ui message
50 50 hgext/hgk.py:0:
51 51 > ui.write("author %s %s %s\n" % (ctx.user(), int(date[0]), date[1]))
52 52 warning: unwrapped ui message
53 53 hgext/hgk.py:0:
54 54 > ui.write("branch %s\n\n" % ctx.branch())
55 55 warning: unwrapped ui message
56 56 hgext/hgk.py:0:
57 57 > ui.write("committer %s %s %s\n" % (committer, int(date[0]), date[1]))
58 58 warning: unwrapped ui message
59 59 hgext/hgk.py:0:
60 60 > ui.write("revision %d\n" % ctx.rev())
61 61 warning: unwrapped ui message
62 62 hgext/hgk.py:0:
63 63 > ui.write("tree %s\n" % short(ctx.changeset()[0]))
64 64 warning: unwrapped ui message
65 65 hgext/mq.py:0:
66 66 > ui.write("mq: %s\n" % ', '.join(m))
67 67 warning: unwrapped ui message
68 68 hgext/patchbomb.py:0:
69 69 > ui.write('Subject: %s\n' % subj)
70 70 warning: unwrapped ui message
71 71 hgext/patchbomb.py:0:
72 72 > ui.write('From: %s\n' % sender)
73 73 warning: unwrapped ui message
74 74 mercurial/commands.py:0:
75 75 > ui.note('branch %s\n' % data)
76 76 warning: unwrapped ui message
77 77 mercurial/commands.py:0:
78 78 > ui.note('node %s\n' % str(data))
79 79 warning: unwrapped ui message
80 80 mercurial/commands.py:0:
81 81 > ui.note('tag %s\n' % name)
82 82 warning: unwrapped ui message
83 83 mercurial/commands.py:0:
84 84 > ui.write("unpruned common: %s\n" % " ".join([short(n)
85 85 warning: unwrapped ui message
86 86 mercurial/commands.py:0:
87 87 > ui.write("format: id, p1, p2, cset, delta base, len(delta)\n")
88 88 warning: unwrapped ui message
89 89 mercurial/commands.py:0:
90 90 > ui.write("local is subset\n")
91 91 warning: unwrapped ui message
92 92 mercurial/commands.py:0:
93 93 > ui.write("remote is subset\n")
94 94 warning: unwrapped ui message
95 95 mercurial/commands.py:0:
96 96 > ui.write('deltas against other : ' + fmt % pcfmt(numother,
97 97 warning: unwrapped ui message
98 98 mercurial/commands.py:0:
99 99 > ui.write('deltas against p1 : ' + fmt % pcfmt(nump1, numdeltas))
100 100 warning: unwrapped ui message
101 101 mercurial/commands.py:0:
102 102 > ui.write('deltas against p2 : ' + fmt % pcfmt(nump2, numdeltas))
103 103 warning: unwrapped ui message
104 104 mercurial/commands.py:0:
105 105 > ui.write("common heads: %s\n" % " ".join([short(n) for n in common]))
106 106 warning: unwrapped ui message
107 107 mercurial/commands.py:0:
108 108 > ui.write("match: %s\n" % m(d[0]))
109 109 warning: unwrapped ui message
110 110 mercurial/commands.py:0:
111 111 > ui.write('deltas against prev : ' + fmt % pcfmt(numprev, numdeltas))
112 112 warning: unwrapped ui message
113 113 mercurial/commands.py:0:
114 114 > ui.write('path %s\n' % k)
115 115 warning: unwrapped ui message
116 116 mercurial/commands.py:0:
117 117 > ui.write('uncompressed data size (min/max/avg) : %d / %d / %d\n'
118 118 warning: unwrapped ui message
119 119 mercurial/commands.py:0:
120 120 > ui.write("digraph G {\n")
121 121 warning: unwrapped ui message
122 122 mercurial/commands.py:0:
123 123 > ui.write("internal: %s %s\n" % d)
124 124 warning: unwrapped ui message
125 125 mercurial/commands.py:0:
126 126 > ui.write("standard: %s\n" % util.datestr(d))
127 127 warning: unwrapped ui message
128 128 mercurial/commands.py:0:
129 129 > ui.write('avg chain length : ' + fmt % avgchainlen)
130 130 warning: unwrapped ui message
131 131 mercurial/commands.py:0:
132 132 > ui.write('case-sensitive: %s\n' % (util.checkcase('.debugfsinfo')
133 133 warning: unwrapped ui message
134 134 mercurial/commands.py:0:
135 135 > ui.write('compression ratio : ' + fmt % compratio)
136 136 warning: unwrapped ui message
137 137 mercurial/commands.py:0:
138 138 > ui.write('delta size (min/max/avg) : %d / %d / %d\n'
139 139 warning: unwrapped ui message
140 140 mercurial/commands.py:0:
141 141 > ui.write('exec: %s\n' % (util.checkexec(path) and 'yes' or 'no'))
142 142 warning: unwrapped ui message
143 143 mercurial/commands.py:0:
144 144 > ui.write('flags : %s\n' % ', '.join(flags))
145 145 warning: unwrapped ui message
146 146 mercurial/commands.py:0:
147 147 > ui.write('format : %d\n' % format)
148 148 warning: unwrapped ui message
149 149 mercurial/commands.py:0:
150 150 > ui.write('full revision size (min/max/avg) : %d / %d / %d\n'
151 151 warning: unwrapped ui message
152 152 mercurial/commands.py:0:
153 153 > ui.write('revision size : ' + fmt2 % totalsize)
154 154 warning: unwrapped ui message
155 155 mercurial/commands.py:0:
156 156 > ui.write('revisions : ' + fmt2 % numrevs)
157 157 warning: unwrapped ui message
158 158 warning: unwrapped ui message
159 159 mercurial/commands.py:0:
160 160 > ui.write('symlink: %s\n' % (util.checklink(path) and 'yes' or 'no'))
161 161 warning: unwrapped ui message
162 162 tests/autodiff.py:0:
163 163 > ui.write('data lost for: %s\n' % fn)
164 164 warning: unwrapped ui message
165 tests/test-convert-mtn.t:0:
166 > > function get_passphrase(keypair_id)
167 don't use 'function', use old style
168 tests/test-import-git.t:0:
169 > > Mc\${NkU|\`?^000jF3jhEB
170 ^ must be quoted
171 tests/test-import.t:0:
172 > > diff -Naur proj-orig/foo proj-new/foo
173 don't use 'diff -N'
174 don't use 'diff -N'
175 tests/test-schemes.t:0:
176 > > z = file:\$PWD/
177 don't use $PWD, use `pwd`
178 165 tests/test-ui-color.py:0:
179 166 > testui.warn('warning\n')
180 167 warning: unwrapped ui message
181 168 tests/test-ui-color.py:0:
182 169 > testui.write('buffered\n')
183 170 warning: unwrapped ui message
@@ -1,119 +1,159 b''
1 1 Init repo1:
2 2
3 3 $ hg init repo1
4 4 $ cd repo1
5 5 $ echo "some text" > a
6 6 $ hg add
7 7 adding a
8 8 $ hg ci -m first
9 9 $ cat .hg/store/fncache | sort
10 10 data/a.i
11 11
12 12 Testing a.i/b:
13 13
14 14 $ mkdir a.i
15 15 $ echo "some other text" > a.i/b
16 16 $ hg add
17 17 adding a.i/b (glob)
18 18 $ hg ci -m second
19 19 $ cat .hg/store/fncache | sort
20 20 data/a.i
21 21 data/a.i.hg/b.i
22 22
23 23 Testing a.i.hg/c:
24 24
25 25 $ mkdir a.i.hg
26 26 $ echo "yet another text" > a.i.hg/c
27 27 $ hg add
28 28 adding a.i.hg/c (glob)
29 29 $ hg ci -m third
30 30 $ cat .hg/store/fncache | sort
31 31 data/a.i
32 32 data/a.i.hg.hg/c.i
33 33 data/a.i.hg/b.i
34 34
35 35 Testing verify:
36 36
37 37 $ hg verify
38 38 checking changesets
39 39 checking manifests
40 40 crosschecking files in changesets and manifests
41 41 checking files
42 42 3 files, 3 changesets, 3 total revisions
43 43
44 44 $ rm .hg/store/fncache
45 45
46 46 $ hg verify
47 47 checking changesets
48 48 checking manifests
49 49 crosschecking files in changesets and manifests
50 50 checking files
51 51 data/a.i@0: missing revlog!
52 52 data/a.i.hg/c.i@2: missing revlog!
53 53 data/a.i/b.i@1: missing revlog!
54 54 3 files, 3 changesets, 3 total revisions
55 55 3 integrity errors encountered!
56 56 (first damaged changeset appears to be 0)
57 57 [1]
58 58 $ cd ..
59 59
60 60 Non store repo:
61 61
62 62 $ hg --config format.usestore=False init foo
63 63 $ cd foo
64 64 $ mkdir tst.d
65 65 $ echo foo > tst.d/foo
66 66 $ hg ci -Amfoo
67 67 adding tst.d/foo
68 68 $ find .hg | sort
69 69 .hg
70 70 .hg/00changelog.i
71 71 .hg/00manifest.i
72 72 .hg/cache
73 73 .hg/cache/branchheads
74 74 .hg/data
75 75 .hg/data/tst.d.hg
76 76 .hg/data/tst.d.hg/foo.i
77 77 .hg/dirstate
78 78 .hg/last-message.txt
79 79 .hg/phaseroots
80 80 .hg/requires
81 81 .hg/undo
82 82 .hg/undo.bookmarks
83 83 .hg/undo.branch
84 84 .hg/undo.desc
85 85 .hg/undo.dirstate
86 86 .hg/undo.phaseroots
87 87 $ cd ..
88 88
89 89 Non fncache repo:
90 90
91 91 $ hg --config format.usefncache=False init bar
92 92 $ cd bar
93 93 $ mkdir tst.d
94 94 $ echo foo > tst.d/Foo
95 95 $ hg ci -Amfoo
96 96 adding tst.d/Foo
97 97 $ find .hg | sort
98 98 .hg
99 99 .hg/00changelog.i
100 100 .hg/cache
101 101 .hg/cache/branchheads
102 102 .hg/dirstate
103 103 .hg/last-message.txt
104 104 .hg/requires
105 105 .hg/store
106 106 .hg/store/00changelog.i
107 107 .hg/store/00manifest.i
108 108 .hg/store/data
109 109 .hg/store/data/tst.d.hg
110 110 .hg/store/data/tst.d.hg/_foo.i
111 111 .hg/store/phaseroots
112 112 .hg/store/undo
113 113 .hg/store/undo.phaseroots
114 114 .hg/undo.bookmarks
115 115 .hg/undo.branch
116 116 .hg/undo.desc
117 117 .hg/undo.dirstate
118 118 $ cd ..
119 119
120 #if no-windows
121
122 Encoding of reserved / long paths in the store
123
124 $ hg init r2
125 $ cd r2
126 $ cat <<EOF > .hg/hgrc
127 > [ui]
128 > portablefilenames = ignore
129 > EOF
130
131 $ DIR="bla.aux/prn/PRN/lpt/com3/nul/coma/foo.NUL"
132 $ mkdir -p "$DIR"
133 $ echo foo > "$DIR/normal.c"
134 $ DIR="AUX/SECOND/X.PRN/FOURTH/FI:FTH/SIXTH/SEVENTH/EIGHTH/NINETH/TENTH/ELEVENTH"
135 $ mkdir -p "$DIR"
136 $ echo foo > "$DIR/LOREMIPSUM.TXT"
137 $ DIR="enterprise/openesbaddons/contrib-imola/corba-bc/netbeansplugin/wsdlExtension/src/main/java/META-INF/services"
138 $ mkdir -p "$DIR"
139 $ echo foo > "$DIR/org.netbeans.modules.xml.wsdl.bindingsupport.spi.ExtensibilityElementTemplateProvider"
140 $ DIR="Project Planning/Resources/AnotherLongDirectoryName/Followedbyanother/AndAnother"
141 $ mkdir -p "$DIR"
142 $ echo foo > "$DIR/AndThenAnExtremelyLongFileName.txt"
143 $ DIR="12345678/12345678/12345678/12345678/12345678/12345678/12345678/12345"
144 $ mkdir -p "$DIR"
145 $ echo foo > "$DIR/xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-123456789-12.3456789-12345-ABCDEFGHIJKLMNOPRSTUVWXYZ-abcdefghjiklmnopqrstuvwxyz"
146 $ hg ci -qAm1
147 $ find .hg/store -name *.i | sort
148 .hg/store/00changelog.i
149 .hg/store/00manifest.i
150 .hg/store/data/bla.aux/pr~6e/_p_r_n/lpt/co~6d3/nu~6c/coma/foo._n_u_l/normal.c.i
151 .hg/store/dh/12345678/12345678/12345678/12345678/12345678/12345678/12345678/12345/xxxxxx168e07b38e65eff86ab579afaaa8e30bfbe0f35f.i
152 .hg/store/dh/au~78/second/x.prn/fourth/fi~3afth/sixth/seventh/eighth/nineth/tenth/loremia20419e358ddff1bf8751e38288aff1d7c32ec05.i
153 .hg/store/dh/enterpri/openesba/contrib-/corba-bc/netbeans/wsdlexte/src/main/java/org.net7018f27961fdf338a598a40c4683429e7ffb9743.i
154 .hg/store/dh/project_/resource/anotherl/followed/andanoth/andthenanextremelylongfilename0d8e1f4187c650e2f1fdca9fd90f786bc0976b6b.i
155
156 $ cd ..
157
158 #endif
159
@@ -1,1155 +1,1158 b''
1 1 $ hg init a
2 2 $ mkdir a/d1
3 3 $ mkdir a/d1/d2
4 4 $ echo line 1 > a/a
5 5 $ echo line 1 > a/d1/d2/a
6 6 $ hg --cwd a ci -Ama
7 7 adding a
8 8 adding d1/d2/a
9 9
10 10 $ echo line 2 >> a/a
11 11 $ hg --cwd a ci -u someone -d '1 0' -m'second change'
12 12
13 13 import with no args:
14 14
15 15 $ hg --cwd a import
16 16 abort: need at least one patch to import
17 17 [255]
18 18
19 19 generate patches for the test
20 20
21 21 $ hg --cwd a export tip > exported-tip.patch
22 22 $ hg --cwd a diff -r0:1 > diffed-tip.patch
23 23
24 24
25 25 import exported patch
26 26
27 27 $ hg clone -r0 a b
28 28 adding changesets
29 29 adding manifests
30 30 adding file changes
31 31 added 1 changesets with 2 changes to 2 files
32 32 updating to branch default
33 33 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
34 34 $ hg --cwd b import ../exported-tip.patch
35 35 applying ../exported-tip.patch
36 36
37 37 message and committer should be same
38 38
39 39 $ hg --cwd b tip
40 40 changeset: 1:1d4bd90af0e4
41 41 tag: tip
42 42 user: someone
43 43 date: Thu Jan 01 00:00:01 1970 +0000
44 44 summary: second change
45 45
46 46 $ rm -r b
47 47
48 48
49 49 import exported patch with external patcher
50 50
51 51 $ cat > dummypatch.py <<EOF
52 52 > print 'patching file a'
53 53 > file('a', 'wb').write('line2\n')
54 54 > EOF
55 55 $ hg clone -r0 a b
56 56 adding changesets
57 57 adding manifests
58 58 adding file changes
59 59 added 1 changesets with 2 changes to 2 files
60 60 updating to branch default
61 61 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
62 62 $ hg --config ui.patch='python ../dummypatch.py' --cwd b import ../exported-tip.patch
63 63 applying ../exported-tip.patch
64 64 $ cat b/a
65 65 line2
66 66 $ rm -r b
67 67
68 68
69 69 import of plain diff should fail without message
70 70
71 71 $ hg clone -r0 a b
72 72 adding changesets
73 73 adding manifests
74 74 adding file changes
75 75 added 1 changesets with 2 changes to 2 files
76 76 updating to branch default
77 77 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
78 78 $ hg --cwd b import ../diffed-tip.patch
79 79 applying ../diffed-tip.patch
80 80 abort: empty commit message
81 81 [255]
82 82 $ rm -r b
83 83
84 84
85 85 import of plain diff should be ok with message
86 86
87 87 $ hg clone -r0 a b
88 88 adding changesets
89 89 adding manifests
90 90 adding file changes
91 91 added 1 changesets with 2 changes to 2 files
92 92 updating to branch default
93 93 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
94 94 $ hg --cwd b import -mpatch ../diffed-tip.patch
95 95 applying ../diffed-tip.patch
96 96 $ rm -r b
97 97
98 98
99 99 import of plain diff with specific date and user
100 100
101 101 $ hg clone -r0 a b
102 102 adding changesets
103 103 adding manifests
104 104 adding file changes
105 105 added 1 changesets with 2 changes to 2 files
106 106 updating to branch default
107 107 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
108 108 $ hg --cwd b import -mpatch -d '1 0' -u 'user@nowhere.net' ../diffed-tip.patch
109 109 applying ../diffed-tip.patch
110 110 $ hg -R b tip -pv
111 111 changeset: 1:ca68f19f3a40
112 112 tag: tip
113 113 user: user@nowhere.net
114 114 date: Thu Jan 01 00:00:01 1970 +0000
115 115 files: a
116 116 description:
117 117 patch
118 118
119 119
120 120 diff -r 80971e65b431 -r ca68f19f3a40 a
121 121 --- a/a Thu Jan 01 00:00:00 1970 +0000
122 122 +++ b/a Thu Jan 01 00:00:01 1970 +0000
123 123 @@ -1,1 +1,2 @@
124 124 line 1
125 125 +line 2
126 126
127 127 $ rm -r b
128 128
129 129
130 130 import of plain diff should be ok with --no-commit
131 131
132 132 $ hg clone -r0 a b
133 133 adding changesets
134 134 adding manifests
135 135 adding file changes
136 136 added 1 changesets with 2 changes to 2 files
137 137 updating to branch default
138 138 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
139 139 $ hg --cwd b import --no-commit ../diffed-tip.patch
140 140 applying ../diffed-tip.patch
141 141 $ hg --cwd b diff --nodates
142 142 diff -r 80971e65b431 a
143 143 --- a/a
144 144 +++ b/a
145 145 @@ -1,1 +1,2 @@
146 146 line 1
147 147 +line 2
148 148 $ rm -r b
149 149
150 150
151 151 import of malformed plain diff should fail
152 152
153 153 $ hg clone -r0 a b
154 154 adding changesets
155 155 adding manifests
156 156 adding file changes
157 157 added 1 changesets with 2 changes to 2 files
158 158 updating to branch default
159 159 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
160 160 $ sed 's/1,1/foo/' < diffed-tip.patch > broken.patch
161 161 $ hg --cwd b import -mpatch ../broken.patch
162 162 applying ../broken.patch
163 163 abort: bad hunk #1
164 164 [255]
165 165 $ rm -r b
166 166
167 167
168 168 hg -R repo import
169 169 put the clone in a subdir - having a directory named "a"
170 170 used to hide a bug.
171 171
172 172 $ mkdir dir
173 173 $ hg clone -r0 a dir/b
174 174 adding changesets
175 175 adding manifests
176 176 adding file changes
177 177 added 1 changesets with 2 changes to 2 files
178 178 updating to branch default
179 179 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
180 180 $ cd dir
181 181 $ hg -R b import ../exported-tip.patch
182 182 applying ../exported-tip.patch
183 183 $ cd ..
184 184 $ rm -r dir
185 185
186 186
187 187 import from stdin
188 188
189 189 $ hg clone -r0 a b
190 190 adding changesets
191 191 adding manifests
192 192 adding file changes
193 193 added 1 changesets with 2 changes to 2 files
194 194 updating to branch default
195 195 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
196 196 $ hg --cwd b import - < exported-tip.patch
197 197 applying patch from stdin
198 198 $ rm -r b
199 199
200 200
201 201 import two patches in one stream
202 202
203 203 $ hg init b
204 204 $ hg --cwd a export 0:tip | hg --cwd b import -
205 205 applying patch from stdin
206 206 $ hg --cwd a id
207 207 1d4bd90af0e4 tip
208 208 $ hg --cwd b id
209 209 1d4bd90af0e4 tip
210 210 $ rm -r b
211 211
212 212
213 213 override commit message
214 214
215 215 $ hg clone -r0 a b
216 216 adding changesets
217 217 adding manifests
218 218 adding file changes
219 219 added 1 changesets with 2 changes to 2 files
220 220 updating to branch default
221 221 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
222 222 $ hg --cwd b import -m 'override' - < exported-tip.patch
223 223 applying patch from stdin
224 224 $ hg --cwd b tip | grep override
225 225 summary: override
226 226 $ rm -r b
227 227
228 228 $ cat > mkmsg.py <<EOF
229 229 > import email.Message, sys
230 230 > msg = email.Message.Message()
231 231 > patch = open(sys.argv[1], 'rb').read()
232 232 > msg.set_payload('email commit message\n' + patch)
233 233 > msg['Subject'] = 'email patch'
234 234 > msg['From'] = 'email patcher'
235 235 > file(sys.argv[2], 'wb').write(msg.as_string())
236 236 > EOF
237 237
238 238
239 239 plain diff in email, subject, message body
240 240
241 241 $ hg clone -r0 a b
242 242 adding changesets
243 243 adding manifests
244 244 adding file changes
245 245 added 1 changesets with 2 changes to 2 files
246 246 updating to branch default
247 247 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
248 248 $ python mkmsg.py diffed-tip.patch msg.patch
249 249 $ hg --cwd b import ../msg.patch
250 250 applying ../msg.patch
251 251 $ hg --cwd b tip | grep email
252 252 user: email patcher
253 253 summary: email patch
254 254 $ rm -r b
255 255
256 256
257 257 plain diff in email, no subject, message body
258 258
259 259 $ hg clone -r0 a b
260 260 adding changesets
261 261 adding manifests
262 262 adding file changes
263 263 added 1 changesets with 2 changes to 2 files
264 264 updating to branch default
265 265 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
266 266 $ grep -v '^Subject:' msg.patch | hg --cwd b import -
267 267 applying patch from stdin
268 268 $ rm -r b
269 269
270 270
271 271 plain diff in email, subject, no message body
272 272
273 273 $ hg clone -r0 a b
274 274 adding changesets
275 275 adding manifests
276 276 adding file changes
277 277 added 1 changesets with 2 changes to 2 files
278 278 updating to branch default
279 279 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
280 280 $ grep -v '^email ' msg.patch | hg --cwd b import -
281 281 applying patch from stdin
282 282 $ rm -r b
283 283
284 284
285 285 plain diff in email, no subject, no message body, should fail
286 286
287 287 $ hg clone -r0 a b
288 288 adding changesets
289 289 adding manifests
290 290 adding file changes
291 291 added 1 changesets with 2 changes to 2 files
292 292 updating to branch default
293 293 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
294 294 $ egrep -v '^(Subject|email)' msg.patch | hg --cwd b import -
295 295 applying patch from stdin
296 296 abort: empty commit message
297 297 [255]
298 298 $ rm -r b
299 299
300 300
301 301 hg export in email, should use patch header
302 302
303 303 $ hg clone -r0 a b
304 304 adding changesets
305 305 adding manifests
306 306 adding file changes
307 307 added 1 changesets with 2 changes to 2 files
308 308 updating to branch default
309 309 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
310 310 $ python mkmsg.py exported-tip.patch msg.patch
311 311 $ cat msg.patch | hg --cwd b import -
312 312 applying patch from stdin
313 313 $ hg --cwd b tip | grep second
314 314 summary: second change
315 315 $ rm -r b
316 316
317 317
318 318 subject: duplicate detection, removal of [PATCH]
319 319 The '---' tests the gitsendmail handling without proper mail headers
320 320
321 321 $ cat > mkmsg2.py <<EOF
322 322 > import email.Message, sys
323 323 > msg = email.Message.Message()
324 324 > patch = open(sys.argv[1], 'rb').read()
325 325 > msg.set_payload('email patch\n\nnext line\n---\n' + patch)
326 326 > msg['Subject'] = '[PATCH] email patch'
327 327 > msg['From'] = 'email patcher'
328 328 > file(sys.argv[2], 'wb').write(msg.as_string())
329 329 > EOF
330 330
331 331
332 332 plain diff in email, [PATCH] subject, message body with subject
333 333
334 334 $ hg clone -r0 a b
335 335 adding changesets
336 336 adding manifests
337 337 adding file changes
338 338 added 1 changesets with 2 changes to 2 files
339 339 updating to branch default
340 340 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
341 341 $ python mkmsg2.py diffed-tip.patch msg.patch
342 342 $ cat msg.patch | hg --cwd b import -
343 343 applying patch from stdin
344 344 $ hg --cwd b tip --template '{desc}\n'
345 345 email patch
346 346
347 347 next line
348 348 ---
349 349 $ rm -r b
350 350
351 351
352 352 Issue963: Parent of working dir incorrect after import of multiple
353 353 patches and rollback
354 354
355 355 We weren't backing up the correct dirstate file when importing many
356 356 patches: import patch1 patch2; rollback
357 357
358 358 $ echo line 3 >> a/a
359 359 $ hg --cwd a ci -m'third change'
360 360 $ hg --cwd a export -o '../patch%R' 1 2
361 361 $ hg clone -qr0 a b
362 362 $ hg --cwd b parents --template 'parent: {rev}\n'
363 363 parent: 0
364 364 $ hg --cwd b import -v ../patch1 ../patch2
365 365 applying ../patch1
366 366 patching file a
367 367 a
368 368 created 1d4bd90af0e4
369 369 applying ../patch2
370 370 patching file a
371 371 a
372 372 created 6d019af21222
373 373 $ hg --cwd b rollback
374 374 repository tip rolled back to revision 0 (undo import)
375 375 working directory now based on revision 0
376 376 $ hg --cwd b parents --template 'parent: {rev}\n'
377 377 parent: 0
378 378 $ rm -r b
379 379
380 380
381 381 importing a patch in a subdirectory failed at the commit stage
382 382
383 383 $ echo line 2 >> a/d1/d2/a
384 384 $ hg --cwd a ci -u someoneelse -d '1 0' -m'subdir change'
385 385
386 386 hg import in a subdirectory
387 387
388 388 $ hg clone -r0 a b
389 389 adding changesets
390 390 adding manifests
391 391 adding file changes
392 392 added 1 changesets with 2 changes to 2 files
393 393 updating to branch default
394 394 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
395 395 $ hg --cwd a export tip > tmp
396 396 $ sed -e 's/d1\/d2\///' < tmp > subdir-tip.patch
397 397 $ dir=`pwd`
398 398 $ cd b/d1/d2 2>&1 > /dev/null
399 399 $ hg import ../../../subdir-tip.patch
400 400 applying ../../../subdir-tip.patch
401 401 $ cd "$dir"
402 402
403 403 message should be 'subdir change'
404 404 committer should be 'someoneelse'
405 405
406 406 $ hg --cwd b tip
407 407 changeset: 1:3577f5aea227
408 408 tag: tip
409 409 user: someoneelse
410 410 date: Thu Jan 01 00:00:01 1970 +0000
411 411 summary: subdir change
412 412
413 413
414 414 should be empty
415 415
416 416 $ hg --cwd b status
417 417
418 418
419 419 Test fuzziness (ambiguous patch location, fuzz=2)
420 420
421 421 $ hg init fuzzy
422 422 $ cd fuzzy
423 423 $ echo line1 > a
424 424 $ echo line0 >> a
425 425 $ echo line3 >> a
426 426 $ hg ci -Am adda
427 427 adding a
428 428 $ echo line1 > a
429 429 $ echo line2 >> a
430 430 $ echo line0 >> a
431 431 $ echo line3 >> a
432 432 $ hg ci -m change a
433 433 $ hg export tip > fuzzy-tip.patch
434 434 $ hg up -C 0
435 435 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
436 436 $ echo line1 > a
437 437 $ echo line0 >> a
438 438 $ echo line1 >> a
439 439 $ echo line0 >> a
440 440 $ hg ci -m brancha
441 441 created new head
442 442 $ hg import --no-commit -v fuzzy-tip.patch
443 443 applying fuzzy-tip.patch
444 444 patching file a
445 445 Hunk #1 succeeded at 2 with fuzz 1 (offset 0 lines).
446 446 applied to working directory
447 447 $ hg revert -a
448 448 reverting a
449 449
450 450
451 451 import with --no-commit should have written .hg/last-message.txt
452 452
453 453 $ cat .hg/last-message.txt
454 454 change (no-eol)
455 455
456 456
457 457 test fuzziness with eol=auto
458 458
459 459 $ hg --config patch.eol=auto import --no-commit -v fuzzy-tip.patch
460 460 applying fuzzy-tip.patch
461 461 patching file a
462 462 Hunk #1 succeeded at 2 with fuzz 1 (offset 0 lines).
463 463 applied to working directory
464 464 $ cd ..
465 465
466 466
467 467 Test hunk touching empty files (issue906)
468 468
469 469 $ hg init empty
470 470 $ cd empty
471 471 $ touch a
472 472 $ touch b1
473 473 $ touch c1
474 474 $ echo d > d
475 475 $ hg ci -Am init
476 476 adding a
477 477 adding b1
478 478 adding c1
479 479 adding d
480 480 $ echo a > a
481 481 $ echo b > b1
482 482 $ hg mv b1 b2
483 483 $ echo c > c1
484 484 $ hg copy c1 c2
485 485 $ rm d
486 486 $ touch d
487 487 $ hg diff --git
488 488 diff --git a/a b/a
489 489 --- a/a
490 490 +++ b/a
491 491 @@ -0,0 +1,1 @@
492 492 +a
493 493 diff --git a/b1 b/b2
494 494 rename from b1
495 495 rename to b2
496 496 --- a/b1
497 497 +++ b/b2
498 498 @@ -0,0 +1,1 @@
499 499 +b
500 500 diff --git a/c1 b/c1
501 501 --- a/c1
502 502 +++ b/c1
503 503 @@ -0,0 +1,1 @@
504 504 +c
505 505 diff --git a/c1 b/c2
506 506 copy from c1
507 507 copy to c2
508 508 --- a/c1
509 509 +++ b/c2
510 510 @@ -0,0 +1,1 @@
511 511 +c
512 512 diff --git a/d b/d
513 513 --- a/d
514 514 +++ b/d
515 515 @@ -1,1 +0,0 @@
516 516 -d
517 517 $ hg ci -m empty
518 518 $ hg export --git tip > empty.diff
519 519 $ hg up -C 0
520 520 4 files updated, 0 files merged, 2 files removed, 0 files unresolved
521 521 $ hg import empty.diff
522 522 applying empty.diff
523 523 $ for name in a b1 b2 c1 c2 d; do
524 524 > echo % $name file
525 525 > test -f $name && cat $name
526 526 > done
527 527 % a file
528 528 a
529 529 % b1 file
530 530 % b2 file
531 531 b
532 532 % c1 file
533 533 c
534 534 % c2 file
535 535 c
536 536 % d file
537 537 $ cd ..
538 538
539 539
540 540 Test importing a patch ending with a binary file removal
541 541
542 542 $ hg init binaryremoval
543 543 $ cd binaryremoval
544 544 $ echo a > a
545 545 $ python -c "file('b', 'wb').write('a\x00b')"
546 546 $ hg ci -Am addall
547 547 adding a
548 548 adding b
549 549 $ hg rm a
550 550 $ hg rm b
551 551 $ hg st
552 552 R a
553 553 R b
554 554 $ hg ci -m remove
555 555 $ hg export --git . > remove.diff
556 556 $ cat remove.diff | grep git
557 557 diff --git a/a b/a
558 558 diff --git a/b b/b
559 559 $ hg up -C 0
560 560 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
561 561 $ hg import remove.diff
562 562 applying remove.diff
563 563 $ hg manifest
564 564 $ cd ..
565 565
566 566
567 567 Issue927: test update+rename with common name
568 568
569 569 $ hg init t
570 570 $ cd t
571 571 $ touch a
572 572 $ hg ci -Am t
573 573 adding a
574 574 $ echo a > a
575 575
576 576 Here, bfile.startswith(afile)
577 577
578 578 $ hg copy a a2
579 579 $ hg ci -m copya
580 580 $ hg export --git tip > copy.diff
581 581 $ hg up -C 0
582 582 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
583 583 $ hg import copy.diff
584 584 applying copy.diff
585 585
586 586 a should contain an 'a'
587 587
588 588 $ cat a
589 589 a
590 590
591 591 and a2 should have duplicated it
592 592
593 593 $ cat a2
594 594 a
595 595 $ cd ..
596 596
597 597
598 598 test -p0
599 599
600 600 $ hg init p0
601 601 $ cd p0
602 602 $ echo a > a
603 603 $ hg ci -Am t
604 604 adding a
605 $ hg import -p foo
606 abort: invalid value 'foo' for option -p, expected int
607 [255]
605 608 $ hg import -p0 - << EOF
606 609 > foobar
607 610 > --- a Sat Apr 12 22:43:58 2008 -0400
608 611 > +++ a Sat Apr 12 22:44:05 2008 -0400
609 612 > @@ -1,1 +1,1 @@
610 613 > -a
611 614 > +bb
612 615 > EOF
613 616 applying patch from stdin
614 617 $ hg status
615 618 $ cat a
616 619 bb
617 620 $ cd ..
618 621
619 622
620 623 test paths outside repo root
621 624
622 625 $ mkdir outside
623 626 $ touch outside/foo
624 627 $ hg init inside
625 628 $ cd inside
626 629 $ hg import - <<EOF
627 630 > diff --git a/a b/b
628 631 > rename from ../outside/foo
629 632 > rename to bar
630 633 > EOF
631 634 applying patch from stdin
632 635 abort: path contains illegal component: ../outside/foo (glob)
633 636 [255]
634 637 $ cd ..
635 638
636 639
637 640 test import with similarity and git and strip (issue295 et al.)
638 641
639 642 $ hg init sim
640 643 $ cd sim
641 644 $ echo 'this is a test' > a
642 645 $ hg ci -Ama
643 646 adding a
644 647 $ cat > ../rename.diff <<EOF
645 648 > diff --git a/foo/a b/foo/a
646 649 > deleted file mode 100644
647 650 > --- a/foo/a
648 651 > +++ /dev/null
649 652 > @@ -1,1 +0,0 @@
650 653 > -this is a test
651 654 > diff --git a/foo/b b/foo/b
652 655 > new file mode 100644
653 656 > --- /dev/null
654 657 > +++ b/foo/b
655 658 > @@ -0,0 +1,2 @@
656 659 > +this is a test
657 660 > +foo
658 661 > EOF
659 662 $ hg import --no-commit -v -s 1 ../rename.diff -p2
660 663 applying ../rename.diff
661 664 patching file a
662 665 patching file b
663 666 adding b
664 667 recording removal of a as rename to b (88% similar)
665 668 applied to working directory
666 669 $ hg st -C
667 670 A b
668 671 a
669 672 R a
670 673 $ hg revert -a
671 674 undeleting a
672 675 forgetting b
673 676 $ rm b
674 677 $ hg import --no-commit -v -s 100 ../rename.diff -p2
675 678 applying ../rename.diff
676 679 patching file a
677 680 patching file b
678 681 adding b
679 682 applied to working directory
680 683 $ hg st -C
681 684 A b
682 685 R a
683 686 $ cd ..
684 687
685 688
686 689 Issue1495: add empty file from the end of patch
687 690
688 691 $ hg init addemptyend
689 692 $ cd addemptyend
690 693 $ touch a
691 694 $ hg addremove
692 695 adding a
693 696 $ hg ci -m "commit"
694 697 $ cat > a.patch <<EOF
695 698 > add a, b
696 699 > diff --git a/a b/a
697 700 > --- a/a
698 701 > +++ b/a
699 702 > @@ -0,0 +1,1 @@
700 703 > +a
701 704 > diff --git a/b b/b
702 705 > new file mode 100644
703 706 > EOF
704 707 $ hg import --no-commit a.patch
705 708 applying a.patch
706 709
707 710 apply a good patch followed by an empty patch (mainly to ensure
708 711 that dirstate is *not* updated when import crashes)
709 712 $ hg update -q -C .
710 713 $ rm b
711 714 $ touch empty.patch
712 715 $ hg import a.patch empty.patch
713 716 applying a.patch
714 717 applying empty.patch
715 718 transaction abort!
716 719 rollback completed
717 720 abort: empty.patch: no diffs found
718 721 [255]
719 722 $ hg tip --template '{rev} {desc|firstline}\n'
720 723 0 commit
721 724 $ hg -q status
722 725 M a
723 726 $ cd ..
724 727
725 728 create file when source is not /dev/null
726 729
727 730 $ cat > create.patch <<EOF
728 731 > diff -Naur proj-orig/foo proj-new/foo
729 732 > --- proj-orig/foo 1969-12-31 16:00:00.000000000 -0800
730 733 > +++ proj-new/foo 2009-07-17 16:50:45.801368000 -0700
731 734 > @@ -0,0 +1,1 @@
732 735 > +a
733 736 > EOF
734 737
735 738 some people have patches like the following too
736 739
737 740 $ cat > create2.patch <<EOF
738 741 > diff -Naur proj-orig/foo proj-new/foo
739 742 > --- proj-orig/foo.orig 1969-12-31 16:00:00.000000000 -0800
740 743 > +++ proj-new/foo 2009-07-17 16:50:45.801368000 -0700
741 744 > @@ -0,0 +1,1 @@
742 745 > +a
743 746 > EOF
744 747 $ hg init oddcreate
745 748 $ cd oddcreate
746 749 $ hg import --no-commit ../create.patch
747 750 applying ../create.patch
748 751 $ cat foo
749 752 a
750 753 $ rm foo
751 754 $ hg revert foo
752 755 $ hg import --no-commit ../create2.patch
753 756 applying ../create2.patch
754 757 $ cat foo
755 758 a
756 759
757 760 $ cd ..
758 761
759 762 Issue1859: first line mistaken for email headers
760 763
761 764 $ hg init emailconfusion
762 765 $ cd emailconfusion
763 766 $ cat > a.patch <<EOF
764 767 > module: summary
765 768 >
766 769 > description
767 770 >
768 771 >
769 772 > diff -r 000000000000 -r 9b4c1e343b55 test.txt
770 773 > --- /dev/null
771 774 > +++ b/a
772 775 > @@ -0,0 +1,1 @@
773 776 > +a
774 777 > EOF
775 778 $ hg import -d '0 0' a.patch
776 779 applying a.patch
777 780 $ hg parents -v
778 781 changeset: 0:5a681217c0ad
779 782 tag: tip
780 783 user: test
781 784 date: Thu Jan 01 00:00:00 1970 +0000
782 785 files: a
783 786 description:
784 787 module: summary
785 788
786 789 description
787 790
788 791
789 792 $ cd ..
790 793
791 794
792 795 in commit message
793 796
794 797 $ hg init commitconfusion
795 798 $ cd commitconfusion
796 799 $ cat > a.patch <<EOF
797 800 > module: summary
798 801 >
799 802 > --- description
800 803 >
801 804 > diff --git a/a b/a
802 805 > new file mode 100644
803 806 > --- /dev/null
804 807 > +++ b/a
805 808 > @@ -0,0 +1,1 @@
806 809 > +a
807 810 > EOF
808 811 > hg import -d '0 0' a.patch
809 812 > hg parents -v
810 813 > cd ..
811 814 >
812 815 > echo '% tricky header splitting'
813 816 > cat > trickyheaders.patch <<EOF
814 817 > From: User A <user@a>
815 818 > Subject: [PATCH] from: tricky!
816 819 >
817 820 > # HG changeset patch
818 821 > # User User B
819 822 > # Date 1266264441 18000
820 823 > # Branch stable
821 824 > # Node ID f2be6a1170ac83bf31cb4ae0bad00d7678115bc0
822 825 > # Parent 0000000000000000000000000000000000000000
823 826 > from: tricky!
824 827 >
825 828 > That is not a header.
826 829 >
827 830 > diff -r 000000000000 -r f2be6a1170ac foo
828 831 > --- /dev/null
829 832 > +++ b/foo
830 833 > @@ -0,0 +1,1 @@
831 834 > +foo
832 835 > EOF
833 836 applying a.patch
834 837 changeset: 0:f34d9187897d
835 838 tag: tip
836 839 user: test
837 840 date: Thu Jan 01 00:00:00 1970 +0000
838 841 files: a
839 842 description:
840 843 module: summary
841 844
842 845
843 846 % tricky header splitting
844 847
845 848 $ hg init trickyheaders
846 849 $ cd trickyheaders
847 850 $ hg import -d '0 0' ../trickyheaders.patch
848 851 applying ../trickyheaders.patch
849 852 $ hg export --git tip
850 853 # HG changeset patch
851 854 # User User B
852 855 # Date 0 0
853 856 # Node ID eb56ab91903632294ac504838508cb370c0901d2
854 857 # Parent 0000000000000000000000000000000000000000
855 858 from: tricky!
856 859
857 860 That is not a header.
858 861
859 862 diff --git a/foo b/foo
860 863 new file mode 100644
861 864 --- /dev/null
862 865 +++ b/foo
863 866 @@ -0,0 +1,1 @@
864 867 +foo
865 868 $ cd ..
866 869
867 870
868 871 Issue2102: hg export and hg import speak different languages
869 872
870 873 $ hg init issue2102
871 874 $ cd issue2102
872 875 $ mkdir -p src/cmd/gc
873 876 $ touch src/cmd/gc/mksys.bash
874 877 $ hg ci -Am init
875 878 adding src/cmd/gc/mksys.bash
876 879 $ hg import - <<EOF
877 880 > # HG changeset patch
878 881 > # User Rob Pike
879 882 > # Date 1216685449 25200
880 883 > # Node ID 03aa2b206f499ad6eb50e6e207b9e710d6409c98
881 884 > # Parent 93d10138ad8df586827ca90b4ddb5033e21a3a84
882 885 > help management of empty pkg and lib directories in perforce
883 886 >
884 887 > R=gri
885 888 > DELTA=4 (4 added, 0 deleted, 0 changed)
886 889 > OCL=13328
887 890 > CL=13328
888 891 >
889 892 > diff --git a/lib/place-holder b/lib/place-holder
890 893 > new file mode 100644
891 894 > --- /dev/null
892 895 > +++ b/lib/place-holder
893 896 > @@ -0,0 +1,2 @@
894 897 > +perforce does not maintain empty directories.
895 898 > +this file helps.
896 899 > diff --git a/pkg/place-holder b/pkg/place-holder
897 900 > new file mode 100644
898 901 > --- /dev/null
899 902 > +++ b/pkg/place-holder
900 903 > @@ -0,0 +1,2 @@
901 904 > +perforce does not maintain empty directories.
902 905 > +this file helps.
903 906 > diff --git a/src/cmd/gc/mksys.bash b/src/cmd/gc/mksys.bash
904 907 > old mode 100644
905 908 > new mode 100755
906 909 > EOF
907 910 applying patch from stdin
908 911
909 912 #if execbit
910 913
911 914 $ hg sum
912 915 parent: 1:d59915696727 tip
913 916 help management of empty pkg and lib directories in perforce
914 917 branch: default
915 918 commit: (clean)
916 919 update: (current)
917 920
918 921 $ hg diff --git -c tip
919 922 diff --git a/lib/place-holder b/lib/place-holder
920 923 new file mode 100644
921 924 --- /dev/null
922 925 +++ b/lib/place-holder
923 926 @@ -0,0 +1,2 @@
924 927 +perforce does not maintain empty directories.
925 928 +this file helps.
926 929 diff --git a/pkg/place-holder b/pkg/place-holder
927 930 new file mode 100644
928 931 --- /dev/null
929 932 +++ b/pkg/place-holder
930 933 @@ -0,0 +1,2 @@
931 934 +perforce does not maintain empty directories.
932 935 +this file helps.
933 936 diff --git a/src/cmd/gc/mksys.bash b/src/cmd/gc/mksys.bash
934 937 old mode 100644
935 938 new mode 100755
936 939
937 940 #else
938 941
939 942 $ hg sum
940 943 parent: 1:28f089cc9ccc tip
941 944 help management of empty pkg and lib directories in perforce
942 945 branch: default
943 946 commit: (clean)
944 947 update: (current)
945 948
946 949 $ hg diff --git -c tip
947 950 diff --git a/lib/place-holder b/lib/place-holder
948 951 new file mode 100644
949 952 --- /dev/null
950 953 +++ b/lib/place-holder
951 954 @@ -0,0 +1,2 @@
952 955 +perforce does not maintain empty directories.
953 956 +this file helps.
954 957 diff --git a/pkg/place-holder b/pkg/place-holder
955 958 new file mode 100644
956 959 --- /dev/null
957 960 +++ b/pkg/place-holder
958 961 @@ -0,0 +1,2 @@
959 962 +perforce does not maintain empty directories.
960 963 +this file helps.
961 964
962 965 /* The mode change for mksys.bash is missing here, because on platforms */
963 966 /* that don't support execbits, mode changes in patches are ignored when */
964 967 /* they are imported. This is obviously also the reason for why the hash */
965 968 /* in the created changeset is different to the one you see above the */
966 969 /* #else clause */
967 970
968 971 #endif
969 972 $ cd ..
970 973
971 974
972 975 diff lines looking like headers
973 976
974 977 $ hg init difflineslikeheaders
975 978 $ cd difflineslikeheaders
976 979 $ echo a >a
977 980 $ echo b >b
978 981 $ echo c >c
979 982 $ hg ci -Am1
980 983 adding a
981 984 adding b
982 985 adding c
983 986
984 987 $ echo "key: value" >>a
985 988 $ echo "key: value" >>b
986 989 $ echo "foo" >>c
987 990 $ hg ci -m2
988 991
989 992 $ hg up -C 0
990 993 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
991 994 $ hg diff --git -c1 >want
992 995 $ hg diff -c1 | hg import --no-commit -
993 996 applying patch from stdin
994 997 $ hg diff --git >have
995 998 $ diff want have
996 999 $ cd ..
997 1000
998 1001 import a unified diff with no lines of context (diff -U0)
999 1002
1000 1003 $ hg init diffzero
1001 1004 $ cd diffzero
1002 1005 $ cat > f << EOF
1003 1006 > c2
1004 1007 > c4
1005 1008 > c5
1006 1009 > EOF
1007 1010 $ hg commit -Am0
1008 1011 adding f
1009 1012
1010 1013 $ hg import --no-commit - << EOF
1011 1014 > # HG changeset patch
1012 1015 > # User test
1013 1016 > # Date 0 0
1014 1017 > # Node ID f4974ab632f3dee767567b0576c0ec9a4508575c
1015 1018 > # Parent 8679a12a975b819fae5f7ad3853a2886d143d794
1016 1019 > 1
1017 1020 > diff -r 8679a12a975b -r f4974ab632f3 f
1018 1021 > --- a/f Thu Jan 01 00:00:00 1970 +0000
1019 1022 > +++ b/f Thu Jan 01 00:00:00 1970 +0000
1020 1023 > @@ -0,0 +1,1 @@
1021 1024 > +c1
1022 1025 > @@ -1,0 +3,1 @@
1023 1026 > +c3
1024 1027 > @@ -3,1 +4,0 @@
1025 1028 > -c5
1026 1029 > EOF
1027 1030 applying patch from stdin
1028 1031
1029 1032 $ cat f
1030 1033 c1
1031 1034 c2
1032 1035 c3
1033 1036 c4
1034 1037
1035 1038 $ cd ..
1036 1039
1037 1040 no segfault while importing a unified diff which start line is zero but chunk
1038 1041 size is non-zero
1039 1042
1040 1043 $ hg init startlinezero
1041 1044 $ cd startlinezero
1042 1045 $ echo foo > foo
1043 1046 $ hg commit -Amfoo
1044 1047 adding foo
1045 1048
1046 1049 $ hg import --no-commit - << EOF
1047 1050 > diff a/foo b/foo
1048 1051 > --- a/foo
1049 1052 > +++ b/foo
1050 1053 > @@ -0,1 +0,1 @@
1051 1054 > foo
1052 1055 > EOF
1053 1056 applying patch from stdin
1054 1057
1055 1058 $ cd ..
1056 1059
1057 1060 Test corner case involving fuzz and skew
1058 1061
1059 1062 $ hg init morecornercases
1060 1063 $ cd morecornercases
1061 1064
1062 1065 $ cat > 01-no-context-beginning-of-file.diff <<EOF
1063 1066 > diff --git a/a b/a
1064 1067 > --- a/a
1065 1068 > +++ b/a
1066 1069 > @@ -1,0 +1,1 @@
1067 1070 > +line
1068 1071 > EOF
1069 1072
1070 1073 $ cat > 02-no-context-middle-of-file.diff <<EOF
1071 1074 > diff --git a/a b/a
1072 1075 > --- a/a
1073 1076 > +++ b/a
1074 1077 > @@ -1,1 +1,1 @@
1075 1078 > -2
1076 1079 > +add some skew
1077 1080 > @@ -2,0 +2,1 @@
1078 1081 > +line
1079 1082 > EOF
1080 1083
1081 1084 $ cat > 03-no-context-end-of-file.diff <<EOF
1082 1085 > diff --git a/a b/a
1083 1086 > --- a/a
1084 1087 > +++ b/a
1085 1088 > @@ -10,0 +10,1 @@
1086 1089 > +line
1087 1090 > EOF
1088 1091
1089 1092 $ cat > 04-middle-of-file-completely-fuzzed.diff <<EOF
1090 1093 > diff --git a/a b/a
1091 1094 > --- a/a
1092 1095 > +++ b/a
1093 1096 > @@ -1,1 +1,1 @@
1094 1097 > -2
1095 1098 > +add some skew
1096 1099 > @@ -2,2 +2,3 @@
1097 1100 > not matching, should fuzz
1098 1101 > ... a bit
1099 1102 > +line
1100 1103 > EOF
1101 1104
1102 1105 $ cat > a <<EOF
1103 1106 > 1
1104 1107 > 2
1105 1108 > 3
1106 1109 > 4
1107 1110 > EOF
1108 1111 $ hg ci -Am adda a
1109 1112 $ for p in *.diff; do
1110 1113 > hg import -v --no-commit $p
1111 1114 > cat a
1112 1115 > hg revert -aqC a
1113 1116 > # patch -p1 < $p
1114 1117 > # cat a
1115 1118 > # hg revert -aC a
1116 1119 > done
1117 1120 applying 01-no-context-beginning-of-file.diff
1118 1121 patching file a
1119 1122 applied to working directory
1120 1123 1
1121 1124 line
1122 1125 2
1123 1126 3
1124 1127 4
1125 1128 applying 02-no-context-middle-of-file.diff
1126 1129 patching file a
1127 1130 Hunk #1 succeeded at 2 (offset 1 lines).
1128 1131 Hunk #2 succeeded at 4 (offset 1 lines).
1129 1132 applied to working directory
1130 1133 1
1131 1134 add some skew
1132 1135 3
1133 1136 line
1134 1137 4
1135 1138 applying 03-no-context-end-of-file.diff
1136 1139 patching file a
1137 1140 Hunk #1 succeeded at 5 (offset -6 lines).
1138 1141 applied to working directory
1139 1142 1
1140 1143 2
1141 1144 3
1142 1145 4
1143 1146 line
1144 1147 applying 04-middle-of-file-completely-fuzzed.diff
1145 1148 patching file a
1146 1149 Hunk #1 succeeded at 2 (offset 1 lines).
1147 1150 Hunk #2 succeeded at 5 with fuzz 2 (offset 1 lines).
1148 1151 applied to working directory
1149 1152 1
1150 1153 add some skew
1151 1154 3
1152 1155 4
1153 1156 line
1154 1157
1155 1158 $ cd ..
General Comments 0
You need to be logged in to leave comments. Login now