##// END OF EJS Templates
test: add missing 'cd ..' to test case...
Danny Hooper -
r42555:b02f3aa2 default
parent child Browse files
Show More
@@ -1,1264 +1,1266 b''
1 1 A script that implements uppercasing of specific lines in a file. This
2 2 approximates the behavior of code formatters well enough for our tests.
3 3
4 4 $ UPPERCASEPY="$TESTTMP/uppercase.py"
5 5 $ cat > $UPPERCASEPY <<EOF
6 6 > import sys
7 7 > from mercurial.utils.procutil import setbinary
8 8 > setbinary(sys.stdin)
9 9 > setbinary(sys.stdout)
10 10 > lines = set()
11 11 > for arg in sys.argv[1:]:
12 12 > if arg == 'all':
13 13 > sys.stdout.write(sys.stdin.read().upper())
14 14 > sys.exit(0)
15 15 > else:
16 16 > first, last = arg.split('-')
17 17 > lines.update(range(int(first), int(last) + 1))
18 18 > for i, line in enumerate(sys.stdin.readlines()):
19 19 > if i + 1 in lines:
20 20 > sys.stdout.write(line.upper())
21 21 > else:
22 22 > sys.stdout.write(line)
23 23 > EOF
24 24 $ TESTLINES="foo\nbar\nbaz\nqux\n"
25 25 $ printf $TESTLINES | "$PYTHON" $UPPERCASEPY
26 26 foo
27 27 bar
28 28 baz
29 29 qux
30 30 $ printf $TESTLINES | "$PYTHON" $UPPERCASEPY all
31 31 FOO
32 32 BAR
33 33 BAZ
34 34 QUX
35 35 $ printf $TESTLINES | "$PYTHON" $UPPERCASEPY 1-1
36 36 FOO
37 37 bar
38 38 baz
39 39 qux
40 40 $ printf $TESTLINES | "$PYTHON" $UPPERCASEPY 1-2
41 41 FOO
42 42 BAR
43 43 baz
44 44 qux
45 45 $ printf $TESTLINES | "$PYTHON" $UPPERCASEPY 2-3
46 46 foo
47 47 BAR
48 48 BAZ
49 49 qux
50 50 $ printf $TESTLINES | "$PYTHON" $UPPERCASEPY 2-2 4-4
51 51 foo
52 52 BAR
53 53 baz
54 54 QUX
55 55
56 56 Set up the config with two simple fixers: one that fixes specific line ranges,
57 57 and one that always fixes the whole file. They both "fix" files by converting
58 58 letters to uppercase. They use different file extensions, so each test case can
59 59 choose which behavior to use by naming files.
60 60
61 61 $ cat >> $HGRCPATH <<EOF
62 62 > [extensions]
63 63 > fix =
64 64 > [experimental]
65 65 > evolution.createmarkers=True
66 66 > evolution.allowunstable=True
67 67 > [fix]
68 68 > uppercase-whole-file:command="$PYTHON" $UPPERCASEPY all
69 69 > uppercase-whole-file:pattern=set:**.whole
70 70 > uppercase-changed-lines:command="$PYTHON" $UPPERCASEPY
71 71 > uppercase-changed-lines:linerange={first}-{last}
72 72 > uppercase-changed-lines:pattern=set:**.changed
73 73 > EOF
74 74
75 75 Help text for fix.
76 76
77 77 $ hg help fix
78 78 hg fix [OPTION]... [FILE]...
79 79
80 80 rewrite file content in changesets or working directory
81 81
82 82 Runs any configured tools to fix the content of files. Only affects files
83 83 with changes, unless file arguments are provided. Only affects changed
84 84 lines of files, unless the --whole flag is used. Some tools may always
85 85 affect the whole file regardless of --whole.
86 86
87 87 If revisions are specified with --rev, those revisions will be checked,
88 88 and they may be replaced with new revisions that have fixed file content.
89 89 It is desirable to specify all descendants of each specified revision, so
90 90 that the fixes propagate to the descendants. If all descendants are fixed
91 91 at the same time, no merging, rebasing, or evolution will be required.
92 92
93 93 If --working-dir is used, files with uncommitted changes in the working
94 94 copy will be fixed. If the checked-out revision is also fixed, the working
95 95 directory will update to the replacement revision.
96 96
97 97 When determining what lines of each file to fix at each revision, the
98 98 whole set of revisions being fixed is considered, so that fixes to earlier
99 99 revisions are not forgotten in later ones. The --base flag can be used to
100 100 override this default behavior, though it is not usually desirable to do
101 101 so.
102 102
103 103 (use 'hg help -e fix' to show help for the fix extension)
104 104
105 105 options ([+] can be repeated):
106 106
107 107 --all fix all non-public non-obsolete revisions
108 108 --base REV [+] revisions to diff against (overrides automatic selection,
109 109 and applies to every revision being fixed)
110 110 -r --rev REV [+] revisions to fix
111 111 -w --working-dir fix the working directory
112 112 --whole always fix every line of a file
113 113
114 114 (some details hidden, use --verbose to show complete help)
115 115
116 116 $ hg help -e fix
117 117 fix extension - rewrite file content in changesets or working copy
118 118 (EXPERIMENTAL)
119 119
120 120 Provides a command that runs configured tools on the contents of modified
121 121 files, writing back any fixes to the working copy or replacing changesets.
122 122
123 123 Here is an example configuration that causes 'hg fix' to apply automatic
124 124 formatting fixes to modified lines in C++ code:
125 125
126 126 [fix]
127 127 clang-format:command=clang-format --assume-filename={rootpath}
128 128 clang-format:linerange=--lines={first}:{last}
129 129 clang-format:pattern=set:**.cpp or **.hpp
130 130
131 131 The :command suboption forms the first part of the shell command that will be
132 132 used to fix a file. The content of the file is passed on standard input, and
133 133 the fixed file content is expected on standard output. Any output on standard
134 134 error will be displayed as a warning. If the exit status is not zero, the file
135 135 will not be affected. A placeholder warning is displayed if there is a non-
136 136 zero exit status but no standard error output. Some values may be substituted
137 137 into the command:
138 138
139 139 {rootpath} The path of the file being fixed, relative to the repo root
140 140 {basename} The name of the file being fixed, without the directory path
141 141
142 142 If the :linerange suboption is set, the tool will only be run if there are
143 143 changed lines in a file. The value of this suboption is appended to the shell
144 144 command once for every range of changed lines in the file. Some values may be
145 145 substituted into the command:
146 146
147 147 {first} The 1-based line number of the first line in the modified range
148 148 {last} The 1-based line number of the last line in the modified range
149 149
150 150 The :pattern suboption determines which files will be passed through each
151 151 configured tool. See 'hg help patterns' for possible values. If there are file
152 152 arguments to 'hg fix', the intersection of these patterns is used.
153 153
154 154 There is also a configurable limit for the maximum size of file that will be
155 155 processed by 'hg fix':
156 156
157 157 [fix]
158 158 maxfilesize = 2MB
159 159
160 160 Normally, execution of configured tools will continue after a failure
161 161 (indicated by a non-zero exit status). It can also be configured to abort
162 162 after the first such failure, so that no files will be affected if any tool
163 163 fails. This abort will also cause 'hg fix' to exit with a non-zero status:
164 164
165 165 [fix]
166 166 failure = abort
167 167
168 168 When multiple tools are configured to affect a file, they execute in an order
169 169 defined by the :priority suboption. The priority suboption has a default value
170 170 of zero for each tool. Tools are executed in order of descending priority. The
171 171 execution order of tools with equal priority is unspecified. For example, you
172 172 could use the 'sort' and 'head' utilities to keep only the 10 smallest numbers
173 173 in a text file by ensuring that 'sort' runs before 'head':
174 174
175 175 [fix]
176 176 sort:command = sort -n
177 177 head:command = head -n 10
178 178 sort:pattern = numbers.txt
179 179 head:pattern = numbers.txt
180 180 sort:priority = 2
181 181 head:priority = 1
182 182
183 183 To account for changes made by each tool, the line numbers used for
184 184 incremental formatting are recomputed before executing the next tool. So, each
185 185 tool may see different values for the arguments added by the :linerange
186 186 suboption.
187 187
188 188 Each fixer tool is allowed to return some metadata in addition to the fixed
189 189 file content. The metadata must be placed before the file content on stdout,
190 190 separated from the file content by a zero byte. The metadata is parsed as a
191 191 JSON value (so, it should be UTF-8 encoded and contain no zero bytes). A fixer
192 192 tool is expected to produce this metadata encoding if and only if the
193 193 :metadata suboption is true:
194 194
195 195 [fix]
196 196 tool:command = tool --prepend-json-metadata
197 197 tool:metadata = true
198 198
199 199 The metadata values are passed to hooks, which can be used to print summaries
200 200 or perform other post-fixing work. The supported hooks are:
201 201
202 202 "postfixfile"
203 203 Run once for each file in each revision where any fixer tools made changes
204 204 to the file content. Provides "$HG_REV" and "$HG_PATH" to identify the file,
205 205 and "$HG_METADATA" with a map of fixer names to metadata values from fixer
206 206 tools that affected the file. Fixer tools that didn't affect the file have a
207 207 valueof None. Only fixer tools that executed are present in the metadata.
208 208
209 209 "postfix"
210 210 Run once after all files and revisions have been handled. Provides
211 211 "$HG_REPLACEMENTS" with information about what revisions were created and
212 212 made obsolete. Provides a boolean "$HG_WDIRWRITTEN" to indicate whether any
213 213 files in the working copy were updated. Provides a list "$HG_METADATA"
214 214 mapping fixer tool names to lists of metadata values returned from
215 215 executions that modified a file. This aggregates the same metadata
216 216 previously passed to the "postfixfile" hook.
217 217
218 218 list of commands:
219 219
220 220 fix rewrite file content in changesets or working directory
221 221
222 222 (use 'hg help -v -e fix' to show built-in aliases and global options)
223 223
224 224 There is no default behavior in the absence of --rev and --working-dir.
225 225
226 226 $ hg init badusage
227 227 $ cd badusage
228 228
229 229 $ hg fix
230 230 abort: no changesets specified
231 231 (use --rev or --working-dir)
232 232 [255]
233 233 $ hg fix --whole
234 234 abort: no changesets specified
235 235 (use --rev or --working-dir)
236 236 [255]
237 237 $ hg fix --base 0
238 238 abort: no changesets specified
239 239 (use --rev or --working-dir)
240 240 [255]
241 241
242 242 Fixing a public revision isn't allowed. It should abort early enough that
243 243 nothing happens, even to the working directory.
244 244
245 245 $ printf "hello\n" > hello.whole
246 246 $ hg commit -Aqm "hello"
247 247 $ hg phase -r 0 --public
248 248 $ hg fix -r 0
249 249 abort: can't fix immutable changeset 0:6470986d2e7b
250 250 [255]
251 251 $ hg fix -r 0 --working-dir
252 252 abort: can't fix immutable changeset 0:6470986d2e7b
253 253 [255]
254 254 $ hg cat -r tip hello.whole
255 255 hello
256 256 $ cat hello.whole
257 257 hello
258 258
259 259 $ cd ..
260 260
261 261 Fixing a clean working directory should do nothing. Even the --whole flag
262 262 shouldn't cause any clean files to be fixed. Specifying a clean file explicitly
263 263 should only fix it if the fixer always fixes the whole file. The combination of
264 264 an explicit filename and --whole should format the entire file regardless.
265 265
266 266 $ hg init fixcleanwdir
267 267 $ cd fixcleanwdir
268 268
269 269 $ printf "hello\n" > hello.changed
270 270 $ printf "world\n" > hello.whole
271 271 $ hg commit -Aqm "foo"
272 272 $ hg fix --working-dir
273 273 $ hg diff
274 274 $ hg fix --working-dir --whole
275 275 $ hg diff
276 276 $ hg fix --working-dir *
277 277 $ cat *
278 278 hello
279 279 WORLD
280 280 $ hg revert --all --no-backup
281 281 reverting hello.whole
282 282 $ hg fix --working-dir * --whole
283 283 $ cat *
284 284 HELLO
285 285 WORLD
286 286
287 287 The same ideas apply to fixing a revision, so we create a revision that doesn't
288 288 modify either of the files in question and try fixing it. This also tests that
289 289 we ignore a file that doesn't match any configured fixer.
290 290
291 291 $ hg revert --all --no-backup
292 292 reverting hello.changed
293 293 reverting hello.whole
294 294 $ printf "unimportant\n" > some.file
295 295 $ hg commit -Aqm "some other file"
296 296
297 297 $ hg fix -r .
298 298 $ hg cat -r tip *
299 299 hello
300 300 world
301 301 unimportant
302 302 $ hg fix -r . --whole
303 303 $ hg cat -r tip *
304 304 hello
305 305 world
306 306 unimportant
307 307 $ hg fix -r . *
308 308 $ hg cat -r tip *
309 309 hello
310 310 WORLD
311 311 unimportant
312 312 $ hg fix -r . * --whole --config experimental.evolution.allowdivergence=true
313 313 2 new content-divergent changesets
314 314 $ hg cat -r tip *
315 315 HELLO
316 316 WORLD
317 317 unimportant
318 318
319 319 $ cd ..
320 320
321 321 Fixing the working directory should still work if there are no revisions.
322 322
323 323 $ hg init norevisions
324 324 $ cd norevisions
325 325
326 326 $ printf "something\n" > something.whole
327 327 $ hg add
328 328 adding something.whole
329 329 $ hg fix --working-dir
330 330 $ cat something.whole
331 331 SOMETHING
332 332
333 333 $ cd ..
334 334
335 335 Test the effect of fixing the working directory for each possible status, with
336 336 and without providing explicit file arguments.
337 337
338 338 $ hg init implicitlyfixstatus
339 339 $ cd implicitlyfixstatus
340 340
341 341 $ printf "modified\n" > modified.whole
342 342 $ printf "removed\n" > removed.whole
343 343 $ printf "deleted\n" > deleted.whole
344 344 $ printf "clean\n" > clean.whole
345 345 $ printf "ignored.whole" > .hgignore
346 346 $ hg commit -Aqm "stuff"
347 347
348 348 $ printf "modified!!!\n" > modified.whole
349 349 $ printf "unknown\n" > unknown.whole
350 350 $ printf "ignored\n" > ignored.whole
351 351 $ printf "added\n" > added.whole
352 352 $ hg add added.whole
353 353 $ hg remove removed.whole
354 354 $ rm deleted.whole
355 355
356 356 $ hg status --all
357 357 M modified.whole
358 358 A added.whole
359 359 R removed.whole
360 360 ! deleted.whole
361 361 ? unknown.whole
362 362 I ignored.whole
363 363 C .hgignore
364 364 C clean.whole
365 365
366 366 $ hg fix --working-dir
367 367
368 368 $ hg status --all
369 369 M modified.whole
370 370 A added.whole
371 371 R removed.whole
372 372 ! deleted.whole
373 373 ? unknown.whole
374 374 I ignored.whole
375 375 C .hgignore
376 376 C clean.whole
377 377
378 378 $ cat *.whole
379 379 ADDED
380 380 clean
381 381 ignored
382 382 MODIFIED!!!
383 383 unknown
384 384
385 385 $ printf "modified!!!\n" > modified.whole
386 386 $ printf "added\n" > added.whole
387 387
388 388 Listing the files explicitly causes untracked files to also be fixed, but
389 389 ignored files are still unaffected.
390 390
391 391 $ hg fix --working-dir *.whole
392 392
393 393 $ hg status --all
394 394 M clean.whole
395 395 M modified.whole
396 396 A added.whole
397 397 R removed.whole
398 398 ! deleted.whole
399 399 ? unknown.whole
400 400 I ignored.whole
401 401 C .hgignore
402 402
403 403 $ cat *.whole
404 404 ADDED
405 405 CLEAN
406 406 ignored
407 407 MODIFIED!!!
408 408 UNKNOWN
409 409
410 410 $ cd ..
411 411
412 412 Test that incremental fixing works on files with additions, deletions, and
413 413 changes in multiple line ranges. Note that deletions do not generally cause
414 414 neighboring lines to be fixed, so we don't return a line range for purely
415 415 deleted sections. In the future we should support a :deletion config that
416 416 allows fixers to know where deletions are located.
417 417
418 418 $ hg init incrementalfixedlines
419 419 $ cd incrementalfixedlines
420 420
421 421 $ printf "a\nb\nc\nd\ne\nf\ng\n" > foo.txt
422 422 $ hg commit -Aqm "foo"
423 423 $ printf "zz\na\nc\ndd\nee\nff\nf\ngg\n" > foo.txt
424 424
425 425 $ hg --config "fix.fail:command=echo" \
426 426 > --config "fix.fail:linerange={first}:{last}" \
427 427 > --config "fix.fail:pattern=foo.txt" \
428 428 > fix --working-dir
429 429 $ cat foo.txt
430 430 1:1 4:6 8:8
431 431
432 432 $ cd ..
433 433
434 434 Test that --whole fixes all lines regardless of the diffs present.
435 435
436 436 $ hg init wholeignoresdiffs
437 437 $ cd wholeignoresdiffs
438 438
439 439 $ printf "a\nb\nc\nd\ne\nf\ng\n" > foo.changed
440 440 $ hg commit -Aqm "foo"
441 441 $ printf "zz\na\nc\ndd\nee\nff\nf\ngg\n" > foo.changed
442 442 $ hg fix --working-dir --whole
443 443 $ cat foo.changed
444 444 ZZ
445 445 A
446 446 C
447 447 DD
448 448 EE
449 449 FF
450 450 F
451 451 GG
452 452
453 453 $ cd ..
454 454
455 455 We should do nothing with symlinks, and their targets should be unaffected. Any
456 456 other behavior would be more complicated to implement and harder to document.
457 457
458 458 #if symlink
459 459 $ hg init dontmesswithsymlinks
460 460 $ cd dontmesswithsymlinks
461 461
462 462 $ printf "hello\n" > hello.whole
463 463 $ ln -s hello.whole hellolink
464 464 $ hg add
465 465 adding hello.whole
466 466 adding hellolink
467 467 $ hg fix --working-dir hellolink
468 468 $ hg status
469 469 A hello.whole
470 470 A hellolink
471 471
472 472 $ cd ..
473 473 #endif
474 474
475 475 We should allow fixers to run on binary files, even though this doesn't sound
476 476 like a common use case. There's not much benefit to disallowing it, and users
477 477 can add "and not binary()" to their filesets if needed. The Mercurial
478 478 philosophy is generally to not handle binary files specially anyway.
479 479
480 480 $ hg init cantouchbinaryfiles
481 481 $ cd cantouchbinaryfiles
482 482
483 483 $ printf "hello\0\n" > hello.whole
484 484 $ hg add
485 485 adding hello.whole
486 486 $ hg fix --working-dir 'set:binary()'
487 487 $ cat hello.whole
488 488 HELLO\x00 (esc)
489 489
490 490 $ cd ..
491 491
492 492 We have a config for the maximum size of file we will attempt to fix. This can
493 493 be helpful to avoid running unsuspecting fixer tools on huge inputs, which
494 494 could happen by accident without a well considered configuration. A more
495 495 precise configuration could use the size() fileset function if one global limit
496 496 is undesired.
497 497
498 498 $ hg init maxfilesize
499 499 $ cd maxfilesize
500 500
501 501 $ printf "this file is huge\n" > hello.whole
502 502 $ hg add
503 503 adding hello.whole
504 504 $ hg --config fix.maxfilesize=10 fix --working-dir
505 505 ignoring file larger than 10 bytes: hello.whole
506 506 $ cat hello.whole
507 507 this file is huge
508 508
509 509 $ cd ..
510 510
511 511 If we specify a file to fix, other files should be left alone, even if they
512 512 have changes.
513 513
514 514 $ hg init fixonlywhatitellyouto
515 515 $ cd fixonlywhatitellyouto
516 516
517 517 $ printf "fix me!\n" > fixme.whole
518 518 $ printf "not me.\n" > notme.whole
519 519 $ hg add
520 520 adding fixme.whole
521 521 adding notme.whole
522 522 $ hg fix --working-dir fixme.whole
523 523 $ cat *.whole
524 524 FIX ME!
525 525 not me.
526 526
527 527 $ cd ..
528 528
529 529 Specifying a directory name should fix all its files and subdirectories.
530 530
531 531 $ hg init fixdirectory
532 532 $ cd fixdirectory
533 533
534 534 $ mkdir -p dir1/dir2
535 535 $ printf "foo\n" > foo.whole
536 536 $ printf "bar\n" > dir1/bar.whole
537 537 $ printf "baz\n" > dir1/dir2/baz.whole
538 538 $ hg add
539 539 adding dir1/bar.whole
540 540 adding dir1/dir2/baz.whole
541 541 adding foo.whole
542 542 $ hg fix --working-dir dir1
543 543 $ cat foo.whole dir1/bar.whole dir1/dir2/baz.whole
544 544 foo
545 545 BAR
546 546 BAZ
547 547
548 548 $ cd ..
549 549
550 550 Fixing a file in the working directory that needs no fixes should not actually
551 551 write back to the file, so for example the mtime shouldn't change.
552 552
553 553 $ hg init donttouchunfixedfiles
554 554 $ cd donttouchunfixedfiles
555 555
556 556 $ printf "NO FIX NEEDED\n" > foo.whole
557 557 $ hg add
558 558 adding foo.whole
559 559 $ cp -p foo.whole foo.whole.orig
560 560 $ cp -p foo.whole.orig foo.whole
561 561 $ sleep 2 # mtime has a resolution of one or two seconds.
562 562 $ hg fix --working-dir
563 563 $ f foo.whole.orig --newer foo.whole
564 564 foo.whole.orig: newer than foo.whole
565 565
566 566 $ cd ..
567 567
568 568 When a fixer prints to stderr, we don't assume that it has failed. We show the
569 569 error messages to the user, and we still let the fixer affect the file it was
570 570 fixing if its exit code is zero. Some code formatters might emit error messages
571 571 on stderr and nothing on stdout, which would cause us the clear the file,
572 572 except that they also exit with a non-zero code. We show the user which fixer
573 573 emitted the stderr, and which revision, but we assume that the fixer will print
574 574 the filename if it is relevant (since the issue may be non-specific). There is
575 575 also a config to abort (without affecting any files whatsoever) if we see any
576 576 tool with a non-zero exit status.
577 577
578 578 $ hg init showstderr
579 579 $ cd showstderr
580 580
581 581 $ printf "hello\n" > hello.txt
582 582 $ hg add
583 583 adding hello.txt
584 584 $ cat > $TESTTMP/work.sh <<'EOF'
585 585 > printf 'HELLO\n'
586 586 > printf "$@: some\nerror that didn't stop the tool" >&2
587 587 > exit 0 # success despite the stderr output
588 588 > EOF
589 589 $ hg --config "fix.work:command=sh $TESTTMP/work.sh {rootpath}" \
590 590 > --config "fix.work:pattern=hello.txt" \
591 591 > fix --working-dir
592 592 [wdir] work: hello.txt: some
593 593 [wdir] work: error that didn't stop the tool
594 594 $ cat hello.txt
595 595 HELLO
596 596
597 597 $ printf "goodbye\n" > hello.txt
598 598 $ printf "foo\n" > foo.whole
599 599 $ hg add
600 600 adding foo.whole
601 601 $ cat > $TESTTMP/fail.sh <<'EOF'
602 602 > printf 'GOODBYE\n'
603 603 > printf "$@: some\nerror that did stop the tool\n" >&2
604 604 > exit 42 # success despite the stdout output
605 605 > EOF
606 606 $ hg --config "fix.fail:command=sh $TESTTMP/fail.sh {rootpath}" \
607 607 > --config "fix.fail:pattern=hello.txt" \
608 608 > --config "fix.failure=abort" \
609 609 > fix --working-dir
610 610 [wdir] fail: hello.txt: some
611 611 [wdir] fail: error that did stop the tool
612 612 abort: no fixes will be applied
613 613 (use --config fix.failure=continue to apply any successful fixes anyway)
614 614 [255]
615 615 $ cat hello.txt
616 616 goodbye
617 617 $ cat foo.whole
618 618 foo
619 619
620 620 $ hg --config "fix.fail:command=sh $TESTTMP/fail.sh {rootpath}" \
621 621 > --config "fix.fail:pattern=hello.txt" \
622 622 > fix --working-dir
623 623 [wdir] fail: hello.txt: some
624 624 [wdir] fail: error that did stop the tool
625 625 $ cat hello.txt
626 626 goodbye
627 627 $ cat foo.whole
628 628 FOO
629 629
630 630 $ hg --config "fix.fail:command=exit 42" \
631 631 > --config "fix.fail:pattern=hello.txt" \
632 632 > fix --working-dir
633 633 [wdir] fail: exited with status 42
634 634
635 635 $ cd ..
636 636
637 637 Fixing the working directory and its parent revision at the same time should
638 638 check out the replacement revision for the parent. This prevents any new
639 639 uncommitted changes from appearing. We test this for a clean working directory
640 640 and a dirty one. In both cases, all lines/files changed since the grandparent
641 641 will be fixed. The grandparent is the "baserev" for both the parent and the
642 642 working copy.
643 643
644 644 $ hg init fixdotandcleanwdir
645 645 $ cd fixdotandcleanwdir
646 646
647 647 $ printf "hello\n" > hello.whole
648 648 $ printf "world\n" > world.whole
649 649 $ hg commit -Aqm "the parent commit"
650 650
651 651 $ hg parents --template '{rev} {desc}\n'
652 652 0 the parent commit
653 653 $ hg fix --working-dir -r .
654 654 $ hg parents --template '{rev} {desc}\n'
655 655 1 the parent commit
656 656 $ hg cat -r . *.whole
657 657 HELLO
658 658 WORLD
659 659 $ cat *.whole
660 660 HELLO
661 661 WORLD
662 662 $ hg status
663 663
664 664 $ cd ..
665 665
666 666 Same test with a dirty working copy.
667 667
668 668 $ hg init fixdotanddirtywdir
669 669 $ cd fixdotanddirtywdir
670 670
671 671 $ printf "hello\n" > hello.whole
672 672 $ printf "world\n" > world.whole
673 673 $ hg commit -Aqm "the parent commit"
674 674
675 675 $ printf "hello,\n" > hello.whole
676 676 $ printf "world!\n" > world.whole
677 677
678 678 $ hg parents --template '{rev} {desc}\n'
679 679 0 the parent commit
680 680 $ hg fix --working-dir -r .
681 681 $ hg parents --template '{rev} {desc}\n'
682 682 1 the parent commit
683 683 $ hg cat -r . *.whole
684 684 HELLO
685 685 WORLD
686 686 $ cat *.whole
687 687 HELLO,
688 688 WORLD!
689 689 $ hg status
690 690 M hello.whole
691 691 M world.whole
692 692
693 693 $ cd ..
694 694
695 695 When we have a chain of commits that change mutually exclusive lines of code,
696 696 we should be able to do incremental fixing that causes each commit in the chain
697 697 to include fixes made to the previous commits. This prevents children from
698 698 backing out the fixes made in their parents. A dirty working directory is
699 699 conceptually similar to another commit in the chain.
700 700
701 701 $ hg init incrementallyfixchain
702 702 $ cd incrementallyfixchain
703 703
704 704 $ cat > file.changed <<EOF
705 705 > first
706 706 > second
707 707 > third
708 708 > fourth
709 709 > fifth
710 710 > EOF
711 711 $ hg commit -Aqm "the common ancestor (the baserev)"
712 712 $ cat > file.changed <<EOF
713 713 > first (changed)
714 714 > second
715 715 > third
716 716 > fourth
717 717 > fifth
718 718 > EOF
719 719 $ hg commit -Aqm "the first commit to fix"
720 720 $ cat > file.changed <<EOF
721 721 > first (changed)
722 722 > second
723 723 > third (changed)
724 724 > fourth
725 725 > fifth
726 726 > EOF
727 727 $ hg commit -Aqm "the second commit to fix"
728 728 $ cat > file.changed <<EOF
729 729 > first (changed)
730 730 > second
731 731 > third (changed)
732 732 > fourth
733 733 > fifth (changed)
734 734 > EOF
735 735
736 736 $ hg fix -r . -r '.^' --working-dir
737 737
738 738 $ hg parents --template '{rev}\n'
739 739 4
740 740 $ hg cat -r '.^^' file.changed
741 741 first
742 742 second
743 743 third
744 744 fourth
745 745 fifth
746 746 $ hg cat -r '.^' file.changed
747 747 FIRST (CHANGED)
748 748 second
749 749 third
750 750 fourth
751 751 fifth
752 752 $ hg cat -r . file.changed
753 753 FIRST (CHANGED)
754 754 second
755 755 THIRD (CHANGED)
756 756 fourth
757 757 fifth
758 758 $ cat file.changed
759 759 FIRST (CHANGED)
760 760 second
761 761 THIRD (CHANGED)
762 762 fourth
763 763 FIFTH (CHANGED)
764 764
765 765 $ cd ..
766 766
767 767 If we incrementally fix a merge commit, we should fix any lines that changed
768 768 versus either parent. You could imagine only fixing the intersection or some
769 769 other subset, but this is necessary if either parent is being fixed. It
770 770 prevents us from forgetting fixes made in either parent.
771 771
772 772 $ hg init incrementallyfixmergecommit
773 773 $ cd incrementallyfixmergecommit
774 774
775 775 $ printf "a\nb\nc\n" > file.changed
776 776 $ hg commit -Aqm "ancestor"
777 777
778 778 $ printf "aa\nb\nc\n" > file.changed
779 779 $ hg commit -m "change a"
780 780
781 781 $ hg checkout '.^'
782 782 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
783 783 $ printf "a\nb\ncc\n" > file.changed
784 784 $ hg commit -m "change c"
785 785 created new head
786 786
787 787 $ hg merge
788 788 merging file.changed
789 789 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
790 790 (branch merge, don't forget to commit)
791 791 $ hg commit -m "merge"
792 792 $ hg cat -r . file.changed
793 793 aa
794 794 b
795 795 cc
796 796
797 797 $ hg fix -r . --working-dir
798 798 $ hg cat -r . file.changed
799 799 AA
800 800 b
801 801 CC
802 802
803 803 $ cd ..
804 804
805 805 Abort fixing revisions if there is an unfinished operation. We don't want to
806 806 make things worse by editing files or stripping/obsoleting things. Also abort
807 807 fixing the working directory if there are unresolved merge conflicts.
808 808
809 809 $ hg init abortunresolved
810 810 $ cd abortunresolved
811 811
812 812 $ echo "foo1" > foo.whole
813 813 $ hg commit -Aqm "foo 1"
814 814
815 815 $ hg update null
816 816 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
817 817 $ echo "foo2" > foo.whole
818 818 $ hg commit -Aqm "foo 2"
819 819
820 820 $ hg --config extensions.rebase= rebase -r 1 -d 0
821 821 rebasing 1:c3b6dc0e177a "foo 2" (tip)
822 822 merging foo.whole
823 823 warning: conflicts while merging foo.whole! (edit, then use 'hg resolve --mark')
824 824 unresolved conflicts (see hg resolve, then hg rebase --continue)
825 825 [1]
826 826
827 827 $ hg --config extensions.rebase= fix --working-dir
828 828 abort: unresolved conflicts
829 829 (use 'hg resolve')
830 830 [255]
831 831
832 832 $ hg --config extensions.rebase= fix -r .
833 833 abort: rebase in progress
834 834 (use 'hg rebase --continue' or 'hg rebase --abort')
835 835 [255]
836 836
837 $ cd ..
838
837 839 When fixing a file that was renamed, we should diff against the source of the
838 840 rename for incremental fixing and we should correctly reproduce the rename in
839 841 the replacement revision.
840 842
841 843 $ hg init fixrenamecommit
842 844 $ cd fixrenamecommit
843 845
844 846 $ printf "a\nb\nc\n" > source.changed
845 847 $ hg commit -Aqm "source revision"
846 848 $ hg move source.changed dest.changed
847 849 $ printf "a\nb\ncc\n" > dest.changed
848 850 $ hg commit -m "dest revision"
849 851
850 852 $ hg fix -r .
851 853 $ hg log -r tip --copies --template "{file_copies}\n"
852 854 dest.changed (source.changed)
853 855 $ hg cat -r tip dest.changed
854 856 a
855 857 b
856 858 CC
857 859
858 860 $ cd ..
859 861
860 862 When fixing revisions that remove files we must ensure that the replacement
861 863 actually removes the file, whereas it could accidentally leave it unchanged or
862 864 write an empty string to it.
863 865
864 866 $ hg init fixremovedfile
865 867 $ cd fixremovedfile
866 868
867 869 $ printf "foo\n" > foo.whole
868 870 $ printf "bar\n" > bar.whole
869 871 $ hg commit -Aqm "add files"
870 872 $ hg remove bar.whole
871 873 $ hg commit -m "remove file"
872 874 $ hg status --change .
873 875 R bar.whole
874 876 $ hg fix -r . foo.whole
875 877 $ hg status --change tip
876 878 M foo.whole
877 879 R bar.whole
878 880
879 881 $ cd ..
880 882
881 883 If fixing a revision finds no fixes to make, no replacement revision should be
882 884 created.
883 885
884 886 $ hg init nofixesneeded
885 887 $ cd nofixesneeded
886 888
887 889 $ printf "FOO\n" > foo.whole
888 890 $ hg commit -Aqm "add file"
889 891 $ hg log --template '{rev}\n'
890 892 0
891 893 $ hg fix -r .
892 894 $ hg log --template '{rev}\n'
893 895 0
894 896
895 897 $ cd ..
896 898
897 899 If fixing a commit reverts all the changes in the commit, we replace it with a
898 900 commit that changes no files.
899 901
900 902 $ hg init nochangesleft
901 903 $ cd nochangesleft
902 904
903 905 $ printf "FOO\n" > foo.whole
904 906 $ hg commit -Aqm "add file"
905 907 $ printf "foo\n" > foo.whole
906 908 $ hg commit -m "edit file"
907 909 $ hg status --change .
908 910 M foo.whole
909 911 $ hg fix -r .
910 912 $ hg status --change tip
911 913
912 914 $ cd ..
913 915
914 916 If we fix a parent and child revision together, the child revision must be
915 917 replaced if the parent is replaced, even if the diffs of the child needed no
916 918 fixes. However, we're free to not replace revisions that need no fixes and have
917 919 no ancestors that are replaced.
918 920
919 921 $ hg init mustreplacechild
920 922 $ cd mustreplacechild
921 923
922 924 $ printf "FOO\n" > foo.whole
923 925 $ hg commit -Aqm "add foo"
924 926 $ printf "foo\n" > foo.whole
925 927 $ hg commit -m "edit foo"
926 928 $ printf "BAR\n" > bar.whole
927 929 $ hg commit -Aqm "add bar"
928 930
929 931 $ hg log --graph --template '{rev} {files}'
930 932 @ 2 bar.whole
931 933 |
932 934 o 1 foo.whole
933 935 |
934 936 o 0 foo.whole
935 937
936 938 $ hg fix -r 0:2
937 939 $ hg log --graph --template '{rev} {files}'
938 940 o 4 bar.whole
939 941 |
940 942 o 3
941 943 |
942 944 | @ 2 bar.whole
943 945 | |
944 946 | x 1 foo.whole
945 947 |/
946 948 o 0 foo.whole
947 949
948 950
949 951 $ cd ..
950 952
951 953 It's also possible that the child needs absolutely no changes, but we still
952 954 need to replace it to update its parent. If we skipped replacing the child
953 955 because it had no file content changes, it would become an orphan for no good
954 956 reason.
955 957
956 958 $ hg init mustreplacechildevenifnop
957 959 $ cd mustreplacechildevenifnop
958 960
959 961 $ printf "Foo\n" > foo.whole
960 962 $ hg commit -Aqm "add a bad foo"
961 963 $ printf "FOO\n" > foo.whole
962 964 $ hg commit -m "add a good foo"
963 965 $ hg fix -r . -r '.^'
964 966 $ hg log --graph --template '{rev} {desc}'
965 967 o 3 add a good foo
966 968 |
967 969 o 2 add a bad foo
968 970
969 971 @ 1 add a good foo
970 972 |
971 973 x 0 add a bad foo
972 974
973 975
974 976 $ cd ..
975 977
976 978 Similar to the case above, the child revision may become empty as a result of
977 979 fixing its parent. We should still create an empty replacement child.
978 980 TODO: determine how this should interact with ui.allowemptycommit given that
979 981 the empty replacement could have children.
980 982
981 983 $ hg init mustreplacechildevenifempty
982 984 $ cd mustreplacechildevenifempty
983 985
984 986 $ printf "foo\n" > foo.whole
985 987 $ hg commit -Aqm "add foo"
986 988 $ printf "Foo\n" > foo.whole
987 989 $ hg commit -m "edit foo"
988 990 $ hg fix -r . -r '.^'
989 991 $ hg log --graph --template '{rev} {desc}\n' --stat
990 992 o 3 edit foo
991 993 |
992 994 o 2 add foo
993 995 foo.whole | 1 +
994 996 1 files changed, 1 insertions(+), 0 deletions(-)
995 997
996 998 @ 1 edit foo
997 999 | foo.whole | 2 +-
998 1000 | 1 files changed, 1 insertions(+), 1 deletions(-)
999 1001 |
1000 1002 x 0 add foo
1001 1003 foo.whole | 1 +
1002 1004 1 files changed, 1 insertions(+), 0 deletions(-)
1003 1005
1004 1006
1005 1007 $ cd ..
1006 1008
1007 1009 Fixing a secret commit should replace it with another secret commit.
1008 1010
1009 1011 $ hg init fixsecretcommit
1010 1012 $ cd fixsecretcommit
1011 1013
1012 1014 $ printf "foo\n" > foo.whole
1013 1015 $ hg commit -Aqm "add foo" --secret
1014 1016 $ hg fix -r .
1015 1017 $ hg log --template '{rev} {phase}\n'
1016 1018 1 secret
1017 1019 0 secret
1018 1020
1019 1021 $ cd ..
1020 1022
1021 1023 We should also preserve phase when fixing a draft commit while the user has
1022 1024 their default set to secret.
1023 1025
1024 1026 $ hg init respectphasesnewcommit
1025 1027 $ cd respectphasesnewcommit
1026 1028
1027 1029 $ printf "foo\n" > foo.whole
1028 1030 $ hg commit -Aqm "add foo"
1029 1031 $ hg --config phases.newcommit=secret fix -r .
1030 1032 $ hg log --template '{rev} {phase}\n'
1031 1033 1 draft
1032 1034 0 draft
1033 1035
1034 1036 $ cd ..
1035 1037
1036 1038 Debug output should show what fixer commands are being subprocessed, which is
1037 1039 useful for anyone trying to set up a new config.
1038 1040
1039 1041 $ hg init debugoutput
1040 1042 $ cd debugoutput
1041 1043
1042 1044 $ printf "foo\nbar\nbaz\n" > foo.changed
1043 1045 $ hg commit -Aqm "foo"
1044 1046 $ printf "Foo\nbar\nBaz\n" > foo.changed
1045 1047 $ hg --debug fix --working-dir
1046 1048 subprocess: * $TESTTMP/uppercase.py 1-1 3-3 (glob)
1047 1049
1048 1050 $ cd ..
1049 1051
1050 1052 Fixing an obsolete revision can cause divergence, so we abort unless the user
1051 1053 configures to allow it. This is not yet smart enough to know whether there is a
1052 1054 successor, but even then it is not likely intentional or idiomatic to fix an
1053 1055 obsolete revision.
1054 1056
1055 1057 $ hg init abortobsoleterev
1056 1058 $ cd abortobsoleterev
1057 1059
1058 1060 $ printf "foo\n" > foo.changed
1059 1061 $ hg commit -Aqm "foo"
1060 1062 $ hg debugobsolete `hg parents --template '{node}'`
1061 1063 obsoleted 1 changesets
1062 1064 $ hg --hidden fix -r 0
1063 1065 abort: fixing obsolete revision could cause divergence
1064 1066 [255]
1065 1067
1066 1068 $ hg --hidden fix -r 0 --config experimental.evolution.allowdivergence=true
1067 1069 $ hg cat -r tip foo.changed
1068 1070 FOO
1069 1071
1070 1072 $ cd ..
1071 1073
1072 1074 Test all of the available substitution values for fixer commands.
1073 1075
1074 1076 $ hg init substitution
1075 1077 $ cd substitution
1076 1078
1077 1079 $ mkdir foo
1078 1080 $ printf "hello\ngoodbye\n" > foo/bar
1079 1081 $ hg add
1080 1082 adding foo/bar
1081 1083 $ hg --config "fix.fail:command=printf '%s\n' '{rootpath}' '{basename}'" \
1082 1084 > --config "fix.fail:linerange='{first}' '{last}'" \
1083 1085 > --config "fix.fail:pattern=foo/bar" \
1084 1086 > fix --working-dir
1085 1087 $ cat foo/bar
1086 1088 foo/bar
1087 1089 bar
1088 1090 1
1089 1091 2
1090 1092
1091 1093 $ cd ..
1092 1094
1093 1095 The --base flag should allow picking the revisions to diff against for changed
1094 1096 files and incremental line formatting.
1095 1097
1096 1098 $ hg init baseflag
1097 1099 $ cd baseflag
1098 1100
1099 1101 $ printf "one\ntwo\n" > foo.changed
1100 1102 $ printf "bar\n" > bar.changed
1101 1103 $ hg commit -Aqm "first"
1102 1104 $ printf "one\nTwo\n" > foo.changed
1103 1105 $ hg commit -m "second"
1104 1106 $ hg fix -w --base .
1105 1107 $ hg status
1106 1108 $ hg fix -w --base null
1107 1109 $ cat foo.changed
1108 1110 ONE
1109 1111 TWO
1110 1112 $ cat bar.changed
1111 1113 BAR
1112 1114
1113 1115 $ cd ..
1114 1116
1115 1117 If the user asks to fix the parent of another commit, they are asking to create
1116 1118 an orphan. We must respect experimental.evolution.allowunstable.
1117 1119
1118 1120 $ hg init allowunstable
1119 1121 $ cd allowunstable
1120 1122
1121 1123 $ printf "one\n" > foo.whole
1122 1124 $ hg commit -Aqm "first"
1123 1125 $ printf "two\n" > foo.whole
1124 1126 $ hg commit -m "second"
1125 1127 $ hg --config experimental.evolution.allowunstable=False fix -r '.^'
1126 1128 abort: can only fix a changeset together with all its descendants
1127 1129 [255]
1128 1130 $ hg fix -r '.^'
1129 1131 1 new orphan changesets
1130 1132 $ hg cat -r 2 foo.whole
1131 1133 ONE
1132 1134
1133 1135 $ cd ..
1134 1136
1135 1137 The --base flag affects the set of files being fixed. So while the --whole flag
1136 1138 makes the base irrelevant for changed line ranges, it still changes the
1137 1139 meaning and effect of the command. In this example, no files or lines are fixed
1138 1140 until we specify the base, but then we do fix unchanged lines.
1139 1141
1140 1142 $ hg init basewhole
1141 1143 $ cd basewhole
1142 1144 $ printf "foo1\n" > foo.changed
1143 1145 $ hg commit -Aqm "first"
1144 1146 $ printf "foo2\n" >> foo.changed
1145 1147 $ printf "bar\n" > bar.changed
1146 1148 $ hg commit -Aqm "second"
1147 1149
1148 1150 $ hg fix --working-dir --whole
1149 1151 $ cat *.changed
1150 1152 bar
1151 1153 foo1
1152 1154 foo2
1153 1155
1154 1156 $ hg fix --working-dir --base 0 --whole
1155 1157 $ cat *.changed
1156 1158 BAR
1157 1159 FOO1
1158 1160 FOO2
1159 1161
1160 1162 $ cd ..
1161 1163
1162 1164 The :fileset subconfig was a misnomer, so we renamed it to :pattern. We will
1163 1165 still accept :fileset by itself as if it were :pattern, but this will issue a
1164 1166 warning.
1165 1167
1166 1168 $ hg init filesetispattern
1167 1169 $ cd filesetispattern
1168 1170
1169 1171 $ printf "foo\n" > foo.whole
1170 1172 $ printf "first\nsecond\n" > bar.txt
1171 1173 $ hg add -q
1172 1174 $ hg fix -w --config fix.sometool:fileset=bar.txt \
1173 1175 > --config fix.sometool:command="sort -r"
1174 1176 the fix.tool:fileset config name is deprecated; please rename it to fix.tool:pattern
1175 1177
1176 1178 $ cat foo.whole
1177 1179 FOO
1178 1180 $ cat bar.txt
1179 1181 second
1180 1182 first
1181 1183
1182 1184 $ cd ..
1183 1185
1184 1186 The execution order of tools can be controlled. This example doesn't work if
1185 1187 you sort after truncating, but the config defines the correct order while the
1186 1188 definitions are out of order (which might imply the incorrect order given the
1187 1189 implementation of fix). The goal is to use multiple tools to select the lowest
1188 1190 5 numbers in the file.
1189 1191
1190 1192 $ hg init priorityexample
1191 1193 $ cd priorityexample
1192 1194
1193 1195 $ cat >> .hg/hgrc <<EOF
1194 1196 > [fix]
1195 1197 > head:command = head -n 5
1196 1198 > head:pattern = numbers.txt
1197 1199 > head:priority = 1
1198 1200 > sort:command = sort -n
1199 1201 > sort:pattern = numbers.txt
1200 1202 > sort:priority = 2
1201 1203 > EOF
1202 1204
1203 1205 $ printf "8\n2\n3\n6\n7\n4\n9\n5\n1\n0\n" > numbers.txt
1204 1206 $ hg add -q
1205 1207 $ hg fix -w
1206 1208 $ cat numbers.txt
1207 1209 0
1208 1210 1
1209 1211 2
1210 1212 3
1211 1213 4
1212 1214
1213 1215 And of course we should be able to break this by reversing the execution order.
1214 1216 Test negative priorities while we're at it.
1215 1217
1216 1218 $ cat >> .hg/hgrc <<EOF
1217 1219 > [fix]
1218 1220 > head:priority = -1
1219 1221 > sort:priority = -2
1220 1222 > EOF
1221 1223 $ printf "8\n2\n3\n6\n7\n4\n9\n5\n1\n0\n" > numbers.txt
1222 1224 $ hg fix -w
1223 1225 $ cat numbers.txt
1224 1226 2
1225 1227 3
1226 1228 6
1227 1229 7
1228 1230 8
1229 1231
1230 1232 $ cd ..
1231 1233
1232 1234 It's possible for repeated applications of a fixer tool to create cycles in the
1233 1235 generated content of a file. For example, two users with different versions of
1234 1236 a code formatter might fight over the formatting when they run hg fix. In the
1235 1237 absence of other changes, this means we could produce commits with the same
1236 1238 hash in subsequent runs of hg fix. This is a problem unless we support
1237 1239 obsolescence cycles well. We avoid this by adding an extra field to the
1238 1240 successor which forces it to have a new hash. That's why this test creates
1239 1241 three revisions instead of two.
1240 1242
1241 1243 $ hg init cyclictool
1242 1244 $ cd cyclictool
1243 1245
1244 1246 $ cat >> .hg/hgrc <<EOF
1245 1247 > [fix]
1246 1248 > swapletters:command = tr ab ba
1247 1249 > swapletters:pattern = foo
1248 1250 > EOF
1249 1251
1250 1252 $ echo ab > foo
1251 1253 $ hg commit -Aqm foo
1252 1254
1253 1255 $ hg fix -r 0
1254 1256 $ hg fix -r 1
1255 1257
1256 1258 $ hg cat -r 0 foo --hidden
1257 1259 ab
1258 1260 $ hg cat -r 1 foo --hidden
1259 1261 ba
1260 1262 $ hg cat -r 2 foo
1261 1263 ab
1262 1264
1263 1265 $ cd ..
1264 1266
General Comments 0
You need to be logged in to leave comments. Login now