Show More
@@ -155,3 +155,4 b' 2f427b57bf9019c6dc3750baa539dc22c1be50f6' | |||
|
155 | 155 | 1e2454b60e5936f5e77498cab2648db469504487 0 iQJVBAABCAA/FiEEOoFVFj0OIKUw/LeGR6Z/+qNGqs4FAlnqRBUhHGtidWxsb2NrK21lcmN1cmlhbEByaW5nd29ybGQub3JnAAoJEEemf/qjRqrOAQQP/28EzmTKFL/RxmNYePdzqrmcdJ2tn+s7OYmGdtneN2sESZ4MK0xb5Q8Mkm+41aXS52zzJdz9ynwdun8DG4wZ3sE5MOG+GgK6K0ecOv1XTKS3a2DkUM0fl5hlcXN7Zz7m7m5M6sy6vSxHP7kTyzQWt//z175ZLSQEu1a0nm/BLH+HP9e8DfnJ2Nfcnwp32kV0Nj1xTqjRV1Yo/oCnXfVvsxEJU+CDUGBiLc29ZcoWVbTw9c1VcxihJ6k0pK711KZ+bedSk7yc1OudiJF7idjB0bLQY6ESHNNNjK8uLppok0RsyuhvvDTAoTsl1rMKGmXMM0Ela3/5oxZ/5lUZB73vEJhzEi48ULvstpq82EO39KylkEfQxwMBPhnBIHQaGRkl7QPLXGOYUDMY6gT08Sm3e8/NqEJc/AgckXehpH3gSS2Ji2xg7/E8H5plGsswFidw//oYTTwm0j0halWpB521TD2wmjkjRHXzk1mj0EoFQUMfwHTIZU3E8flUBasD3mZ9XqZJPr66RV7QCrXayH75B/i0CyNqd/Hv5Tkf2TlC3EkEBZwZyAjqw7EyL1LuS936sc7fWuMFsH5k/fwjVwzIc1LmP+nmk2Dd9hIC66vec4w1QZeeAXuDKgOJjvQzj2n+uYRuObl4kKcxvoXqgQN0glGuB1IW7lPllGHR1kplhoub |
|
156 | 156 | 0ccb43d4cf01d013ae05917ec4f305509f851b2d 0 iQJVBAABCAA/FiEEOoFVFj0OIKUw/LeGR6Z/+qNGqs4FAln6Qp8hHGtidWxsb2NrK21lcmN1cmlhbEByaW5nd29ybGQub3JnAAoJEEemf/qjRqrOJ8MP/2ufm/dbrFoE0F8hewhztG1vS4stus13lZ9lmM9kza8OKeOgY/MDH8GaV3O8GnRiCNUFsVD8JEIexE31c84H2Ie7VQO0GQSUHSyMCRrbED6IvfrWp6EZ6RDNPk4LHBfxCuPmuVHGRoGZtsLKJBPIxIHJKWMlEJlj9BZuUxZp/8kurQ6CXwblVbFzXdOaZQlioOBH27Bk3S0+gXfJ+wA2ed5XOQvT9jwjqC8y/1t8obaoPTpzyAvb9NArG+9RT9vfNN42aWISZNwg6RW5oLJISqoGrAes6EoG7dZfOC0UoKMVYXoNvZzJvVlMHyjugIoid+WI+V8y9bPrRTfbPCmocCzEzCOLEHQta8roNijB0bKcq8hmQPHcMyXlj1Srnqlco49jbhftgJoPTwzb10wQyU0VFvaZDPW/EQUT3M/k4j3sVESjANdyG1iu6EDV080LK1LgAdhjpKMBbf6mcgAe06/07XFMbKNrZMEislOcVFp98BSKjdioUNpy91rCeSmkEsASJ3yMArRnSkuVgpyrtJaGWl79VUcmOwKhUOA/8MXMz/Oqu7hvve/sgv71xlnim460nnLw6YHPyeeCsz6KSoUK3knFXAbTk/0jvU1ixUZbI122aMzX04UgPGeTukCOUw49XfaOdN+x0YXlkl4PsrnRQhIoixY2gosPpK4YO73G |
|
157 | 157 | cabc840ffdee8a72f3689fb77dd74d04fdc2bc04 0 iQJEBAABCAAuFiEEK8zhT1xnJaouqK63ucncgkqlvdUFAloB+EYQHHJhZkBkdXJpbjQyLmNvbQAKCRC5ydyCSqW91TfwEAC/pYW7TC8mQnqSJzde4yiv2+zgflfJzRlg5rbvlUQl1gSBla3sFADZcic0ebAc+8XUu8eIzyPX+oa4wjsHvL13silUCkUzTEEQLqfKPX1bhA4mwfSDb5A7v2VZ5q8qhRGnlhTsB79ML8uBOhR/Bigdm2ixURPEZ37pWljiMp9XWBMtxPxXn/m0n5CDViibX6QqQCR4k3orcsIGd72YXU6B8NGbBN8qlqMSd0pGvSF4vM2cgVhz7D71+zU4XL/HVP97aU9GsOwN9QWW029DOJu6KG6x51WWtfD/tzyNDu7+lZ5/IKyqHX4tyqCIXEGAsQ3XypeHgCq5hV3E6LJLRqPcLpUNDiQlCg6tNPRaOuMC878MRIlffKqMH+sWo8Z7zHrut+LfRh5/k1aCh4J+FIlE6Hgbvbvv2Z8JxDpUKl0Tr+i0oHNTapbGXIecq1ZFR4kcdchodUHXBC2E6HWR50/ek5YKPddzw8WPGsBtzXMfkhFr3WkvyP2Gbe2XJnkuYptTJA+u2CfhrvgmWsYlvt/myTaMZQEzZ+uir4Xoo5NvzqTL30SFqPrP4Nh0n9G6vpVJl/eZxoYK9jL3VC0vDhnZXitkvDpjXZuJqw/HgExXWKZFfiQ3X2HY48v1gvJiSegZ5rX+uGGJtW2/Mp5FidePEgnFIqZW/yhBfs2Hzj1D2A== |
|
158 | a92b9f8e11ba330614cdfd6af0e03b15c1ff3797 0 iQJVBAABCAA/FiEEOoFVFj0OIKUw/LeGR6Z/+qNGqs4FAlohslshHGtidWxsb2NrK21lcmN1cmlhbEByaW5nd29ybGQub3JnAAoJEEemf/qjRqrO7P8P/1qGts96acEdB9BZbK/Eesalb1wUByLXZoP8j+1wWwqh/Kq/q7V4Qe0z1jw/92oZbmnLy2C8sDhWv/XKxACKv69oPrcqQix1E8M+07u88ZXqHJMSxkOmvA2Vimp9EG1qgje+qchgOVgvhEhysA96bRpEnc6V0RnBqI5UdfbKtlfBmX5mUE/qsoBZhly1FTmzV1bhYlGgNLyqtJQpcbA34wyPoywsp8DRBiHWrIzz5XNR+DJFTOe4Kqio1i5r8R4QSIM5vtTbj5pbsmtGcP2CsFC9S3xTSAU6AEJKxGpubPk3ckNj3P9zolvR7krU5Jt8LIgXSVaKLt9rPhmxCbPrLtORgXkUupJcrwzQl+oYz5bkl9kowFa959waIPYoCuuW402mOTDq/L3xwDH9AKK5rELPl3fNo+5OIDKAKRIu6zRSAzBtyGT6kkfb1NSghumP4scR7cgUmLaNibZBa8eJj92gwf+ucSGoB/dF/YHWNe0jY09LFK3nyCoftmyLzxcRk1JLGNngw8MCIuisHTskhxSm/qlX7qjunoZnA3yy9behhy/YaFt4YzYZbMTivt2gszX5ktToaDqfxWDYdIa79kp8G68rYPeybelTS74LwbK3blXPI3I1nddkW52znHYLvW6BYyi+QQ5jPZLkiOC+AF0q+c4gYmPaLVN/mpMZjjmB |
@@ -168,3 +168,4 b' 2f427b57bf9019c6dc3750baa539dc22c1be50f6' | |||
|
168 | 168 | 1e2454b60e5936f5e77498cab2648db469504487 4.4-rc |
|
169 | 169 | 0ccb43d4cf01d013ae05917ec4f305509f851b2d 4.4 |
|
170 | 170 | cabc840ffdee8a72f3689fb77dd74d04fdc2bc04 4.4.1 |
|
171 | a92b9f8e11ba330614cdfd6af0e03b15c1ff3797 4.4.2 |
@@ -455,6 +455,7 b' def updatelfiles(ui, repo, filelist=None' | |||
|
455 | 455 | lfiles = [f for f in lfiles if f in filelist] |
|
456 | 456 | |
|
457 | 457 | update = {} |
|
458 | dropped = set() | |
|
458 | 459 | updated, removed = 0, 0 |
|
459 | 460 | wvfs = repo.wvfs |
|
460 | 461 | wctx = repo[None] |
@@ -476,7 +477,11 b' def updatelfiles(ui, repo, filelist=None' | |||
|
476 | 477 | expecthash = lfutil.readasstandin(wctx[relstandin]) |
|
477 | 478 | if expecthash != '': |
|
478 | 479 | if lfile not in wctx: # not switched to normal file |
|
479 | wvfs.unlinkpath(rellfile, ignoremissing=True) | |
|
480 | if repo.dirstate[relstandin] != '?': | |
|
481 | wvfs.unlinkpath(rellfile, ignoremissing=True) | |
|
482 | else: | |
|
483 | dropped.add(rellfile) | |
|
484 | ||
|
480 | 485 | # use normallookup() to allocate an entry in largefiles |
|
481 | 486 | # dirstate to prevent lfilesrepo.status() from reporting |
|
482 | 487 | # missing files as removed. |
@@ -496,6 +501,15 b' def updatelfiles(ui, repo, filelist=None' | |||
|
496 | 501 | lfdirstate.write() |
|
497 | 502 | |
|
498 | 503 | if lfiles: |
|
504 | lfiles = [f for f in lfiles if f not in dropped] | |
|
505 | ||
|
506 | for f in dropped: | |
|
507 | repo.wvfs.unlinkpath(lfutil.standin(f)) | |
|
508 | ||
|
509 | # This needs to happen for dropped files, otherwise they stay in | |
|
510 | # the M state. | |
|
511 | lfutil.synclfdirstate(repo, lfdirstate, f, normallookup) | |
|
512 | ||
|
499 | 513 | statuswriter(_('getting changed largefiles\n')) |
|
500 | 514 | cachelfiles(ui, repo, None, lfiles) |
|
501 | 515 |
@@ -220,8 +220,17 b' def _loadnewui(srcui, args):' | |||
|
220 | 220 | newui._csystem = srcui._csystem |
|
221 | 221 | |
|
222 | 222 | # command line args |
|
223 | args = args[:] | |
|
224 | dispatch._parseconfig(newui, dispatch._earlygetopt(['--config'], args)) | |
|
223 | options = {} | |
|
224 | if srcui.plain('strictflags'): | |
|
225 | options.update(dispatch._earlyparseopts(args)) | |
|
226 | else: | |
|
227 | args = args[:] | |
|
228 | options['config'] = dispatch._earlygetopt(['--config'], args) | |
|
229 | cwds = dispatch._earlygetopt(['--cwd'], args) | |
|
230 | options['cwd'] = cwds and cwds[-1] or '' | |
|
231 | rpath = dispatch._earlygetopt(["-R", "--repository", "--repo"], args) | |
|
232 | options['repository'] = rpath and rpath[-1] or '' | |
|
233 | dispatch._parseconfig(newui, options['config']) | |
|
225 | 234 | |
|
226 | 235 | # stolen from tortoisehg.util.copydynamicconfig() |
|
227 | 236 | for section, name, value in srcui.walkconfig(): |
@@ -232,10 +241,9 b' def _loadnewui(srcui, args):' | |||
|
232 | 241 | newui.setconfig(section, name, value, source) |
|
233 | 242 | |
|
234 | 243 | # load wd and repo config, copied from dispatch.py |
|
235 | cwds = dispatch._earlygetopt(['--cwd'], args) | |
|
236 |
cwd = cwd |
|
|
237 | rpath = dispatch._earlygetopt(["-R", "--repository", "--repo"], args) | |
|
238 | rpath = rpath and rpath[-1] or '' | |
|
244 | cwd = options['cwd'] | |
|
245 | cwd = cwd and os.path.realpath(cwd) or None | |
|
246 | rpath = options['repository'] | |
|
239 | 247 | path, newlui = dispatch._getlocal(newui, rpath, wd=cwd) |
|
240 | 248 | |
|
241 | 249 | return (newui, newlui) |
@@ -150,6 +150,8 b' def dispatch(req):' | |||
|
150 | 150 | try: |
|
151 | 151 | if not req.ui: |
|
152 | 152 | req.ui = uimod.ui.load() |
|
153 | if req.ui.plain('strictflags'): | |
|
154 | req.earlyoptions.update(_earlyparseopts(req.args)) | |
|
153 | 155 | if _earlyreqoptbool(req, 'traceback', ['--traceback']): |
|
154 | 156 | req.ui.setconfig('ui', 'traceback', 'on', '--traceback') |
|
155 | 157 | |
@@ -644,6 +646,12 b' def _parseconfig(ui, config):' | |||
|
644 | 646 | |
|
645 | 647 | return configs |
|
646 | 648 | |
|
649 | def _earlyparseopts(args): | |
|
650 | options = {} | |
|
651 | fancyopts.fancyopts(args, commands.globalopts, options, | |
|
652 | gnu=False, early=True) | |
|
653 | return options | |
|
654 | ||
|
647 | 655 | def _earlygetopt(aliases, args, strip=True): |
|
648 | 656 | """Return list of values for an option (or aliases). |
|
649 | 657 | |
@@ -732,12 +740,16 b' def _earlygetopt(aliases, args, strip=Tr' | |||
|
732 | 740 | |
|
733 | 741 | def _earlyreqopt(req, name, aliases): |
|
734 | 742 | """Peek a list option without using a full options table""" |
|
743 | if req.ui.plain('strictflags'): | |
|
744 | return req.earlyoptions[name] | |
|
735 | 745 | values = _earlygetopt(aliases, req.args, strip=False) |
|
736 | 746 | req.earlyoptions[name] = values |
|
737 | 747 | return values |
|
738 | 748 | |
|
739 | 749 | def _earlyreqoptstr(req, name, aliases): |
|
740 | 750 | """Peek a string option without using a full options table""" |
|
751 | if req.ui.plain('strictflags'): | |
|
752 | return req.earlyoptions[name] | |
|
741 | 753 | value = (_earlygetopt(aliases, req.args, strip=False) or [''])[-1] |
|
742 | 754 | req.earlyoptions[name] = value |
|
743 | 755 | return value |
@@ -745,13 +757,15 b' def _earlyreqoptstr(req, name, aliases):' | |||
|
745 | 757 | def _earlyreqoptbool(req, name, aliases): |
|
746 | 758 | """Peek a boolean option without using a full options table |
|
747 | 759 | |
|
748 | >>> req = request([b'x', b'--debugger']) | |
|
760 | >>> req = request([b'x', b'--debugger'], uimod.ui()) | |
|
749 | 761 | >>> _earlyreqoptbool(req, b'debugger', [b'--debugger']) |
|
750 | 762 | True |
|
751 | 763 | |
|
752 | >>> req = request([b'x', b'--', b'--debugger']) | |
|
764 | >>> req = request([b'x', b'--', b'--debugger'], uimod.ui()) | |
|
753 | 765 | >>> _earlyreqoptbool(req, b'debugger', [b'--debugger']) |
|
754 | 766 | """ |
|
767 | if req.ui.plain('strictflags'): | |
|
768 | return req.earlyoptions[name] | |
|
755 | 769 | try: |
|
756 | 770 | argcount = req.args.index("--") |
|
757 | 771 | except ValueError: |
@@ -7,6 +7,8 b'' | |||
|
7 | 7 | |
|
8 | 8 | from __future__ import absolute_import |
|
9 | 9 | |
|
10 | import functools | |
|
11 | ||
|
10 | 12 | from .i18n import _ |
|
11 | 13 | from . import ( |
|
12 | 14 | error, |
@@ -24,6 +26,179 b' nevernegate = {' | |||
|
24 | 26 | 'version', |
|
25 | 27 | } |
|
26 | 28 | |
|
29 | def _earlyoptarg(arg, shortlist, namelist): | |
|
30 | """Check if the given arg is a valid unabbreviated option | |
|
31 | ||
|
32 | Returns (flag_str, has_embedded_value?, embedded_value, takes_value?) | |
|
33 | ||
|
34 | >>> def opt(arg): | |
|
35 | ... return _earlyoptarg(arg, b'R:q', [b'cwd=', b'debugger']) | |
|
36 | ||
|
37 | long form: | |
|
38 | ||
|
39 | >>> opt(b'--cwd') | |
|
40 | ('--cwd', False, '', True) | |
|
41 | >>> opt(b'--cwd=') | |
|
42 | ('--cwd', True, '', True) | |
|
43 | >>> opt(b'--cwd=foo') | |
|
44 | ('--cwd', True, 'foo', True) | |
|
45 | >>> opt(b'--debugger') | |
|
46 | ('--debugger', False, '', False) | |
|
47 | >>> opt(b'--debugger=') # invalid but parsable | |
|
48 | ('--debugger', True, '', False) | |
|
49 | ||
|
50 | short form: | |
|
51 | ||
|
52 | >>> opt(b'-R') | |
|
53 | ('-R', False, '', True) | |
|
54 | >>> opt(b'-Rfoo') | |
|
55 | ('-R', True, 'foo', True) | |
|
56 | >>> opt(b'-q') | |
|
57 | ('-q', False, '', False) | |
|
58 | >>> opt(b'-qfoo') # invalid but parsable | |
|
59 | ('-q', True, 'foo', False) | |
|
60 | ||
|
61 | unknown or invalid: | |
|
62 | ||
|
63 | >>> opt(b'--unknown') | |
|
64 | ('', False, '', False) | |
|
65 | >>> opt(b'-u') | |
|
66 | ('', False, '', False) | |
|
67 | >>> opt(b'-ufoo') | |
|
68 | ('', False, '', False) | |
|
69 | >>> opt(b'--') | |
|
70 | ('', False, '', False) | |
|
71 | >>> opt(b'-') | |
|
72 | ('', False, '', False) | |
|
73 | >>> opt(b'-:') | |
|
74 | ('', False, '', False) | |
|
75 | >>> opt(b'-:foo') | |
|
76 | ('', False, '', False) | |
|
77 | """ | |
|
78 | if arg.startswith('--'): | |
|
79 | flag, eq, val = arg.partition('=') | |
|
80 | if flag[2:] in namelist: | |
|
81 | return flag, bool(eq), val, False | |
|
82 | if flag[2:] + '=' in namelist: | |
|
83 | return flag, bool(eq), val, True | |
|
84 | elif arg.startswith('-') and arg != '-' and not arg.startswith('-:'): | |
|
85 | flag, val = arg[:2], arg[2:] | |
|
86 | i = shortlist.find(flag[1:]) | |
|
87 | if i >= 0: | |
|
88 | return flag, bool(val), val, shortlist.startswith(':', i + 1) | |
|
89 | return '', False, '', False | |
|
90 | ||
|
91 | def earlygetopt(args, shortlist, namelist, gnu=False, keepsep=False): | |
|
92 | """Parse options like getopt, but ignores unknown options and abbreviated | |
|
93 | forms | |
|
94 | ||
|
95 | If gnu=False, this stops processing options as soon as a non/unknown-option | |
|
96 | argument is encountered. Otherwise, option and non-option arguments may be | |
|
97 | intermixed, and unknown-option arguments are taken as non-option. | |
|
98 | ||
|
99 | If keepsep=True, '--' won't be removed from the list of arguments left. | |
|
100 | This is useful for stripping early options from a full command arguments. | |
|
101 | ||
|
102 | >>> def get(args, gnu=False, keepsep=False): | |
|
103 | ... return earlygetopt(args, b'R:q', [b'cwd=', b'debugger'], | |
|
104 | ... gnu=gnu, keepsep=keepsep) | |
|
105 | ||
|
106 | default parsing rules for early options: | |
|
107 | ||
|
108 | >>> get([b'x', b'--cwd', b'foo', b'-Rbar', b'-q', b'y'], gnu=True) | |
|
109 | ([('--cwd', 'foo'), ('-R', 'bar'), ('-q', '')], ['x', 'y']) | |
|
110 | >>> get([b'x', b'--cwd=foo', b'y', b'-R', b'bar', b'--debugger'], gnu=True) | |
|
111 | ([('--cwd', 'foo'), ('-R', 'bar'), ('--debugger', '')], ['x', 'y']) | |
|
112 | >>> get([b'--unknown', b'--cwd=foo', b'--', '--debugger'], gnu=True) | |
|
113 | ([('--cwd', 'foo')], ['--unknown', '--debugger']) | |
|
114 | ||
|
115 | restricted parsing rules (early options must come first): | |
|
116 | ||
|
117 | >>> get([b'--cwd', b'foo', b'-Rbar', b'x', b'-q', b'y'], gnu=False) | |
|
118 | ([('--cwd', 'foo'), ('-R', 'bar')], ['x', '-q', 'y']) | |
|
119 | >>> get([b'--cwd=foo', b'x', b'y', b'-R', b'bar', b'--debugger'], gnu=False) | |
|
120 | ([('--cwd', 'foo')], ['x', 'y', '-R', 'bar', '--debugger']) | |
|
121 | >>> get([b'--unknown', b'--cwd=foo', b'--', '--debugger'], gnu=False) | |
|
122 | ([], ['--unknown', '--cwd=foo', '--debugger']) | |
|
123 | ||
|
124 | stripping early options (without loosing '--'): | |
|
125 | ||
|
126 | >>> get([b'x', b'-Rbar', b'--', '--debugger'], gnu=True, keepsep=True)[1] | |
|
127 | ['x', '--', '--debugger'] | |
|
128 | ||
|
129 | last argument: | |
|
130 | ||
|
131 | >>> get([b'--cwd']) | |
|
132 | ([], ['--cwd']) | |
|
133 | >>> get([b'--cwd=foo']) | |
|
134 | ([('--cwd', 'foo')], []) | |
|
135 | >>> get([b'-R']) | |
|
136 | ([], ['-R']) | |
|
137 | >>> get([b'-Rbar']) | |
|
138 | ([('-R', 'bar')], []) | |
|
139 | >>> get([b'-q']) | |
|
140 | ([('-q', '')], []) | |
|
141 | >>> get([b'-q', b'--']) | |
|
142 | ([('-q', '')], []) | |
|
143 | ||
|
144 | value passed to bool options: | |
|
145 | ||
|
146 | >>> get([b'--debugger=foo', b'x']) | |
|
147 | ([], ['--debugger=foo', 'x']) | |
|
148 | >>> get([b'-qfoo', b'x']) | |
|
149 | ([], ['-qfoo', 'x']) | |
|
150 | ||
|
151 | short option isn't separated with '=': | |
|
152 | ||
|
153 | >>> get([b'-R=bar']) | |
|
154 | ([('-R', '=bar')], []) | |
|
155 | ||
|
156 | ':' may be in shortlist, but shouldn't be taken as an option letter: | |
|
157 | ||
|
158 | >>> get([b'-:', b'y']) | |
|
159 | ([], ['-:', 'y']) | |
|
160 | ||
|
161 | '-' is a valid non-option argument: | |
|
162 | ||
|
163 | >>> get([b'-', b'y']) | |
|
164 | ([], ['-', 'y']) | |
|
165 | """ | |
|
166 | # ignoring everything just after '--' isn't correct as '--' may be an | |
|
167 | # option value (e.g. ['-R', '--']), but we do that consistently. | |
|
168 | try: | |
|
169 | argcount = args.index('--') | |
|
170 | except ValueError: | |
|
171 | argcount = len(args) | |
|
172 | ||
|
173 | parsedopts = [] | |
|
174 | parsedargs = [] | |
|
175 | pos = 0 | |
|
176 | while pos < argcount: | |
|
177 | arg = args[pos] | |
|
178 | flag, hasval, val, takeval = _earlyoptarg(arg, shortlist, namelist) | |
|
179 | if not hasval and takeval and pos + 1 >= argcount: | |
|
180 | # missing last argument | |
|
181 | break | |
|
182 | if not flag or hasval and not takeval: | |
|
183 | # non-option argument or -b/--bool=INVALID_VALUE | |
|
184 | if gnu: | |
|
185 | parsedargs.append(arg) | |
|
186 | pos += 1 | |
|
187 | else: | |
|
188 | break | |
|
189 | elif hasval == takeval: | |
|
190 | # -b/--bool or -s/--str=VALUE | |
|
191 | parsedopts.append((flag, val)) | |
|
192 | pos += 1 | |
|
193 | else: | |
|
194 | # -s/--str VALUE | |
|
195 | parsedopts.append((flag, args[pos + 1])) | |
|
196 | pos += 2 | |
|
197 | ||
|
198 | parsedargs.extend(args[pos:argcount]) | |
|
199 | parsedargs.extend(args[argcount + (not keepsep):]) | |
|
200 | return parsedopts, parsedargs | |
|
201 | ||
|
27 | 202 | def gnugetopt(args, options, longoptions): |
|
28 | 203 | """Parse options mostly like getopt.gnu_getopt. |
|
29 | 204 | |
@@ -51,7 +226,7 b' def gnugetopt(args, options, longoptions' | |||
|
51 | 226 | return opts, args |
|
52 | 227 | |
|
53 | 228 | |
|
54 | def fancyopts(args, options, state, gnu=False): | |
|
229 | def fancyopts(args, options, state, gnu=False, early=False): | |
|
55 | 230 | """ |
|
56 | 231 | read args, parse options, and store options in state |
|
57 | 232 | |
@@ -124,7 +299,9 b' def fancyopts(args, options, state, gnu=' | |||
|
124 | 299 | namelist.append(oname) |
|
125 | 300 | |
|
126 | 301 | # parse arguments |
|
127 |
if |
|
|
302 | if early: | |
|
303 | parse = functools.partial(earlygetopt, gnu=gnu) | |
|
304 | elif gnu: | |
|
128 | 305 | parse = gnugetopt |
|
129 | 306 | else: |
|
130 | 307 | parse = pycompat.getoptb |
@@ -56,9 +56,17 b' HGPLAIN' | |||
|
56 | 56 | localization. This can be useful when scripting against Mercurial |
|
57 | 57 | in the face of existing user configuration. |
|
58 | 58 | |
|
59 | In addition to the features disabled by ``HGPLAIN=``, the following | |
|
60 | values can be specified to adjust behavior: | |
|
61 | ||
|
62 | ``+strictflags`` | |
|
63 | Restrict parsing of command line flags. | |
|
64 | ||
|
59 | 65 | Equivalent options set via command line flags or environment |
|
60 | 66 | variables are not overridden. |
|
61 | 67 | |
|
68 | See :hg:`help scripting` for details. | |
|
69 | ||
|
62 | 70 | HGPLAINEXCEPT |
|
63 | 71 | This is a comma-separated list of features to preserve when |
|
64 | 72 | HGPLAIN is enabled. Currently the following values are supported: |
@@ -74,6 +74,32 b' HGRCPATH' | |||
|
74 | 74 | like the username and extensions that may be required to interface |
|
75 | 75 | with a repository. |
|
76 | 76 | |
|
77 | Command-line Flags | |
|
78 | ================== | |
|
79 | ||
|
80 | Mercurial's default command-line parser is designed for humans, and is not | |
|
81 | robust against malicious input. For instance, you can start a debugger by | |
|
82 | passing ``--debugger`` as an option value:: | |
|
83 | ||
|
84 | $ REV=--debugger sh -c 'hg log -r "$REV"' | |
|
85 | ||
|
86 | This happens because several command-line flags need to be scanned without | |
|
87 | using a concrete command table, which may be modified while loading repository | |
|
88 | settings and extensions. | |
|
89 | ||
|
90 | Since Mercurial 4.4.2, the parsing of such flags may be restricted by setting | |
|
91 | ``HGPLAIN=+strictflags``. When this feature is enabled, all early options | |
|
92 | (e.g. ``-R/--repository``, ``--cwd``, ``--config``) must be specified first | |
|
93 | amongst the other global options, and cannot be injected to an arbitrary | |
|
94 | location:: | |
|
95 | ||
|
96 | $ HGPLAIN=+strictflags hg -R "$REPO" log -r "$REV" | |
|
97 | ||
|
98 | In earlier Mercurial versions where ``+strictflags`` isn't available, you | |
|
99 | can mitigate the issue by concatenating an option value with its flag:: | |
|
100 | ||
|
101 | $ hg log -r"$REV" --keyword="$KEYWORD" | |
|
102 | ||
|
77 | 103 | Consuming Command Output |
|
78 | 104 | ======================== |
|
79 | 105 |
@@ -90,7 +90,7 b' Interaction with Mercurial Commands' | |||
|
90 | 90 | :archive: archive does not recurse in subrepositories unless |
|
91 | 91 | -S/--subrepos is specified. |
|
92 | 92 | |
|
93 |
:cat: |
|
|
93 | :cat: Git subrepositories only support exact file matches. | |
|
94 | 94 | Subversion subrepositories are currently ignored. |
|
95 | 95 | |
|
96 | 96 | :commit: commit creates a consistent snapshot of the state of the |
@@ -653,7 +653,7 b' def _checkunknownfile(repo, wctx, mctx, ' | |||
|
653 | 653 | and repo.dirstate.normalize(f) not in repo.dirstate |
|
654 | 654 | and mctx[f2].cmp(wctx[f])) |
|
655 | 655 | |
|
656 | def _checkunknowndirs(repo, f): | |
|
656 | class _unknowndirschecker(object): | |
|
657 | 657 | """ |
|
658 | 658 | Look for any unknown files or directories that may have a path conflict |
|
659 | 659 | with a file. If any path prefix of the file exists as a file or link, |
@@ -663,23 +663,42 b' def _checkunknowndirs(repo, f):' | |||
|
663 | 663 | Returns the shortest path at which a conflict occurs, or None if there is |
|
664 | 664 | no conflict. |
|
665 | 665 | """ |
|
666 | def __init__(self): | |
|
667 | # A set of paths known to be good. This prevents repeated checking of | |
|
668 | # dirs. It will be updated with any new dirs that are checked and found | |
|
669 | # to be safe. | |
|
670 | self._unknowndircache = set() | |
|
666 | 671 | |
|
667 | # Check for path prefixes that exist as unknown files. | |
|
668 | for p in reversed(list(util.finddirs(f))): | |
|
669 | if (repo.wvfs.audit.check(p) | |
|
670 | and repo.wvfs.isfileorlink(p) | |
|
671 | and repo.dirstate.normalize(p) not in repo.dirstate): | |
|
672 | return p | |
|
672 | # A set of paths that are known to be absent. This prevents repeated | |
|
673 | # checking of subdirectories that are known not to exist. It will be | |
|
674 | # updated with any new dirs that are checked and found to be absent. | |
|
675 | self._missingdircache = set() | |
|
673 | 676 | |
|
674 | # Check if the file conflicts with a directory containing unknown files. | |
|
675 | if repo.wvfs.audit.check(f) and repo.wvfs.isdir(f): | |
|
676 | # Does the directory contain any files that are not in the dirstate? | |
|
677 | for p, dirs, files in repo.wvfs.walk(f): | |
|
678 | for fn in files: | |
|
679 | relf = repo.dirstate.normalize(repo.wvfs.reljoin(p, fn)) | |
|
680 |
|
|
|
681 | return f | |
|
682 | return None | |
|
677 | def __call__(self, repo, f): | |
|
678 | # Check for path prefixes that exist as unknown files. | |
|
679 | for p in reversed(list(util.finddirs(f))): | |
|
680 | if p in self._missingdircache: | |
|
681 | return | |
|
682 | if p in self._unknowndircache: | |
|
683 | continue | |
|
684 | if repo.wvfs.audit.check(p): | |
|
685 | if (repo.wvfs.isfileorlink(p) | |
|
686 | and repo.dirstate.normalize(p) not in repo.dirstate): | |
|
687 | return p | |
|
688 | if not repo.wvfs.lexists(p): | |
|
689 | self._missingdircache.add(p) | |
|
690 | return | |
|
691 | self._unknowndircache.add(p) | |
|
692 | ||
|
693 | # Check if the file conflicts with a directory containing unknown files. | |
|
694 | if repo.wvfs.audit.check(f) and repo.wvfs.isdir(f): | |
|
695 | # Does the directory contain any files that are not in the dirstate? | |
|
696 | for p, dirs, files in repo.wvfs.walk(f): | |
|
697 | for fn in files: | |
|
698 | relf = repo.dirstate.normalize(repo.wvfs.reljoin(p, fn)) | |
|
699 | if relf not in repo.dirstate: | |
|
700 | return f | |
|
701 | return None | |
|
683 | 702 | |
|
684 | 703 | def _checkunknownfiles(repo, wctx, mctx, force, actions, mergeforce): |
|
685 | 704 | """ |
@@ -701,12 +720,13 b' def _checkunknownfiles(repo, wctx, mctx,' | |||
|
701 | 720 | elif config == 'warn': |
|
702 | 721 | warnconflicts.update(conflicts) |
|
703 | 722 | |
|
723 | checkunknowndirs = _unknowndirschecker() | |
|
704 | 724 | for f, (m, args, msg) in actions.iteritems(): |
|
705 | 725 | if m in ('c', 'dc'): |
|
706 | 726 | if _checkunknownfile(repo, wctx, mctx, f): |
|
707 | 727 | fileconflicts.add(f) |
|
708 | 728 | elif pathconfig and f not in wctx: |
|
709 |
path = |
|
|
729 | path = checkunknowndirs(repo, f) | |
|
710 | 730 | if path is not None: |
|
711 | 731 | pathconflicts.add(path) |
|
712 | 732 | elif m == 'dg': |
@@ -895,34 +915,21 b' def checkpathconflicts(repo, wctx, mctx,' | |||
|
895 | 915 | # can't be updated to cleanly. |
|
896 | 916 | invalidconflicts = set() |
|
897 | 917 | |
|
918 | # The set of directories that contain files that are being created. | |
|
919 | createdfiledirs = set() | |
|
920 | ||
|
898 | 921 | # The set of files deleted by all the actions. |
|
899 | 922 | deletedfiles = set() |
|
900 | 923 | |
|
901 | 924 | for f, (m, args, msg) in actions.items(): |
|
902 | 925 | if m in ('c', 'dc', 'm', 'cm'): |
|
903 | 926 | # This action may create a new local file. |
|
927 | createdfiledirs.update(util.finddirs(f)) | |
|
904 | 928 | if mf.hasdir(f): |
|
905 | 929 | # The file aliases a local directory. This might be ok if all |
|
906 | 930 | # the files in the local directory are being deleted. This |
|
907 | 931 | # will be checked once we know what all the deleted files are. |
|
908 | 932 | remoteconflicts.add(f) |
|
909 | for p in util.finddirs(f): | |
|
910 | if p in mf: | |
|
911 | if p in mctx: | |
|
912 | # The file is in a directory which aliases both a local | |
|
913 | # and a remote file. This is an internal inconsistency | |
|
914 | # within the remote manifest. | |
|
915 | invalidconflicts.add(p) | |
|
916 | else: | |
|
917 | # The file is in a directory which aliases a local file. | |
|
918 | # We will need to rename the local file. | |
|
919 | localconflicts.add(p) | |
|
920 | if p in actions and actions[p][0] in ('c', 'dc', 'm', 'cm'): | |
|
921 | # The file is in a directory which aliases a remote file. | |
|
922 | # This is an internal inconsistency within the remote | |
|
923 | # manifest. | |
|
924 | invalidconflicts.add(p) | |
|
925 | ||
|
926 | 933 | # Track the names of all deleted files. |
|
927 | 934 | if m == 'r': |
|
928 | 935 | deletedfiles.add(f) |
@@ -934,6 +941,24 b' def checkpathconflicts(repo, wctx, mctx,' | |||
|
934 | 941 | f2, flags = args |
|
935 | 942 | deletedfiles.add(f2) |
|
936 | 943 | |
|
944 | # Check all directories that contain created files for path conflicts. | |
|
945 | for p in createdfiledirs: | |
|
946 | if p in mf: | |
|
947 | if p in mctx: | |
|
948 | # A file is in a directory which aliases both a local | |
|
949 | # and a remote file. This is an internal inconsistency | |
|
950 | # within the remote manifest. | |
|
951 | invalidconflicts.add(p) | |
|
952 | else: | |
|
953 | # A file is in a directory which aliases a local file. | |
|
954 | # We will need to rename the local file. | |
|
955 | localconflicts.add(p) | |
|
956 | if p in actions and actions[p][0] in ('c', 'dc', 'm', 'cm'): | |
|
957 | # The file is in a directory which aliases a remote file. | |
|
958 | # This is an internal inconsistency within the remote | |
|
959 | # manifest. | |
|
960 | invalidconflicts.add(p) | |
|
961 | ||
|
937 | 962 | # Rename all local conflicting files that have not been deleted. |
|
938 | 963 | for p in localconflicts: |
|
939 | 964 | if p not in deletedfiles: |
@@ -766,6 +766,7 b' class ui(object):' | |||
|
766 | 766 | |
|
767 | 767 | The return value can either be |
|
768 | 768 | - False if HGPLAIN is not set, or feature is in HGPLAINEXCEPT |
|
769 | - False if feature is disabled by default and not included in HGPLAIN | |
|
769 | 770 | - True otherwise |
|
770 | 771 | ''' |
|
771 | 772 | if ('HGPLAIN' not in encoding.environ and |
@@ -773,6 +774,9 b' class ui(object):' | |||
|
773 | 774 | return False |
|
774 | 775 | exceptions = encoding.environ.get('HGPLAINEXCEPT', |
|
775 | 776 | '').strip().split(',') |
|
777 | # TODO: add support for HGPLAIN=+feature,-feature syntax | |
|
778 | if '+strictflags' not in encoding.environ.get('HGPLAIN', '').split(','): | |
|
779 | exceptions.append('strictflags') | |
|
776 | 780 | if feature and exceptions: |
|
777 | 781 | return feature not in exceptions |
|
778 | 782 | return True |
@@ -58,7 +58,7 b' amend with dirty subrepo' | |||
|
58 | 58 | |
|
59 | 59 | $ echo a >> s/a |
|
60 | 60 | $ hg add -R s |
|
61 | adding s/a | |
|
61 | adding s/a (glob) | |
|
62 | 62 | $ hg amend |
|
63 | 63 | abort: uncommitted changes in subrepository "s" |
|
64 | 64 | (use --subrepos for recursive commit) |
@@ -9,7 +9,7 b' on commit:' | |||
|
9 | 9 | $ hg init sub/.hg |
|
10 | 10 | $ echo 'sub/.hg = sub/.hg' >> .hgsub |
|
11 | 11 | $ hg ci -qAm 'add subrepo "sub/.hg"' |
|
12 | abort: path 'sub/.hg' is inside nested repo 'sub' | |
|
12 | abort: path 'sub/.hg' is inside nested repo 'sub' (glob) | |
|
13 | 13 | [255] |
|
14 | 14 | |
|
15 | 15 | prepare tampered repo (including the commit above): |
@@ -33,7 +33,7 b' prepare tampered repo (including the com' | |||
|
33 | 33 | on clone (and update): |
|
34 | 34 | |
|
35 | 35 | $ hg clone -q hgname hgname2 |
|
36 | abort: path 'sub/.hg' is inside nested repo 'sub' | |
|
36 | abort: path 'sub/.hg' is inside nested repo 'sub' (glob) | |
|
37 | 37 | [255] |
|
38 | 38 | |
|
39 | 39 | Test direct symlink traversal |
@@ -137,6 +137,20 b' typical client does not want echo-back m' | |||
|
137 | 137 | summary: 1 |
|
138 | 138 | |
|
139 | 139 | |
|
140 | check strict parsing of early options: | |
|
141 | ||
|
142 | >>> import os | |
|
143 | >>> from hgclient import check, readchannel, runcommand | |
|
144 | >>> os.environ['HGPLAIN'] = '+strictflags' | |
|
145 | >>> @check | |
|
146 | ... def cwd(server): | |
|
147 | ... readchannel(server) | |
|
148 | ... runcommand(server, ['log', '-b', '--config=alias.log=!echo pwned', | |
|
149 | ... 'default']) | |
|
150 | *** runcommand log -b --config=alias.log=!echo pwned default | |
|
151 | abort: unknown revision '--config=alias.log=!echo pwned'! | |
|
152 | [255] | |
|
153 | ||
|
140 | 154 | check that "histedit --commands=-" can read rules from the input channel: |
|
141 | 155 | |
|
142 | 156 | >>> import cStringIO |
@@ -113,6 +113,51 b' Shell aliases bypass any command parsing' | |||
|
113 | 113 | $ hg log -b '--config=alias.log=!echo howdy' |
|
114 | 114 | howdy |
|
115 | 115 | |
|
116 | Early options must come first if HGPLAIN=+strictflags is specified: | |
|
117 | (BUG: chg cherry-picks early options to pass them as a server command) | |
|
118 | ||
|
119 | #if no-chg | |
|
120 | $ HGPLAIN=+strictflags hg log -b --config='hooks.pre-log=false' default | |
|
121 | abort: unknown revision '--config=hooks.pre-log=false'! | |
|
122 | [255] | |
|
123 | $ HGPLAIN=+strictflags hg log -b -R. default | |
|
124 | abort: unknown revision '-R.'! | |
|
125 | [255] | |
|
126 | $ HGPLAIN=+strictflags hg log -b --cwd=. default | |
|
127 | abort: unknown revision '--cwd=.'! | |
|
128 | [255] | |
|
129 | #endif | |
|
130 | $ HGPLAIN=+strictflags hg log -b --debugger default | |
|
131 | abort: unknown revision '--debugger'! | |
|
132 | [255] | |
|
133 | $ HGPLAIN=+strictflags hg log -b --config='alias.log=!echo pwned' default | |
|
134 | abort: unknown revision '--config=alias.log=!echo pwned'! | |
|
135 | [255] | |
|
136 | ||
|
137 | $ HGPLAIN=+strictflags hg log --config='hooks.pre-log=false' -b default | |
|
138 | abort: option --config may not be abbreviated! | |
|
139 | [255] | |
|
140 | $ HGPLAIN=+strictflags hg log -q --cwd=.. -b default | |
|
141 | abort: option --cwd may not be abbreviated! | |
|
142 | [255] | |
|
143 | $ HGPLAIN=+strictflags hg log -q -R . -b default | |
|
144 | abort: option -R has to be separated from other options (e.g. not -qR) and --repository may only be abbreviated as --repo! | |
|
145 | [255] | |
|
146 | ||
|
147 | $ HGPLAIN=+strictflags hg --config='hooks.pre-log=false' log -b default | |
|
148 | abort: pre-log hook exited with status 1 | |
|
149 | [255] | |
|
150 | $ HGPLAIN=+strictflags hg --cwd .. -q -Ra log -b default | |
|
151 | 0:cb9a9f314b8b | |
|
152 | ||
|
153 | For compatibility reasons, HGPLAIN=+strictflags is not enabled by plain HGPLAIN: | |
|
154 | ||
|
155 | $ HGPLAIN= hg log --config='hooks.pre-log=false' -b default | |
|
156 | abort: pre-log hook exited with status 1 | |
|
157 | [255] | |
|
158 | $ HGPLAINEXCEPT= hg log --cwd .. -q -Ra -b default | |
|
159 | 0:cb9a9f314b8b | |
|
160 | ||
|
116 | 161 | [defaults] |
|
117 | 162 | |
|
118 | 163 | $ hg cat a |
@@ -48,6 +48,7 b" testmod('mercurial.context')" | |||
|
48 | 48 | testmod('mercurial.dagparser', optionflags=doctest.NORMALIZE_WHITESPACE) |
|
49 | 49 | testmod('mercurial.dispatch') |
|
50 | 50 | testmod('mercurial.encoding') |
|
51 | testmod('mercurial.fancyopts') | |
|
51 | 52 | testmod('mercurial.formatter') |
|
52 | 53 | testmod('mercurial.hg') |
|
53 | 54 | testmod('mercurial.hgweb.hgwebdir_mod') |
@@ -972,6 +972,7 b' test import with similarity and git and ' | |||
|
972 | 972 | adding b |
|
973 | 973 | recording removal of a as rename to b (88% similar) |
|
974 | 974 | applied to working directory |
|
975 | $ echo 'mod b' > b | |
|
975 | 976 | $ hg st -C |
|
976 | 977 | A b |
|
977 | 978 | a |
@@ -979,6 +980,8 b' test import with similarity and git and ' | |||
|
979 | 980 | $ hg revert -a |
|
980 | 981 | undeleting a |
|
981 | 982 | forgetting b |
|
983 | $ cat b | |
|
984 | mod b | |
|
982 | 985 | $ rm b |
|
983 | 986 | $ hg import --no-commit -v -s 100 ../rename.diff -p2 |
|
984 | 987 | applying ../rename.diff |
@@ -390,8 +390,12 b' Test update with subrepos.' | |||
|
390 | 390 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
391 | 391 | $ hg status -S |
|
392 | 392 | |
|
393 | Forget doesn't change the content of the file | |
|
394 | $ echo 'pre-forget content' > subrepo/large.txt | |
|
393 | 395 | $ hg forget -v subrepo/large.txt |
|
394 | 396 | removing subrepo/large.txt (glob) |
|
397 | $ cat subrepo/large.txt | |
|
398 | pre-forget content | |
|
395 | 399 | |
|
396 | 400 | Test reverting a forgotten file |
|
397 | 401 | $ hg revert -R subrepo subrepo/large.txt |
@@ -1060,7 +1064,9 b' largefiles (issue4547)' | |||
|
1060 | 1064 | > largefiles= |
|
1061 | 1065 | > EOF |
|
1062 | 1066 | $ echo large > subrepo-root/large |
|
1063 | $ hg -R subrepo-root add --large subrepo-root/large | |
|
1067 | $ mkdir -p subrepo-root/dir/subdir | |
|
1068 | $ echo large2 > subrepo-root/dir/subdir/large.bin | |
|
1069 | $ hg -R subrepo-root add --large subrepo-root/large subrepo-root/dir/subdir/large.bin | |
|
1064 | 1070 | $ hg clone -q no-largefiles subrepo-root/no-largefiles |
|
1065 | 1071 | $ cat > subrepo-root/.hgsub <<EOF |
|
1066 | 1072 | > no-largefiles = no-largefiles |
@@ -1069,6 +1075,7 b' largefiles (issue4547)' | |||
|
1069 | 1075 | $ hg -R subrepo-root commit -m '#0' |
|
1070 | 1076 | Invoking status precommit hook |
|
1071 | 1077 | A .hgsub |
|
1078 | A dir/subdir/large.bin | |
|
1072 | 1079 | A large |
|
1073 | 1080 | ? .hgsubstate |
|
1074 | 1081 | $ echo dirty >> subrepo-root/large |
@@ -1085,8 +1092,155 b' largefiles (issue4547)' | |||
|
1085 | 1092 | reverting subrepo no-largefiles |
|
1086 | 1093 | reverting subrepo-root/no-largefiles/normal1 (glob) |
|
1087 | 1094 | |
|
1088 | $ cd .. | |
|
1095 | Move (and then undo) a directory move with only largefiles. | |
|
1096 | ||
|
1097 | $ listtree() { | |
|
1098 | > find $@ \( -type d -printf "%p/\n" -o -type f -printf "%p\n" \) \ | |
|
1099 | > -a -name .hg -prune | sort | |
|
1100 | > } | |
|
1101 | ||
|
1102 | $ cd subrepo-root | |
|
1103 | $ listtree .hglf dir* large* | |
|
1104 | .hglf/ | |
|
1105 | .hglf/dir/ | |
|
1106 | .hglf/dir/subdir/ | |
|
1107 | .hglf/dir/subdir/large.bin | |
|
1108 | .hglf/large | |
|
1109 | dir/ | |
|
1110 | dir/subdir/ | |
|
1111 | dir/subdir/large.bin | |
|
1112 | large | |
|
1113 | large.orig | |
|
1114 | ||
|
1115 | $ hg mv dir/subdir dir/subdir2 | |
|
1116 | moving .hglf/dir/subdir/large.bin to .hglf/dir/subdir2/large.bin (glob) | |
|
1117 | ||
|
1118 | $ listtree .hglf dir* large* | |
|
1119 | .hglf/ | |
|
1120 | .hglf/dir/ | |
|
1121 | .hglf/dir/subdir2/ | |
|
1122 | .hglf/dir/subdir2/large.bin | |
|
1123 | .hglf/large | |
|
1124 | dir/ | |
|
1125 | dir/subdir2/ | |
|
1126 | dir/subdir2/large.bin | |
|
1127 | large | |
|
1128 | large.orig | |
|
1129 | $ hg status -C | |
|
1130 | A dir/subdir2/large.bin | |
|
1131 | dir/subdir/large.bin | |
|
1132 | R dir/subdir/large.bin | |
|
1133 | ? large.orig | |
|
1134 | ||
|
1135 | $ echo 'modified' > dir/subdir2/large.bin | |
|
1136 | $ hg status -C | |
|
1137 | A dir/subdir2/large.bin | |
|
1138 | dir/subdir/large.bin | |
|
1139 | R dir/subdir/large.bin | |
|
1140 | ? large.orig | |
|
1141 | ||
|
1142 | $ hg revert --all | |
|
1143 | undeleting .hglf/dir/subdir/large.bin (glob) | |
|
1144 | forgetting .hglf/dir/subdir2/large.bin (glob) | |
|
1145 | reverting subrepo no-largefiles | |
|
1146 | ||
|
1147 | $ hg status -C | |
|
1148 | ? dir/subdir2/large.bin | |
|
1149 | ? large.orig | |
|
1150 | ||
|
1151 | The content of the forgotten file shouldn't be clobbered | |
|
1152 | ||
|
1153 | $ cat dir/subdir2/large.bin | |
|
1154 | modified | |
|
1155 | ||
|
1156 | The standin for subdir2 should be deleted, not just dropped | |
|
1089 | 1157 | |
|
1158 | $ listtree .hglf dir* large* | |
|
1159 | .hglf/ | |
|
1160 | .hglf/dir/ | |
|
1161 | .hglf/dir/subdir/ | |
|
1162 | .hglf/dir/subdir/large.bin | |
|
1163 | .hglf/large | |
|
1164 | dir/ | |
|
1165 | dir/subdir/ | |
|
1166 | dir/subdir/large.bin | |
|
1167 | dir/subdir2/ | |
|
1168 | dir/subdir2/large.bin | |
|
1169 | large | |
|
1170 | large.orig | |
|
1171 | ||
|
1172 | $ rm -r dir/subdir2 | |
|
1173 | ||
|
1174 | 'subdir' should not be in the destination. It would be if the subdir2 directory | |
|
1175 | existed under .hglf/. | |
|
1176 | $ hg mv dir/subdir dir/subdir2 | |
|
1177 | moving .hglf/dir/subdir/large.bin to .hglf/dir/subdir2/large.bin (glob) | |
|
1178 | ||
|
1179 | $ hg status -C | |
|
1180 | A dir/subdir2/large.bin | |
|
1181 | dir/subdir/large.bin | |
|
1182 | R dir/subdir/large.bin | |
|
1183 | ? large.orig | |
|
1184 | ||
|
1185 | $ listtree .hglf dir* large* | |
|
1186 | .hglf/ | |
|
1187 | .hglf/dir/ | |
|
1188 | .hglf/dir/subdir2/ | |
|
1189 | .hglf/dir/subdir2/large.bin | |
|
1190 | .hglf/large | |
|
1191 | dir/ | |
|
1192 | dir/subdir2/ | |
|
1193 | dir/subdir2/large.bin | |
|
1194 | large | |
|
1195 | large.orig | |
|
1196 | ||
|
1197 | Start from scratch, and rename something other than the final path component. | |
|
1198 | ||
|
1199 | $ hg up -qC . | |
|
1200 | $ hg --config extensions.purge= purge | |
|
1201 | ||
|
1202 | $ hg mv dir/subdir dir2/subdir | |
|
1203 | moving .hglf/dir/subdir/large.bin to .hglf/dir2/subdir/large.bin (glob) | |
|
1204 | ||
|
1205 | $ hg status -C | |
|
1206 | A dir2/subdir/large.bin | |
|
1207 | dir/subdir/large.bin | |
|
1208 | R dir/subdir/large.bin | |
|
1209 | ||
|
1210 | $ listtree .hglf dir* large* | |
|
1211 | .hglf/ | |
|
1212 | .hglf/dir2/ | |
|
1213 | .hglf/dir2/subdir/ | |
|
1214 | .hglf/dir2/subdir/large.bin | |
|
1215 | .hglf/large | |
|
1216 | dir2/ | |
|
1217 | dir2/subdir/ | |
|
1218 | dir2/subdir/large.bin | |
|
1219 | large | |
|
1220 | ||
|
1221 | $ hg revert --all | |
|
1222 | undeleting .hglf/dir/subdir/large.bin (glob) | |
|
1223 | forgetting .hglf/dir2/subdir/large.bin (glob) | |
|
1224 | reverting subrepo no-largefiles | |
|
1225 | ||
|
1226 | $ hg status -C | |
|
1227 | ? dir2/subdir/large.bin | |
|
1228 | ||
|
1229 | $ listtree .hglf dir* large* | |
|
1230 | .hglf/ | |
|
1231 | .hglf/dir/ | |
|
1232 | .hglf/dir/subdir/ | |
|
1233 | .hglf/dir/subdir/large.bin | |
|
1234 | .hglf/large | |
|
1235 | dir/ | |
|
1236 | dir/subdir/ | |
|
1237 | dir/subdir/large.bin | |
|
1238 | dir2/ | |
|
1239 | dir2/subdir/ | |
|
1240 | dir2/subdir/large.bin | |
|
1241 | large | |
|
1242 | ||
|
1243 | $ cd ../.. | |
|
1090 | 1244 | |
|
1091 | 1245 | Test "pull --rebase" when rebase is enabled before largefiles (issue3861) |
|
1092 | 1246 | ========================================================================= |
@@ -1071,6 +1071,18 b' Prepare a repo with subrepo' | |||
|
1071 | 1071 | "path": "sub/repo/foo" |
|
1072 | 1072 | } |
|
1073 | 1073 | ] |
|
1074 | ||
|
1075 | non-exact match: | |
|
1076 | ||
|
1077 | $ hg cat -T '{path}\n' 'glob:**' | |
|
1078 | .hgsub | |
|
1079 | .hgsubstate | |
|
1080 | sub/repo/foo (glob) | |
|
1081 | $ hg cat -T '{path}\n' 're:^sub' | |
|
1082 | sub/repo/foo (glob) | |
|
1083 | ||
|
1084 | missing subrepos in working directory: | |
|
1085 | ||
|
1074 | 1086 | $ mkdir -p tmp/sub/repo |
|
1075 | 1087 | $ hg cat -r 0 --output tmp/%p_p sub/repo/foo |
|
1076 | 1088 | $ cat tmp/sub/repo/foo_p |
General Comments 0
You need to be logged in to leave comments.
Login now