##// END OF EJS Templates
merge with stable
Kevin Bullock -
r35187:aef2b98d merge default
parent child Browse files
Show More
@@ -155,3 +155,4 b' 2f427b57bf9019c6dc3750baa539dc22c1be50f6'
155 1e2454b60e5936f5e77498cab2648db469504487 0 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
@@ -168,3 +168,4 b' 2f427b57bf9019c6dc3750baa539dc22c1be50f6'
168 1e2454b60e5936f5e77498cab2648db469504487 4.4-rc
168 1e2454b60e5936f5e77498cab2648db469504487 4.4-rc
169 0ccb43d4cf01d013ae05917ec4f305509f851b2d 4.4
169 0ccb43d4cf01d013ae05917ec4f305509f851b2d 4.4
170 cabc840ffdee8a72f3689fb77dd74d04fdc2bc04 4.4.1
170 cabc840ffdee8a72f3689fb77dd74d04fdc2bc04 4.4.1
171 a92b9f8e11ba330614cdfd6af0e03b15c1ff3797 4.4.2
@@ -455,6 +455,7 b' def updatelfiles(ui, repo, filelist=None'
455 lfiles = [f for f in lfiles if f in filelist]
455 lfiles = [f for f in lfiles if f in filelist]
456
456
457 update = {}
457 update = {}
458 dropped = set()
458 updated, removed = 0, 0
459 updated, removed = 0, 0
459 wvfs = repo.wvfs
460 wvfs = repo.wvfs
460 wctx = repo[None]
461 wctx = repo[None]
@@ -476,7 +477,11 b' def updatelfiles(ui, repo, filelist=None'
476 expecthash = lfutil.readasstandin(wctx[relstandin])
477 expecthash = lfutil.readasstandin(wctx[relstandin])
477 if expecthash != '':
478 if expecthash != '':
478 if lfile not in wctx: # not switched to normal file
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 # use normallookup() to allocate an entry in largefiles
485 # use normallookup() to allocate an entry in largefiles
481 # dirstate to prevent lfilesrepo.status() from reporting
486 # dirstate to prevent lfilesrepo.status() from reporting
482 # missing files as removed.
487 # missing files as removed.
@@ -496,6 +501,15 b' def updatelfiles(ui, repo, filelist=None'
496 lfdirstate.write()
501 lfdirstate.write()
497
502
498 if lfiles:
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 statuswriter(_('getting changed largefiles\n'))
513 statuswriter(_('getting changed largefiles\n'))
500 cachelfiles(ui, repo, None, lfiles)
514 cachelfiles(ui, repo, None, lfiles)
501
515
@@ -220,8 +220,17 b' def _loadnewui(srcui, args):'
220 newui._csystem = srcui._csystem
220 newui._csystem = srcui._csystem
221
221
222 # command line args
222 # command line args
223 args = args[:]
223 options = {}
224 dispatch._parseconfig(newui, dispatch._earlygetopt(['--config'], args))
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 # stolen from tortoisehg.util.copydynamicconfig()
235 # stolen from tortoisehg.util.copydynamicconfig()
227 for section, name, value in srcui.walkconfig():
236 for section, name, value in srcui.walkconfig():
@@ -232,10 +241,9 b' def _loadnewui(srcui, args):'
232 newui.setconfig(section, name, value, source)
241 newui.setconfig(section, name, value, source)
233
242
234 # load wd and repo config, copied from dispatch.py
243 # load wd and repo config, copied from dispatch.py
235 cwds = dispatch._earlygetopt(['--cwd'], args)
244 cwd = options['cwd']
236 cwd = cwds and os.path.realpath(cwds[-1]) or None
245 cwd = cwd and os.path.realpath(cwd) or None
237 rpath = dispatch._earlygetopt(["-R", "--repository", "--repo"], args)
246 rpath = options['repository']
238 rpath = rpath and rpath[-1] or ''
239 path, newlui = dispatch._getlocal(newui, rpath, wd=cwd)
247 path, newlui = dispatch._getlocal(newui, rpath, wd=cwd)
240
248
241 return (newui, newlui)
249 return (newui, newlui)
@@ -150,6 +150,8 b' def dispatch(req):'
150 try:
150 try:
151 if not req.ui:
151 if not req.ui:
152 req.ui = uimod.ui.load()
152 req.ui = uimod.ui.load()
153 if req.ui.plain('strictflags'):
154 req.earlyoptions.update(_earlyparseopts(req.args))
153 if _earlyreqoptbool(req, 'traceback', ['--traceback']):
155 if _earlyreqoptbool(req, 'traceback', ['--traceback']):
154 req.ui.setconfig('ui', 'traceback', 'on', '--traceback')
156 req.ui.setconfig('ui', 'traceback', 'on', '--traceback')
155
157
@@ -644,6 +646,12 b' def _parseconfig(ui, config):'
644
646
645 return configs
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 def _earlygetopt(aliases, args, strip=True):
655 def _earlygetopt(aliases, args, strip=True):
648 """Return list of values for an option (or aliases).
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 def _earlyreqopt(req, name, aliases):
741 def _earlyreqopt(req, name, aliases):
734 """Peek a list option without using a full options table"""
742 """Peek a list option without using a full options table"""
743 if req.ui.plain('strictflags'):
744 return req.earlyoptions[name]
735 values = _earlygetopt(aliases, req.args, strip=False)
745 values = _earlygetopt(aliases, req.args, strip=False)
736 req.earlyoptions[name] = values
746 req.earlyoptions[name] = values
737 return values
747 return values
738
748
739 def _earlyreqoptstr(req, name, aliases):
749 def _earlyreqoptstr(req, name, aliases):
740 """Peek a string option without using a full options table"""
750 """Peek a string option without using a full options table"""
751 if req.ui.plain('strictflags'):
752 return req.earlyoptions[name]
741 value = (_earlygetopt(aliases, req.args, strip=False) or [''])[-1]
753 value = (_earlygetopt(aliases, req.args, strip=False) or [''])[-1]
742 req.earlyoptions[name] = value
754 req.earlyoptions[name] = value
743 return value
755 return value
@@ -745,13 +757,15 b' def _earlyreqoptstr(req, name, aliases):'
745 def _earlyreqoptbool(req, name, aliases):
757 def _earlyreqoptbool(req, name, aliases):
746 """Peek a boolean option without using a full options table
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 >>> _earlyreqoptbool(req, b'debugger', [b'--debugger'])
761 >>> _earlyreqoptbool(req, b'debugger', [b'--debugger'])
750 True
762 True
751
763
752 >>> req = request([b'x', b'--', b'--debugger'])
764 >>> req = request([b'x', b'--', b'--debugger'], uimod.ui())
753 >>> _earlyreqoptbool(req, b'debugger', [b'--debugger'])
765 >>> _earlyreqoptbool(req, b'debugger', [b'--debugger'])
754 """
766 """
767 if req.ui.plain('strictflags'):
768 return req.earlyoptions[name]
755 try:
769 try:
756 argcount = req.args.index("--")
770 argcount = req.args.index("--")
757 except ValueError:
771 except ValueError:
@@ -7,6 +7,8 b''
7
7
8 from __future__ import absolute_import
8 from __future__ import absolute_import
9
9
10 import functools
11
10 from .i18n import _
12 from .i18n import _
11 from . import (
13 from . import (
12 error,
14 error,
@@ -24,6 +26,179 b' nevernegate = {'
24 'version',
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 def gnugetopt(args, options, longoptions):
202 def gnugetopt(args, options, longoptions):
28 """Parse options mostly like getopt.gnu_getopt.
203 """Parse options mostly like getopt.gnu_getopt.
29
204
@@ -51,7 +226,7 b' def gnugetopt(args, options, longoptions'
51 return opts, args
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 read args, parse options, and store options in state
231 read args, parse options, and store options in state
57
232
@@ -124,7 +299,9 b' def fancyopts(args, options, state, gnu='
124 namelist.append(oname)
299 namelist.append(oname)
125
300
126 # parse arguments
301 # parse arguments
127 if gnu:
302 if early:
303 parse = functools.partial(earlygetopt, gnu=gnu)
304 elif gnu:
128 parse = gnugetopt
305 parse = gnugetopt
129 else:
306 else:
130 parse = pycompat.getoptb
307 parse = pycompat.getoptb
@@ -56,9 +56,17 b' HGPLAIN'
56 localization. This can be useful when scripting against Mercurial
56 localization. This can be useful when scripting against Mercurial
57 in the face of existing user configuration.
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 Equivalent options set via command line flags or environment
65 Equivalent options set via command line flags or environment
60 variables are not overridden.
66 variables are not overridden.
61
67
68 See :hg:`help scripting` for details.
69
62 HGPLAINEXCEPT
70 HGPLAINEXCEPT
63 This is a comma-separated list of features to preserve when
71 This is a comma-separated list of features to preserve when
64 HGPLAIN is enabled. Currently the following values are supported:
72 HGPLAIN is enabled. Currently the following values are supported:
@@ -74,6 +74,32 b' HGRCPATH'
74 like the username and extensions that may be required to interface
74 like the username and extensions that may be required to interface
75 with a repository.
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 Consuming Command Output
103 Consuming Command Output
78 ========================
104 ========================
79
105
@@ -90,7 +90,7 b' Interaction with Mercurial Commands'
90 :archive: archive does not recurse in subrepositories unless
90 :archive: archive does not recurse in subrepositories unless
91 -S/--subrepos is specified.
91 -S/--subrepos is specified.
92
92
93 :cat: cat currently only handles exact file matches in subrepos.
93 :cat: Git subrepositories only support exact file matches.
94 Subversion subrepositories are currently ignored.
94 Subversion subrepositories are currently ignored.
95
95
96 :commit: commit creates a consistent snapshot of the state of the
96 :commit: commit creates a consistent snapshot of the state of the
@@ -653,7 +653,7 b' def _checkunknownfile(repo, wctx, mctx, '
653 and repo.dirstate.normalize(f) not in repo.dirstate
653 and repo.dirstate.normalize(f) not in repo.dirstate
654 and mctx[f2].cmp(wctx[f]))
654 and mctx[f2].cmp(wctx[f]))
655
655
656 def _checkunknowndirs(repo, f):
656 class _unknowndirschecker(object):
657 """
657 """
658 Look for any unknown files or directories that may have a path conflict
658 Look for any unknown files or directories that may have a path conflict
659 with a file. If any path prefix of the file exists as a file or link,
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 Returns the shortest path at which a conflict occurs, or None if there is
663 Returns the shortest path at which a conflict occurs, or None if there is
664 no conflict.
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.
672 # A set of paths that are known to be absent. This prevents repeated
668 for p in reversed(list(util.finddirs(f))):
673 # checking of subdirectories that are known not to exist. It will be
669 if (repo.wvfs.audit.check(p)
674 # updated with any new dirs that are checked and found to be absent.
670 and repo.wvfs.isfileorlink(p)
675 self._missingdircache = set()
671 and repo.dirstate.normalize(p) not in repo.dirstate):
672 return p
673
676
674 # Check if the file conflicts with a directory containing unknown files.
677 def __call__(self, repo, f):
675 if repo.wvfs.audit.check(f) and repo.wvfs.isdir(f):
678 # Check for path prefixes that exist as unknown files.
676 # Does the directory contain any files that are not in the dirstate?
679 for p in reversed(list(util.finddirs(f))):
677 for p, dirs, files in repo.wvfs.walk(f):
680 if p in self._missingdircache:
678 for fn in files:
681 return
679 relf = repo.dirstate.normalize(repo.wvfs.reljoin(p, fn))
682 if p in self._unknowndircache:
680 if relf not in repo.dirstate:
683 continue
681 return f
684 if repo.wvfs.audit.check(p):
682 return None
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 def _checkunknownfiles(repo, wctx, mctx, force, actions, mergeforce):
703 def _checkunknownfiles(repo, wctx, mctx, force, actions, mergeforce):
685 """
704 """
@@ -701,12 +720,13 b' def _checkunknownfiles(repo, wctx, mctx,'
701 elif config == 'warn':
720 elif config == 'warn':
702 warnconflicts.update(conflicts)
721 warnconflicts.update(conflicts)
703
722
723 checkunknowndirs = _unknowndirschecker()
704 for f, (m, args, msg) in actions.iteritems():
724 for f, (m, args, msg) in actions.iteritems():
705 if m in ('c', 'dc'):
725 if m in ('c', 'dc'):
706 if _checkunknownfile(repo, wctx, mctx, f):
726 if _checkunknownfile(repo, wctx, mctx, f):
707 fileconflicts.add(f)
727 fileconflicts.add(f)
708 elif pathconfig and f not in wctx:
728 elif pathconfig and f not in wctx:
709 path = _checkunknowndirs(repo, f)
729 path = checkunknowndirs(repo, f)
710 if path is not None:
730 if path is not None:
711 pathconflicts.add(path)
731 pathconflicts.add(path)
712 elif m == 'dg':
732 elif m == 'dg':
@@ -895,34 +915,21 b' def checkpathconflicts(repo, wctx, mctx,'
895 # can't be updated to cleanly.
915 # can't be updated to cleanly.
896 invalidconflicts = set()
916 invalidconflicts = set()
897
917
918 # The set of directories that contain files that are being created.
919 createdfiledirs = set()
920
898 # The set of files deleted by all the actions.
921 # The set of files deleted by all the actions.
899 deletedfiles = set()
922 deletedfiles = set()
900
923
901 for f, (m, args, msg) in actions.items():
924 for f, (m, args, msg) in actions.items():
902 if m in ('c', 'dc', 'm', 'cm'):
925 if m in ('c', 'dc', 'm', 'cm'):
903 # This action may create a new local file.
926 # This action may create a new local file.
927 createdfiledirs.update(util.finddirs(f))
904 if mf.hasdir(f):
928 if mf.hasdir(f):
905 # The file aliases a local directory. This might be ok if all
929 # The file aliases a local directory. This might be ok if all
906 # the files in the local directory are being deleted. This
930 # the files in the local directory are being deleted. This
907 # will be checked once we know what all the deleted files are.
931 # will be checked once we know what all the deleted files are.
908 remoteconflicts.add(f)
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 # Track the names of all deleted files.
933 # Track the names of all deleted files.
927 if m == 'r':
934 if m == 'r':
928 deletedfiles.add(f)
935 deletedfiles.add(f)
@@ -934,6 +941,24 b' def checkpathconflicts(repo, wctx, mctx,'
934 f2, flags = args
941 f2, flags = args
935 deletedfiles.add(f2)
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 # Rename all local conflicting files that have not been deleted.
962 # Rename all local conflicting files that have not been deleted.
938 for p in localconflicts:
963 for p in localconflicts:
939 if p not in deletedfiles:
964 if p not in deletedfiles:
@@ -766,6 +766,7 b' class ui(object):'
766
766
767 The return value can either be
767 The return value can either be
768 - False if HGPLAIN is not set, or feature is in HGPLAINEXCEPT
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 - True otherwise
770 - True otherwise
770 '''
771 '''
771 if ('HGPLAIN' not in encoding.environ and
772 if ('HGPLAIN' not in encoding.environ and
@@ -773,6 +774,9 b' class ui(object):'
773 return False
774 return False
774 exceptions = encoding.environ.get('HGPLAINEXCEPT',
775 exceptions = encoding.environ.get('HGPLAINEXCEPT',
775 '').strip().split(',')
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 if feature and exceptions:
780 if feature and exceptions:
777 return feature not in exceptions
781 return feature not in exceptions
778 return True
782 return True
@@ -58,7 +58,7 b' amend with dirty subrepo'
58
58
59 $ echo a >> s/a
59 $ echo a >> s/a
60 $ hg add -R s
60 $ hg add -R s
61 adding s/a
61 adding s/a (glob)
62 $ hg amend
62 $ hg amend
63 abort: uncommitted changes in subrepository "s"
63 abort: uncommitted changes in subrepository "s"
64 (use --subrepos for recursive commit)
64 (use --subrepos for recursive commit)
@@ -9,7 +9,7 b' on commit:'
9 $ hg init sub/.hg
9 $ hg init sub/.hg
10 $ echo 'sub/.hg = sub/.hg' >> .hgsub
10 $ echo 'sub/.hg = sub/.hg' >> .hgsub
11 $ hg ci -qAm 'add subrepo "sub/.hg"'
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 [255]
13 [255]
14
14
15 prepare tampered repo (including the commit above):
15 prepare tampered repo (including the commit above):
@@ -33,7 +33,7 b' prepare tampered repo (including the com'
33 on clone (and update):
33 on clone (and update):
34
34
35 $ hg clone -q hgname hgname2
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 [255]
37 [255]
38
38
39 Test direct symlink traversal
39 Test direct symlink traversal
@@ -137,6 +137,20 b' typical client does not want echo-back m'
137 summary: 1
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 check that "histedit --commands=-" can read rules from the input channel:
154 check that "histedit --commands=-" can read rules from the input channel:
141
155
142 >>> import cStringIO
156 >>> import cStringIO
@@ -113,6 +113,51 b' Shell aliases bypass any command parsing'
113 $ hg log -b '--config=alias.log=!echo howdy'
113 $ hg log -b '--config=alias.log=!echo howdy'
114 howdy
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 [defaults]
161 [defaults]
117
162
118 $ hg cat a
163 $ hg cat a
@@ -48,6 +48,7 b" testmod('mercurial.context')"
48 testmod('mercurial.dagparser', optionflags=doctest.NORMALIZE_WHITESPACE)
48 testmod('mercurial.dagparser', optionflags=doctest.NORMALIZE_WHITESPACE)
49 testmod('mercurial.dispatch')
49 testmod('mercurial.dispatch')
50 testmod('mercurial.encoding')
50 testmod('mercurial.encoding')
51 testmod('mercurial.fancyopts')
51 testmod('mercurial.formatter')
52 testmod('mercurial.formatter')
52 testmod('mercurial.hg')
53 testmod('mercurial.hg')
53 testmod('mercurial.hgweb.hgwebdir_mod')
54 testmod('mercurial.hgweb.hgwebdir_mod')
@@ -972,6 +972,7 b' test import with similarity and git and '
972 adding b
972 adding b
973 recording removal of a as rename to b (88% similar)
973 recording removal of a as rename to b (88% similar)
974 applied to working directory
974 applied to working directory
975 $ echo 'mod b' > b
975 $ hg st -C
976 $ hg st -C
976 A b
977 A b
977 a
978 a
@@ -979,6 +980,8 b' test import with similarity and git and '
979 $ hg revert -a
980 $ hg revert -a
980 undeleting a
981 undeleting a
981 forgetting b
982 forgetting b
983 $ cat b
984 mod b
982 $ rm b
985 $ rm b
983 $ hg import --no-commit -v -s 100 ../rename.diff -p2
986 $ hg import --no-commit -v -s 100 ../rename.diff -p2
984 applying ../rename.diff
987 applying ../rename.diff
@@ -390,8 +390,12 b' Test update with subrepos.'
390 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
390 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
391 $ hg status -S
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 $ hg forget -v subrepo/large.txt
395 $ hg forget -v subrepo/large.txt
394 removing subrepo/large.txt (glob)
396 removing subrepo/large.txt (glob)
397 $ cat subrepo/large.txt
398 pre-forget content
395
399
396 Test reverting a forgotten file
400 Test reverting a forgotten file
397 $ hg revert -R subrepo subrepo/large.txt
401 $ hg revert -R subrepo subrepo/large.txt
@@ -1060,7 +1064,9 b' largefiles (issue4547)'
1060 > largefiles=
1064 > largefiles=
1061 > EOF
1065 > EOF
1062 $ echo large > subrepo-root/large
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 $ hg clone -q no-largefiles subrepo-root/no-largefiles
1070 $ hg clone -q no-largefiles subrepo-root/no-largefiles
1065 $ cat > subrepo-root/.hgsub <<EOF
1071 $ cat > subrepo-root/.hgsub <<EOF
1066 > no-largefiles = no-largefiles
1072 > no-largefiles = no-largefiles
@@ -1069,6 +1075,7 b' largefiles (issue4547)'
1069 $ hg -R subrepo-root commit -m '#0'
1075 $ hg -R subrepo-root commit -m '#0'
1070 Invoking status precommit hook
1076 Invoking status precommit hook
1071 A .hgsub
1077 A .hgsub
1078 A dir/subdir/large.bin
1072 A large
1079 A large
1073 ? .hgsubstate
1080 ? .hgsubstate
1074 $ echo dirty >> subrepo-root/large
1081 $ echo dirty >> subrepo-root/large
@@ -1085,8 +1092,155 b' largefiles (issue4547)'
1085 reverting subrepo no-largefiles
1092 reverting subrepo no-largefiles
1086 reverting subrepo-root/no-largefiles/normal1 (glob)
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 Test "pull --rebase" when rebase is enabled before largefiles (issue3861)
1245 Test "pull --rebase" when rebase is enabled before largefiles (issue3861)
1092 =========================================================================
1246 =========================================================================
@@ -1071,6 +1071,18 b' Prepare a repo with subrepo'
1071 "path": "sub/repo/foo"
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 $ mkdir -p tmp/sub/repo
1086 $ mkdir -p tmp/sub/repo
1075 $ hg cat -r 0 --output tmp/%p_p sub/repo/foo
1087 $ hg cat -r 0 --output tmp/%p_p sub/repo/foo
1076 $ cat tmp/sub/repo/foo_p
1088 $ cat tmp/sub/repo/foo_p
General Comments 0
You need to be logged in to leave comments. Login now