Mercurial > public > mercurial-scm > hg
comparison mercurial/cmdutil.py @ 43077:687b865b95ad
formatting: byteify all mercurial/ and hgext/ string literals
Done with
python3.7 contrib/byteify-strings.py -i $(hg files 'set:mercurial/**.py - mercurial/thirdparty/** + hgext/**.py - hgext/fsmonitor/pywatchman/** - mercurial/__init__.py')
black -l 80 -t py33 -S $(hg files 'set:**.py - mercurial/thirdparty/** - "contrib/python-zstandard/**" - hgext/fsmonitor/pywatchman/**')
# skip-blame mass-reformatting only
Differential Revision: https://phab.mercurial-scm.org/D6972
author | Augie Fackler <augie@google.com> |
---|---|
date | Sun, 06 Oct 2019 09:48:39 -0400 |
parents | 2372284d9457 |
children | eef9a2d67051 |
comparison
equal
deleted
inserted
replaced
43076:2372284d9457 | 43077:687b865b95ad |
---|---|
59 stringio = util.stringio | 59 stringio = util.stringio |
60 | 60 |
61 # templates of common command options | 61 # templates of common command options |
62 | 62 |
63 dryrunopts = [ | 63 dryrunopts = [ |
64 ('n', 'dry-run', None, _('do not perform actions, just print output')), | 64 (b'n', b'dry-run', None, _(b'do not perform actions, just print output')), |
65 ] | 65 ] |
66 | 66 |
67 confirmopts = [ | 67 confirmopts = [ |
68 ('', 'confirm', None, _('ask before applying actions')), | 68 (b'', b'confirm', None, _(b'ask before applying actions')), |
69 ] | 69 ] |
70 | 70 |
71 remoteopts = [ | 71 remoteopts = [ |
72 ('e', 'ssh', '', _('specify ssh command to use'), _('CMD')), | 72 (b'e', b'ssh', b'', _(b'specify ssh command to use'), _(b'CMD')), |
73 ( | 73 ( |
74 '', | 74 b'', |
75 'remotecmd', | 75 b'remotecmd', |
76 '', | 76 b'', |
77 _('specify hg command to run on the remote side'), | 77 _(b'specify hg command to run on the remote side'), |
78 _('CMD'), | 78 _(b'CMD'), |
79 ), | 79 ), |
80 ( | 80 ( |
81 '', | 81 b'', |
82 'insecure', | 82 b'insecure', |
83 None, | 83 None, |
84 _('do not verify server certificate (ignoring web.cacerts config)'), | 84 _(b'do not verify server certificate (ignoring web.cacerts config)'), |
85 ), | 85 ), |
86 ] | 86 ] |
87 | 87 |
88 walkopts = [ | 88 walkopts = [ |
89 ( | 89 ( |
90 'I', | 90 b'I', |
91 'include', | 91 b'include', |
92 [], | 92 [], |
93 _('include names matching the given patterns'), | 93 _(b'include names matching the given patterns'), |
94 _('PATTERN'), | 94 _(b'PATTERN'), |
95 ), | 95 ), |
96 ( | 96 ( |
97 'X', | 97 b'X', |
98 'exclude', | 98 b'exclude', |
99 [], | 99 [], |
100 _('exclude names matching the given patterns'), | 100 _(b'exclude names matching the given patterns'), |
101 _('PATTERN'), | 101 _(b'PATTERN'), |
102 ), | 102 ), |
103 ] | 103 ] |
104 | 104 |
105 commitopts = [ | 105 commitopts = [ |
106 ('m', 'message', '', _('use text as commit message'), _('TEXT')), | 106 (b'm', b'message', b'', _(b'use text as commit message'), _(b'TEXT')), |
107 ('l', 'logfile', '', _('read commit message from file'), _('FILE')), | 107 (b'l', b'logfile', b'', _(b'read commit message from file'), _(b'FILE')), |
108 ] | 108 ] |
109 | 109 |
110 commitopts2 = [ | 110 commitopts2 = [ |
111 ('d', 'date', '', _('record the specified date as commit date'), _('DATE')), | 111 ( |
112 ('u', 'user', '', _('record the specified user as committer'), _('USER')), | 112 b'd', |
113 b'date', | |
114 b'', | |
115 _(b'record the specified date as commit date'), | |
116 _(b'DATE'), | |
117 ), | |
118 ( | |
119 b'u', | |
120 b'user', | |
121 b'', | |
122 _(b'record the specified user as committer'), | |
123 _(b'USER'), | |
124 ), | |
113 ] | 125 ] |
114 | 126 |
115 commitopts3 = [ | 127 commitopts3 = [ |
116 (b'D', b'currentdate', None, _(b'record the current date as commit date')), | 128 (b'D', b'currentdate', None, _(b'record the current date as commit date')), |
117 (b'U', b'currentuser', None, _(b'record the current user as committer')), | 129 (b'U', b'currentuser', None, _(b'record the current user as committer')), |
118 ] | 130 ] |
119 | 131 |
120 formatteropts = [ | 132 formatteropts = [ |
121 ('T', 'template', '', _('display with template'), _('TEMPLATE')), | 133 (b'T', b'template', b'', _(b'display with template'), _(b'TEMPLATE')), |
122 ] | 134 ] |
123 | 135 |
124 templateopts = [ | 136 templateopts = [ |
125 ( | 137 ( |
126 '', | 138 b'', |
127 'style', | 139 b'style', |
128 '', | 140 b'', |
129 _('display using template map file (DEPRECATED)'), | 141 _(b'display using template map file (DEPRECATED)'), |
130 _('STYLE'), | 142 _(b'STYLE'), |
131 ), | 143 ), |
132 ('T', 'template', '', _('display with template'), _('TEMPLATE')), | 144 (b'T', b'template', b'', _(b'display with template'), _(b'TEMPLATE')), |
133 ] | 145 ] |
134 | 146 |
135 logopts = [ | 147 logopts = [ |
136 ('p', 'patch', None, _('show patch')), | 148 (b'p', b'patch', None, _(b'show patch')), |
137 ('g', 'git', None, _('use git extended diff format')), | 149 (b'g', b'git', None, _(b'use git extended diff format')), |
138 ('l', 'limit', '', _('limit number of changes displayed'), _('NUM')), | 150 (b'l', b'limit', b'', _(b'limit number of changes displayed'), _(b'NUM')), |
139 ('M', 'no-merges', None, _('do not show merges')), | 151 (b'M', b'no-merges', None, _(b'do not show merges')), |
140 ('', 'stat', None, _('output diffstat-style summary of changes')), | 152 (b'', b'stat', None, _(b'output diffstat-style summary of changes')), |
141 ('G', 'graph', None, _("show the revision DAG")), | 153 (b'G', b'graph', None, _(b"show the revision DAG")), |
142 ] + templateopts | 154 ] + templateopts |
143 | 155 |
144 diffopts = [ | 156 diffopts = [ |
145 ('a', 'text', None, _('treat all files as text')), | 157 (b'a', b'text', None, _(b'treat all files as text')), |
146 ('g', 'git', None, _('use git extended diff format')), | 158 (b'g', b'git', None, _(b'use git extended diff format')), |
147 ('', 'binary', None, _('generate binary diffs in git mode (default)')), | 159 (b'', b'binary', None, _(b'generate binary diffs in git mode (default)')), |
148 ('', 'nodates', None, _('omit dates from diff headers')), | 160 (b'', b'nodates', None, _(b'omit dates from diff headers')), |
149 ] | 161 ] |
150 | 162 |
151 diffwsopts = [ | 163 diffwsopts = [ |
152 ( | 164 ( |
153 'w', | 165 b'w', |
154 'ignore-all-space', | 166 b'ignore-all-space', |
155 None, | 167 None, |
156 _('ignore white space when comparing lines'), | 168 _(b'ignore white space when comparing lines'), |
157 ), | 169 ), |
158 ( | 170 ( |
159 'b', | 171 b'b', |
160 'ignore-space-change', | 172 b'ignore-space-change', |
161 None, | 173 None, |
162 _('ignore changes in the amount of white space'), | 174 _(b'ignore changes in the amount of white space'), |
163 ), | 175 ), |
164 ( | 176 ( |
165 'B', | 177 b'B', |
166 'ignore-blank-lines', | 178 b'ignore-blank-lines', |
167 None, | 179 None, |
168 _('ignore changes whose lines are all blank'), | 180 _(b'ignore changes whose lines are all blank'), |
169 ), | 181 ), |
170 ( | 182 ( |
171 'Z', | 183 b'Z', |
172 'ignore-space-at-eol', | 184 b'ignore-space-at-eol', |
173 None, | 185 None, |
174 _('ignore changes in whitespace at EOL'), | 186 _(b'ignore changes in whitespace at EOL'), |
175 ), | 187 ), |
176 ] | 188 ] |
177 | 189 |
178 diffopts2 = ( | 190 diffopts2 = ( |
179 [ | 191 [ |
180 ('', 'noprefix', None, _('omit a/ and b/ prefixes from filenames')), | 192 (b'', b'noprefix', None, _(b'omit a/ and b/ prefixes from filenames')), |
181 ( | 193 ( |
182 'p', | 194 b'p', |
183 'show-function', | 195 b'show-function', |
184 None, | 196 None, |
185 _('show which function each change is in'), | 197 _(b'show which function each change is in'), |
186 ), | 198 ), |
187 ('', 'reverse', None, _('produce a diff that undoes the changes')), | 199 (b'', b'reverse', None, _(b'produce a diff that undoes the changes')), |
188 ] | 200 ] |
189 + diffwsopts | 201 + diffwsopts |
190 + [ | 202 + [ |
191 ('U', 'unified', '', _('number of lines of context to show'), _('NUM')), | 203 ( |
192 ('', 'stat', None, _('output diffstat-style summary of changes')), | 204 b'U', |
193 ('', 'root', '', _('produce diffs relative to subdirectory'), _('DIR')), | 205 b'unified', |
206 b'', | |
207 _(b'number of lines of context to show'), | |
208 _(b'NUM'), | |
209 ), | |
210 (b'', b'stat', None, _(b'output diffstat-style summary of changes')), | |
211 ( | |
212 b'', | |
213 b'root', | |
214 b'', | |
215 _(b'produce diffs relative to subdirectory'), | |
216 _(b'DIR'), | |
217 ), | |
194 ] | 218 ] |
195 ) | 219 ) |
196 | 220 |
197 mergetoolopts = [ | 221 mergetoolopts = [ |
198 ('t', 'tool', '', _('specify merge tool'), _('TOOL')), | 222 (b't', b'tool', b'', _(b'specify merge tool'), _(b'TOOL')), |
199 ] | 223 ] |
200 | 224 |
201 similarityopts = [ | 225 similarityopts = [ |
202 ( | 226 ( |
203 's', | 227 b's', |
204 'similarity', | 228 b'similarity', |
205 '', | 229 b'', |
206 _('guess renamed files by similarity (0<=s<=100)'), | 230 _(b'guess renamed files by similarity (0<=s<=100)'), |
207 _('SIMILARITY'), | 231 _(b'SIMILARITY'), |
208 ) | 232 ) |
209 ] | 233 ] |
210 | 234 |
211 subrepoopts = [('S', 'subrepos', None, _('recurse into subrepositories'))] | 235 subrepoopts = [(b'S', b'subrepos', None, _(b'recurse into subrepositories'))] |
212 | 236 |
213 debugrevlogopts = [ | 237 debugrevlogopts = [ |
214 ('c', 'changelog', False, _('open changelog')), | 238 (b'c', b'changelog', False, _(b'open changelog')), |
215 ('m', 'manifest', False, _('open manifest')), | 239 (b'm', b'manifest', False, _(b'open manifest')), |
216 ('', 'dir', '', _('open directory manifest')), | 240 (b'', b'dir', b'', _(b'open directory manifest')), |
217 ] | 241 ] |
218 | 242 |
219 # special string such that everything below this line will be ingored in the | 243 # special string such that everything below this line will be ingored in the |
220 # editor text | 244 # editor text |
221 _linebelow = "^HG: ------------------------ >8 ------------------------$" | 245 _linebelow = b"^HG: ------------------------ >8 ------------------------$" |
222 | 246 |
223 | 247 |
224 def resolvecommitoptions(ui, opts): | 248 def resolvecommitoptions(ui, opts): |
225 """modify commit options dict to handle related options | 249 """modify commit options dict to handle related options |
226 | 250 |
227 The return value indicates that ``rewrite.update-timestamp`` is the reason | 251 The return value indicates that ``rewrite.update-timestamp`` is the reason |
228 the ``date`` option is set. | 252 the ``date`` option is set. |
229 """ | 253 """ |
230 if opts.get('date') and opts.get('currentdate'): | 254 if opts.get(b'date') and opts.get(b'currentdate'): |
231 raise error.Abort( | 255 raise error.Abort( |
232 _('--date and --currentdate are mutually ' 'exclusive') | 256 _(b'--date and --currentdate are mutually ' b'exclusive') |
233 ) | 257 ) |
234 if opts.get(b'user') and opts.get(b'currentuser'): | 258 if opts.get(b'user') and opts.get(b'currentuser'): |
235 raise error.Abort( | 259 raise error.Abort( |
236 _('--user and --currentuser are mutually ' 'exclusive') | 260 _(b'--user and --currentuser are mutually ' b'exclusive') |
237 ) | 261 ) |
238 | 262 |
239 datemaydiffer = False # date-only change should be ignored? | 263 datemaydiffer = False # date-only change should be ignored? |
240 | 264 |
241 if opts.get(b'currentdate'): | 265 if opts.get(b'currentdate'): |
242 opts[b'date'] = b'%d %d' % dateutil.makedate() | 266 opts[b'date'] = b'%d %d' % dateutil.makedate() |
243 elif ( | 267 elif ( |
244 not opts.get('date') | 268 not opts.get(b'date') |
245 and ui.configbool('rewrite', 'update-timestamp') | 269 and ui.configbool(b'rewrite', b'update-timestamp') |
246 and opts.get('currentdate') is None | 270 and opts.get(b'currentdate') is None |
247 ): | 271 ): |
248 opts[b'date'] = b'%d %d' % dateutil.makedate() | 272 opts[b'date'] = b'%d %d' % dateutil.makedate() |
249 datemaydiffer = True | 273 datemaydiffer = True |
250 | 274 |
251 if opts.get(b'currentuser'): | 275 if opts.get(b'currentuser'): |
255 | 279 |
256 | 280 |
257 def checknotesize(ui, opts): | 281 def checknotesize(ui, opts): |
258 """ make sure note is of valid format """ | 282 """ make sure note is of valid format """ |
259 | 283 |
260 note = opts.get('note') | 284 note = opts.get(b'note') |
261 if not note: | 285 if not note: |
262 return | 286 return |
263 | 287 |
264 if len(note) > 255: | 288 if len(note) > 255: |
265 raise error.Abort(_(b"cannot store a note of more than 255 bytes")) | 289 raise error.Abort(_(b"cannot store a note of more than 255 bytes")) |
287 ) | 311 ) |
288 return newlyaddedandmodifiedfiles, alsorestore | 312 return newlyaddedandmodifiedfiles, alsorestore |
289 | 313 |
290 | 314 |
291 def parsealiases(cmd): | 315 def parsealiases(cmd): |
292 return cmd.split("|") | 316 return cmd.split(b"|") |
293 | 317 |
294 | 318 |
295 def setupwrapcolorwrite(ui): | 319 def setupwrapcolorwrite(ui): |
296 # wrap ui.write so diff output can be labeled/colorized | 320 # wrap ui.write so diff output can be labeled/colorized |
297 def wrapwrite(orig, *args, **kw): | 321 def wrapwrite(orig, *args, **kw): |
298 label = kw.pop(r'label', '') | 322 label = kw.pop(r'label', b'') |
299 for chunk, l in patch.difflabel(lambda: args): | 323 for chunk, l in patch.difflabel(lambda: args): |
300 orig(chunk, label=label + l) | 324 orig(chunk, label=label + l) |
301 | 325 |
302 oldwrite = ui.write | 326 oldwrite = ui.write |
303 | 327 |
320 | 344 |
321 return crecordmod.filterpatch( | 345 return crecordmod.filterpatch( |
322 ui, originalhunks, recordfn, operation | 346 ui, originalhunks, recordfn, operation |
323 ) | 347 ) |
324 except crecordmod.fallbackerror as e: | 348 except crecordmod.fallbackerror as e: |
325 ui.warn('%s\n' % e.message) | 349 ui.warn(b'%s\n' % e.message) |
326 ui.warn(_('falling back to text mode\n')) | 350 ui.warn(_(b'falling back to text mode\n')) |
327 | 351 |
328 return patch.filterpatch(ui, originalhunks, match, operation) | 352 return patch.filterpatch(ui, originalhunks, match, operation) |
329 | 353 |
330 | 354 |
331 def recordfilter(ui, originalhunks, match, operation=None): | 355 def recordfilter(ui, originalhunks, match, operation=None): |
334 *operation* is used for to build ui messages to indicate the user what | 358 *operation* is used for to build ui messages to indicate the user what |
335 kind of filtering they are doing: reverting, committing, shelving, etc. | 359 kind of filtering they are doing: reverting, committing, shelving, etc. |
336 (see patch.filterpatch). | 360 (see patch.filterpatch). |
337 """ | 361 """ |
338 usecurses = crecordmod.checkcurses(ui) | 362 usecurses = crecordmod.checkcurses(ui) |
339 testfile = ui.config('experimental', 'crecordtest') | 363 testfile = ui.config(b'experimental', b'crecordtest') |
340 oldwrite = setupwrapcolorwrite(ui) | 364 oldwrite = setupwrapcolorwrite(ui) |
341 try: | 365 try: |
342 newchunks, newopts = filterchunks( | 366 newchunks, newopts = filterchunks( |
343 ui, originalhunks, usecurses, testfile, match, operation | 367 ui, originalhunks, usecurses, testfile, match, operation |
344 ) | 368 ) |
351 ui, repo, commitfunc, cmdsuggest, backupall, filterfn, *pats, **opts | 375 ui, repo, commitfunc, cmdsuggest, backupall, filterfn, *pats, **opts |
352 ): | 376 ): |
353 opts = pycompat.byteskwargs(opts) | 377 opts = pycompat.byteskwargs(opts) |
354 if not ui.interactive(): | 378 if not ui.interactive(): |
355 if cmdsuggest: | 379 if cmdsuggest: |
356 msg = _('running non-interactively, use %s instead') % cmdsuggest | 380 msg = _(b'running non-interactively, use %s instead') % cmdsuggest |
357 else: | 381 else: |
358 msg = _('running non-interactively') | 382 msg = _(b'running non-interactively') |
359 raise error.Abort(msg) | 383 raise error.Abort(msg) |
360 | 384 |
361 # make sure username is set before going interactive | 385 # make sure username is set before going interactive |
362 if not opts.get('user'): | 386 if not opts.get(b'user'): |
363 ui.username() # raise exception, username not provided | 387 ui.username() # raise exception, username not provided |
364 | 388 |
365 def recordfunc(ui, repo, message, match, opts): | 389 def recordfunc(ui, repo, message, match, opts): |
366 """This is generic record driver. | 390 """This is generic record driver. |
367 | 391 |
374 working directory is restored to its original state. | 398 working directory is restored to its original state. |
375 | 399 |
376 In the end we'll record interesting changes, and everything else | 400 In the end we'll record interesting changes, and everything else |
377 will be left in place, so the user can continue working. | 401 will be left in place, so the user can continue working. |
378 """ | 402 """ |
379 if not opts.get('interactive-unshelve'): | 403 if not opts.get(b'interactive-unshelve'): |
380 checkunfinished(repo, commit=True) | 404 checkunfinished(repo, commit=True) |
381 wctx = repo[None] | 405 wctx = repo[None] |
382 merge = len(wctx.parents()) > 1 | 406 merge = len(wctx.parents()) > 1 |
383 if merge: | 407 if merge: |
384 raise error.Abort( | 408 raise error.Abort( |
385 _( | 409 _( |
386 'cannot partially commit a merge ' | 410 b'cannot partially commit a merge ' |
387 '(use "hg commit" instead)' | 411 b'(use "hg commit" instead)' |
388 ) | 412 ) |
389 ) | 413 ) |
390 | 414 |
391 def fail(f, msg): | 415 def fail(f, msg): |
392 raise error.Abort('%s: %s' % (f, msg)) | 416 raise error.Abort(b'%s: %s' % (f, msg)) |
393 | 417 |
394 force = opts.get('force') | 418 force = opts.get(b'force') |
395 if not force: | 419 if not force: |
396 vdirs = [] | 420 vdirs = [] |
397 match = matchmod.badmatch(match, fail) | 421 match = matchmod.badmatch(match, fail) |
398 match.explicitdir = vdirs.append | 422 match.explicitdir = vdirs.append |
399 | 423 |
426 repo.checkcommitpatterns(wctx, vdirs, match, status, fail) | 450 repo.checkcommitpatterns(wctx, vdirs, match, status, fail) |
427 diffopts = patch.difffeatureopts( | 451 diffopts = patch.difffeatureopts( |
428 ui, | 452 ui, |
429 opts=opts, | 453 opts=opts, |
430 whitespace=True, | 454 whitespace=True, |
431 section='commands', | 455 section=b'commands', |
432 configprefix='commit.interactive.', | 456 configprefix=b'commit.interactive.', |
433 ) | 457 ) |
434 diffopts.nodates = True | 458 diffopts.nodates = True |
435 diffopts.git = True | 459 diffopts.git = True |
436 diffopts.showfunc = True | 460 diffopts.showfunc = True |
437 originaldiff = patch.diff(repo, changes=status, opts=diffopts) | 461 originaldiff = patch.diff(repo, changes=status, opts=diffopts) |
440 | 464 |
441 # 1. filter patch, since we are intending to apply subset of it | 465 # 1. filter patch, since we are intending to apply subset of it |
442 try: | 466 try: |
443 chunks, newopts = filterfn(ui, originalchunks, match) | 467 chunks, newopts = filterfn(ui, originalchunks, match) |
444 except error.PatchError as err: | 468 except error.PatchError as err: |
445 raise error.Abort(_('error parsing patch: %s') % err) | 469 raise error.Abort(_(b'error parsing patch: %s') % err) |
446 opts.update(newopts) | 470 opts.update(newopts) |
447 | 471 |
448 # We need to keep a backup of files that have been newly added and | 472 # We need to keep a backup of files that have been newly added and |
449 # modified during the recording process because there is a previous | 473 # modified during the recording process because there is a previous |
450 # version without the edit in the workdir. We also will need to restore | 474 # version without the edit in the workdir. We also will need to restore |
461 pass | 485 pass |
462 | 486 |
463 changed = status.modified + status.added + status.removed | 487 changed = status.modified + status.added + status.removed |
464 newfiles = [f for f in changed if f in contenders] | 488 newfiles = [f for f in changed if f in contenders] |
465 if not newfiles: | 489 if not newfiles: |
466 ui.status(_('no changes to record\n')) | 490 ui.status(_(b'no changes to record\n')) |
467 return 0 | 491 return 0 |
468 | 492 |
469 modified = set(status.modified) | 493 modified = set(status.modified) |
470 | 494 |
471 # 2. backup changed files, so we can restore them in the end | 495 # 2. backup changed files, so we can restore them in the end |
478 for f in newfiles | 502 for f in newfiles |
479 if f in modified or f in newlyaddedandmodifiedfiles | 503 if f in modified or f in newlyaddedandmodifiedfiles |
480 ] | 504 ] |
481 backups = {} | 505 backups = {} |
482 if tobackup: | 506 if tobackup: |
483 backupdir = repo.vfs.join('record-backups') | 507 backupdir = repo.vfs.join(b'record-backups') |
484 try: | 508 try: |
485 os.mkdir(backupdir) | 509 os.mkdir(backupdir) |
486 except OSError as err: | 510 except OSError as err: |
487 if err.errno != errno.EEXIST: | 511 if err.errno != errno.EEXIST: |
488 raise | 512 raise |
489 try: | 513 try: |
490 # backup continues | 514 # backup continues |
491 for f in tobackup: | 515 for f in tobackup: |
492 fd, tmpname = pycompat.mkstemp( | 516 fd, tmpname = pycompat.mkstemp( |
493 prefix=f.replace('/', '_') + '.', dir=backupdir | 517 prefix=f.replace(b'/', b'_') + b'.', dir=backupdir |
494 ) | 518 ) |
495 os.close(fd) | 519 os.close(fd) |
496 ui.debug('backup %r as %r\n' % (f, tmpname)) | 520 ui.debug(b'backup %r as %r\n' % (f, tmpname)) |
497 util.copyfile(repo.wjoin(f), tmpname, copystat=True) | 521 util.copyfile(repo.wjoin(f), tmpname, copystat=True) |
498 backups[f] = tmpname | 522 backups[f] = tmpname |
499 | 523 |
500 fp = stringio() | 524 fp = stringio() |
501 for c in chunks: | 525 for c in chunks: |
504 c.write(fp) | 528 c.write(fp) |
505 dopatch = fp.tell() | 529 dopatch = fp.tell() |
506 fp.seek(0) | 530 fp.seek(0) |
507 | 531 |
508 # 2.5 optionally review / modify patch in text editor | 532 # 2.5 optionally review / modify patch in text editor |
509 if opts.get('review', False): | 533 if opts.get(b'review', False): |
510 patchtext = ( | 534 patchtext = ( |
511 crecordmod.diffhelptext | 535 crecordmod.diffhelptext |
512 + crecordmod.patchhelptext | 536 + crecordmod.patchhelptext |
513 + fp.read() | 537 + fp.read() |
514 ) | 538 ) |
515 reviewedpatch = ui.edit( | 539 reviewedpatch = ui.edit( |
516 patchtext, "", action="diff", repopath=repo.path | 540 patchtext, b"", action=b"diff", repopath=repo.path |
517 ) | 541 ) |
518 fp.truncate(0) | 542 fp.truncate(0) |
519 fp.write(reviewedpatch) | 543 fp.write(reviewedpatch) |
520 fp.seek(0) | 544 fp.seek(0) |
521 | 545 |
533 ) | 557 ) |
534 | 558 |
535 # 3b. (apply) | 559 # 3b. (apply) |
536 if dopatch: | 560 if dopatch: |
537 try: | 561 try: |
538 ui.debug('applying patch\n') | 562 ui.debug(b'applying patch\n') |
539 ui.debug(fp.getvalue()) | 563 ui.debug(fp.getvalue()) |
540 patch.internalpatch(ui, repo, fp, 1, eolmode=None) | 564 patch.internalpatch(ui, repo, fp, 1, eolmode=None) |
541 except error.PatchError as err: | 565 except error.PatchError as err: |
542 raise error.Abort(pycompat.bytestr(err)) | 566 raise error.Abort(pycompat.bytestr(err)) |
543 del fp | 567 del fp |
552 finally: | 576 finally: |
553 # 5. finally restore backed-up files | 577 # 5. finally restore backed-up files |
554 try: | 578 try: |
555 dirstate = repo.dirstate | 579 dirstate = repo.dirstate |
556 for realname, tmpname in backups.iteritems(): | 580 for realname, tmpname in backups.iteritems(): |
557 ui.debug('restoring %r to %r\n' % (tmpname, realname)) | 581 ui.debug(b'restoring %r to %r\n' % (tmpname, realname)) |
558 | 582 |
559 if dirstate[realname] == 'n': | 583 if dirstate[realname] == b'n': |
560 # without normallookup, restoring timestamp | 584 # without normallookup, restoring timestamp |
561 # may cause partially committed files | 585 # may cause partially committed files |
562 # to be treated as unmodified | 586 # to be treated as unmodified |
563 dirstate.normallookup(realname) | 587 dirstate.normallookup(realname) |
564 | 588 |
616 there. | 640 there. |
617 """ | 641 """ |
618 | 642 |
619 # the filename contains a path separator, it means it's not the direct | 643 # the filename contains a path separator, it means it's not the direct |
620 # child of this directory | 644 # child of this directory |
621 if '/' in filename: | 645 if b'/' in filename: |
622 subdir, filep = filename.split('/', 1) | 646 subdir, filep = filename.split(b'/', 1) |
623 | 647 |
624 # does the dirnode object for subdir exists | 648 # does the dirnode object for subdir exists |
625 if subdir not in self.subdirs: | 649 if subdir not in self.subdirs: |
626 subdirpath = pathutil.join(self.path, subdir) | 650 subdirpath = pathutil.join(self.path, subdir) |
627 self.subdirs[subdir] = dirnode(subdirpath) | 651 self.subdirs[subdir] = dirnode(subdirpath) |
667 onlyst = self.statuses.pop() | 691 onlyst = self.statuses.pop() |
668 | 692 |
669 # Making sure we terse only when the status abbreviation is | 693 # Making sure we terse only when the status abbreviation is |
670 # passed as terse argument | 694 # passed as terse argument |
671 if onlyst in terseargs: | 695 if onlyst in terseargs: |
672 yield onlyst, self.path + '/' | 696 yield onlyst, self.path + b'/' |
673 return | 697 return |
674 | 698 |
675 # add the files to status list | 699 # add the files to status list |
676 for st, fpath in self.iterfilepaths(): | 700 for st, fpath in self.iterfilepaths(): |
677 yield st, fpath | 701 yield st, fpath |
694 The function makes a tree of objects of dirnode class, and at each node it | 718 The function makes a tree of objects of dirnode class, and at each node it |
695 stores the information required to know whether we can terse a certain | 719 stores the information required to know whether we can terse a certain |
696 directory or not. | 720 directory or not. |
697 """ | 721 """ |
698 # the order matters here as that is used to produce final list | 722 # the order matters here as that is used to produce final list |
699 allst = ('m', 'a', 'r', 'd', 'u', 'i', 'c') | 723 allst = (b'm', b'a', b'r', b'd', b'u', b'i', b'c') |
700 | 724 |
701 # checking the argument validity | 725 # checking the argument validity |
702 for s in pycompat.bytestr(terseargs): | 726 for s in pycompat.bytestr(terseargs): |
703 if s not in allst: | 727 if s not in allst: |
704 raise error.Abort(_("'%s' not recognized") % s) | 728 raise error.Abort(_(b"'%s' not recognized") % s) |
705 | 729 |
706 # creating a dirnode object for the root of the repo | 730 # creating a dirnode object for the root of the repo |
707 rootobj = dirnode('') | 731 rootobj = dirnode(b'') |
708 pstatus = ( | 732 pstatus = ( |
709 'modified', | 733 b'modified', |
710 'added', | 734 b'added', |
711 'deleted', | 735 b'deleted', |
712 'clean', | 736 b'clean', |
713 'unknown', | 737 b'unknown', |
714 'ignored', | 738 b'ignored', |
715 'removed', | 739 b'removed', |
716 ) | 740 ) |
717 | 741 |
718 tersedict = {} | 742 tersedict = {} |
719 for attrname in pstatus: | 743 for attrname in pstatus: |
720 statuschar = attrname[0:1] | 744 statuschar = attrname[0:1] |
740 | 764 |
741 | 765 |
742 def _commentlines(raw): | 766 def _commentlines(raw): |
743 '''Surround lineswith a comment char and a new line''' | 767 '''Surround lineswith a comment char and a new line''' |
744 lines = raw.splitlines() | 768 lines = raw.splitlines() |
745 commentedlines = ['# %s' % line for line in lines] | 769 commentedlines = [b'# %s' % line for line in lines] |
746 return '\n'.join(commentedlines) + '\n' | 770 return b'\n'.join(commentedlines) + b'\n' |
747 | 771 |
748 | 772 |
749 def _conflictsmsg(repo): | 773 def _conflictsmsg(repo): |
750 mergestate = mergemod.mergestate.read(repo) | 774 mergestate = mergemod.mergestate.read(repo) |
751 if not mergestate.active(): | 775 if not mergestate.active(): |
752 return | 776 return |
753 | 777 |
754 m = scmutil.match(repo[None]) | 778 m = scmutil.match(repo[None]) |
755 unresolvedlist = [f for f in mergestate.unresolved() if m(f)] | 779 unresolvedlist = [f for f in mergestate.unresolved() if m(f)] |
756 if unresolvedlist: | 780 if unresolvedlist: |
757 mergeliststr = '\n'.join( | 781 mergeliststr = b'\n'.join( |
758 [ | 782 [ |
759 ' %s' % util.pathto(repo.root, encoding.getcwd(), path) | 783 b' %s' % util.pathto(repo.root, encoding.getcwd(), path) |
760 for path in sorted(unresolvedlist) | 784 for path in sorted(unresolvedlist) |
761 ] | 785 ] |
762 ) | 786 ) |
763 msg = ( | 787 msg = ( |
764 _( | 788 _( |
769 To mark files as resolved: hg resolve --mark FILE''' | 793 To mark files as resolved: hg resolve --mark FILE''' |
770 ) | 794 ) |
771 % mergeliststr | 795 % mergeliststr |
772 ) | 796 ) |
773 else: | 797 else: |
774 msg = _('No unresolved merge conflicts.') | 798 msg = _(b'No unresolved merge conflicts.') |
775 | 799 |
776 return _commentlines(msg) | 800 return _commentlines(msg) |
777 | 801 |
778 | 802 |
779 def morestatus(repo, fm): | 803 def morestatus(repo, fm): |
780 statetuple = statemod.getrepostate(repo) | 804 statetuple = statemod.getrepostate(repo) |
781 label = 'status.morestatus' | 805 label = b'status.morestatus' |
782 if statetuple: | 806 if statetuple: |
783 state, helpfulmsg = statetuple | 807 state, helpfulmsg = statetuple |
784 statemsg = _('The repository is in an unfinished *%s* state.') % state | 808 statemsg = _(b'The repository is in an unfinished *%s* state.') % state |
785 fm.plain('%s\n' % _commentlines(statemsg), label=label) | 809 fm.plain(b'%s\n' % _commentlines(statemsg), label=label) |
786 conmsg = _conflictsmsg(repo) | 810 conmsg = _conflictsmsg(repo) |
787 if conmsg: | 811 if conmsg: |
788 fm.plain('%s\n' % conmsg, label=label) | 812 fm.plain(b'%s\n' % conmsg, label=label) |
789 if helpfulmsg: | 813 if helpfulmsg: |
790 fm.plain('%s\n' % _commentlines(helpfulmsg), label=label) | 814 fm.plain(b'%s\n' % _commentlines(helpfulmsg), label=label) |
791 | 815 |
792 | 816 |
793 def findpossible(cmd, table, strict=False): | 817 def findpossible(cmd, table, strict=False): |
794 """ | 818 """ |
795 Return cmd -> (aliases, command table entry) | 819 Return cmd -> (aliases, command table entry) |
816 for a in aliases: | 840 for a in aliases: |
817 if a.startswith(cmd): | 841 if a.startswith(cmd): |
818 found = a | 842 found = a |
819 break | 843 break |
820 if found is not None: | 844 if found is not None: |
821 if aliases[0].startswith("debug") or found.startswith("debug"): | 845 if aliases[0].startswith(b"debug") or found.startswith(b"debug"): |
822 debugchoice[found] = (aliases, table[e]) | 846 debugchoice[found] = (aliases, table[e]) |
823 else: | 847 else: |
824 choice[found] = (aliases, table[e]) | 848 choice[found] = (aliases, table[e]) |
825 | 849 |
826 if not choice and debugchoice: | 850 if not choice and debugchoice: |
847 | 871 |
848 | 872 |
849 def changebranch(ui, repo, revs, label): | 873 def changebranch(ui, repo, revs, label): |
850 """ Change the branch name of given revs to label """ | 874 """ Change the branch name of given revs to label """ |
851 | 875 |
852 with repo.wlock(), repo.lock(), repo.transaction('branches'): | 876 with repo.wlock(), repo.lock(), repo.transaction(b'branches'): |
853 # abort in case of uncommitted merge or dirty wdir | 877 # abort in case of uncommitted merge or dirty wdir |
854 bailifchanged(repo) | 878 bailifchanged(repo) |
855 revs = scmutil.revrange(repo, revs) | 879 revs = scmutil.revrange(repo, revs) |
856 if not revs: | 880 if not revs: |
857 raise error.Abort("empty revision set") | 881 raise error.Abort(b"empty revision set") |
858 roots = repo.revs('roots(%ld)', revs) | 882 roots = repo.revs(b'roots(%ld)', revs) |
859 if len(roots) > 1: | 883 if len(roots) > 1: |
860 raise error.Abort(_("cannot change branch of non-linear revisions")) | 884 raise error.Abort( |
861 rewriteutil.precheck(repo, revs, 'change branch of') | 885 _(b"cannot change branch of non-linear revisions") |
886 ) | |
887 rewriteutil.precheck(repo, revs, b'change branch of') | |
862 | 888 |
863 root = repo[roots.first()] | 889 root = repo[roots.first()] |
864 rpb = {parent.branch() for parent in root.parents()} | 890 rpb = {parent.branch() for parent in root.parents()} |
865 if label not in rpb and label in repo.branchmap(): | 891 if label not in rpb and label in repo.branchmap(): |
866 raise error.Abort(_("a branch of the same name already exists")) | 892 raise error.Abort(_(b"a branch of the same name already exists")) |
867 | 893 |
868 if repo.revs('obsolete() and %ld', revs): | 894 if repo.revs(b'obsolete() and %ld', revs): |
869 raise error.Abort(_("cannot change branch of a obsolete changeset")) | 895 raise error.Abort( |
896 _(b"cannot change branch of a obsolete changeset") | |
897 ) | |
870 | 898 |
871 # make sure only topological heads | 899 # make sure only topological heads |
872 if repo.revs('heads(%ld) - head()', revs): | 900 if repo.revs(b'heads(%ld) - head()', revs): |
873 raise error.Abort(_("cannot change branch in middle of a stack")) | 901 raise error.Abort(_(b"cannot change branch in middle of a stack")) |
874 | 902 |
875 replacements = {} | 903 replacements = {} |
876 # avoid import cycle mercurial.cmdutil -> mercurial.context -> | 904 # avoid import cycle mercurial.cmdutil -> mercurial.context -> |
877 # mercurial.subrepo -> mercurial.cmdutil | 905 # mercurial.subrepo -> mercurial.cmdutil |
878 from . import context | 906 from . import context |
889 return ctx[path] | 917 return ctx[path] |
890 except error.ManifestLookupError: | 918 except error.ManifestLookupError: |
891 return None | 919 return None |
892 | 920 |
893 ui.debug( | 921 ui.debug( |
894 "changing branch of '%s' from '%s' to '%s'\n" | 922 b"changing branch of '%s' from '%s' to '%s'\n" |
895 % (hex(ctx.node()), oldbranch, label) | 923 % (hex(ctx.node()), oldbranch, label) |
896 ) | 924 ) |
897 extra = ctx.extra() | 925 extra = ctx.extra() |
898 extra['branch_change'] = hex(ctx.node()) | 926 extra[b'branch_change'] = hex(ctx.node()) |
899 # While changing branch of set of linear commits, make sure that | 927 # While changing branch of set of linear commits, make sure that |
900 # we base our commits on new parent rather than old parent which | 928 # we base our commits on new parent rather than old parent which |
901 # was obsoleted while changing the branch | 929 # was obsoleted while changing the branch |
902 p1 = ctx.p1().node() | 930 p1 = ctx.p1().node() |
903 p2 = ctx.p2().node() | 931 p2 = ctx.p2().node() |
918 branch=label, | 946 branch=label, |
919 ) | 947 ) |
920 | 948 |
921 newnode = repo.commitctx(mc) | 949 newnode = repo.commitctx(mc) |
922 replacements[ctx.node()] = (newnode,) | 950 replacements[ctx.node()] = (newnode,) |
923 ui.debug('new node id is %s\n' % hex(newnode)) | 951 ui.debug(b'new node id is %s\n' % hex(newnode)) |
924 | 952 |
925 # create obsmarkers and move bookmarks | 953 # create obsmarkers and move bookmarks |
926 scmutil.cleanupnodes(repo, replacements, 'branch-change', fixphase=True) | 954 scmutil.cleanupnodes( |
955 repo, replacements, b'branch-change', fixphase=True | |
956 ) | |
927 | 957 |
928 # move the working copy too | 958 # move the working copy too |
929 wctx = repo[None] | 959 wctx = repo[None] |
930 # in-progress merge is a bit too complex for now. | 960 # in-progress merge is a bit too complex for now. |
931 if len(wctx.parents()) == 1: | 961 if len(wctx.parents()) == 1: |
935 # mercurial.cmdutil | 965 # mercurial.cmdutil |
936 from . import hg | 966 from . import hg |
937 | 967 |
938 hg.update(repo, newid[0], quietempty=True) | 968 hg.update(repo, newid[0], quietempty=True) |
939 | 969 |
940 ui.status(_("changed branch on %d changesets\n") % len(replacements)) | 970 ui.status(_(b"changed branch on %d changesets\n") % len(replacements)) |
941 | 971 |
942 | 972 |
943 def findrepo(p): | 973 def findrepo(p): |
944 while not os.path.isdir(os.path.join(p, ".hg")): | 974 while not os.path.isdir(os.path.join(p, b".hg")): |
945 oldp, p = p, os.path.dirname(p) | 975 oldp, p = p, os.path.dirname(p) |
946 if p == oldp: | 976 if p == oldp: |
947 return None | 977 return None |
948 | 978 |
949 return p | 979 return p |
957 | 987 |
958 'hint' is the usual hint given to Abort exception. | 988 'hint' is the usual hint given to Abort exception. |
959 """ | 989 """ |
960 | 990 |
961 if merge and repo.dirstate.p2() != nullid: | 991 if merge and repo.dirstate.p2() != nullid: |
962 raise error.Abort(_('outstanding uncommitted merge'), hint=hint) | 992 raise error.Abort(_(b'outstanding uncommitted merge'), hint=hint) |
963 modified, added, removed, deleted = repo.status()[:4] | 993 modified, added, removed, deleted = repo.status()[:4] |
964 if modified or added or removed or deleted: | 994 if modified or added or removed or deleted: |
965 raise error.Abort(_('uncommitted changes'), hint=hint) | 995 raise error.Abort(_(b'uncommitted changes'), hint=hint) |
966 ctx = repo[None] | 996 ctx = repo[None] |
967 for s in sorted(ctx.substate): | 997 for s in sorted(ctx.substate): |
968 ctx.sub(s).bailifchanged(hint=hint) | 998 ctx.sub(s).bailifchanged(hint=hint) |
969 | 999 |
970 | 1000 |
971 def logmessage(ui, opts): | 1001 def logmessage(ui, opts): |
972 """ get the log message according to -m and -l option """ | 1002 """ get the log message according to -m and -l option """ |
973 message = opts.get('message') | 1003 message = opts.get(b'message') |
974 logfile = opts.get('logfile') | 1004 logfile = opts.get(b'logfile') |
975 | 1005 |
976 if message and logfile: | 1006 if message and logfile: |
977 raise error.Abort( | 1007 raise error.Abort( |
978 _('options --message and --logfile are mutually ' 'exclusive') | 1008 _(b'options --message and --logfile are mutually ' b'exclusive') |
979 ) | 1009 ) |
980 if not message and logfile: | 1010 if not message and logfile: |
981 try: | 1011 try: |
982 if isstdiofilename(logfile): | 1012 if isstdiofilename(logfile): |
983 message = ui.fin.read() | 1013 message = ui.fin.read() |
984 else: | 1014 else: |
985 message = '\n'.join(util.readfile(logfile).splitlines()) | 1015 message = b'\n'.join(util.readfile(logfile).splitlines()) |
986 except IOError as inst: | 1016 except IOError as inst: |
987 raise error.Abort( | 1017 raise error.Abort( |
988 _("can't read commit message '%s': %s") | 1018 _(b"can't read commit message '%s': %s") |
989 % (logfile, encoding.strtolocal(inst.strerror)) | 1019 % (logfile, encoding.strtolocal(inst.strerror)) |
990 ) | 1020 ) |
991 return message | 1021 return message |
992 | 1022 |
993 | 1023 |
1000 This returns baseformname with '.merge' appended if it is a merge, | 1030 This returns baseformname with '.merge' appended if it is a merge, |
1001 otherwise '.normal' is appended. | 1031 otherwise '.normal' is appended. |
1002 """ | 1032 """ |
1003 if isinstance(ctxorbool, bool): | 1033 if isinstance(ctxorbool, bool): |
1004 if ctxorbool: | 1034 if ctxorbool: |
1005 return baseformname + ".merge" | 1035 return baseformname + b".merge" |
1006 elif len(ctxorbool.parents()) > 1: | 1036 elif len(ctxorbool.parents()) > 1: |
1007 return baseformname + ".merge" | 1037 return baseformname + b".merge" |
1008 | 1038 |
1009 return baseformname + ".normal" | 1039 return baseformname + b".normal" |
1010 | 1040 |
1011 | 1041 |
1012 def getcommiteditor( | 1042 def getcommiteditor( |
1013 edit=False, finishdesc=None, extramsg=None, editform='', **opts | 1043 edit=False, finishdesc=None, extramsg=None, editform=b'', **opts |
1014 ): | 1044 ): |
1015 """get appropriate commit message editor according to '--edit' option | 1045 """get appropriate commit message editor according to '--edit' option |
1016 | 1046 |
1017 'finishdesc' is a function to be called with edited commit message | 1047 'finishdesc' is a function to be called with edited commit message |
1018 (= 'description' of the new changeset) just after editing, but | 1048 (= 'description' of the new changeset) just after editing, but |
1079 repo = ctx.repo() | 1109 repo = ctx.repo() |
1080 tres = formatter.templateresources(repo.ui, repo) | 1110 tres = formatter.templateresources(repo.ui, repo) |
1081 t = formatter.maketemplater( | 1111 t = formatter.maketemplater( |
1082 repo.ui, tmpl, defaults=templatekw.keywords, resources=tres | 1112 repo.ui, tmpl, defaults=templatekw.keywords, resources=tres |
1083 ) | 1113 ) |
1084 mapping = {'ctx': ctx} | 1114 mapping = {b'ctx': ctx} |
1085 if props: | 1115 if props: |
1086 mapping.update(props) | 1116 mapping.update(props) |
1087 return t.renderdefault(mapping) | 1117 return t.renderdefault(mapping) |
1088 | 1118 |
1089 | 1119 |
1143 newname.append(stringutil.escapestr(pat[i:end])) | 1173 newname.append(stringutil.escapestr(pat[i:end])) |
1144 break | 1174 break |
1145 newname.append(stringutil.escapestr(pat[i:n])) | 1175 newname.append(stringutil.escapestr(pat[i:n])) |
1146 if n + 2 > end: | 1176 if n + 2 > end: |
1147 raise error.Abort( | 1177 raise error.Abort( |
1148 _("incomplete format spec in output " "filename") | 1178 _(b"incomplete format spec in output " b"filename") |
1149 ) | 1179 ) |
1150 c = pat[n + 1 : n + 2] | 1180 c = pat[n + 1 : n + 2] |
1151 i = n + 2 | 1181 i = n + 2 |
1152 try: | 1182 try: |
1153 newname.append(expander[c]) | 1183 newname.append(expander[c]) |
1154 except KeyError: | 1184 except KeyError: |
1155 raise error.Abort( | 1185 raise error.Abort( |
1156 _("invalid format spec '%%%s' in output " "filename") % c | 1186 _(b"invalid format spec '%%%s' in output " b"filename") % c |
1157 ) | 1187 ) |
1158 return ''.join(newname) | 1188 return b''.join(newname) |
1159 | 1189 |
1160 | 1190 |
1161 def makefilename(ctx, pat, **props): | 1191 def makefilename(ctx, pat, **props): |
1162 if not pat: | 1192 if not pat: |
1163 return pat | 1193 return pat |
1168 return rendertemplate(ctx, tmpl, pycompat.byteskwargs(props)) | 1198 return rendertemplate(ctx, tmpl, pycompat.byteskwargs(props)) |
1169 | 1199 |
1170 | 1200 |
1171 def isstdiofilename(pat): | 1201 def isstdiofilename(pat): |
1172 """True if the given pat looks like a filename denoting stdin/stdout""" | 1202 """True if the given pat looks like a filename denoting stdin/stdout""" |
1173 return not pat or pat == '-' | 1203 return not pat or pat == b'-' |
1174 | 1204 |
1175 | 1205 |
1176 class _unclosablefile(object): | 1206 class _unclosablefile(object): |
1177 def __init__(self, fp): | 1207 def __init__(self, fp): |
1178 self._fp = fp | 1208 self._fp = fp |
1191 | 1221 |
1192 def __exit__(self, exc_type, exc_value, exc_tb): | 1222 def __exit__(self, exc_type, exc_value, exc_tb): |
1193 pass | 1223 pass |
1194 | 1224 |
1195 | 1225 |
1196 def makefileobj(ctx, pat, mode='wb', **props): | 1226 def makefileobj(ctx, pat, mode=b'wb', **props): |
1197 writable = mode not in ('r', 'rb') | 1227 writable = mode not in (b'r', b'rb') |
1198 | 1228 |
1199 if isstdiofilename(pat): | 1229 if isstdiofilename(pat): |
1200 repo = ctx.repo() | 1230 repo = ctx.repo() |
1201 if writable: | 1231 if writable: |
1202 fp = repo.ui.fout | 1232 fp = repo.ui.fout |
1207 return open(fn, mode) | 1237 return open(fn, mode) |
1208 | 1238 |
1209 | 1239 |
1210 def openstorage(repo, cmd, file_, opts, returnrevlog=False): | 1240 def openstorage(repo, cmd, file_, opts, returnrevlog=False): |
1211 """opens the changelog, manifest, a filelog or a given revlog""" | 1241 """opens the changelog, manifest, a filelog or a given revlog""" |
1212 cl = opts['changelog'] | 1242 cl = opts[b'changelog'] |
1213 mf = opts['manifest'] | 1243 mf = opts[b'manifest'] |
1214 dir = opts['dir'] | 1244 dir = opts[b'dir'] |
1215 msg = None | 1245 msg = None |
1216 if cl and mf: | 1246 if cl and mf: |
1217 msg = _('cannot specify --changelog and --manifest at the same time') | 1247 msg = _(b'cannot specify --changelog and --manifest at the same time') |
1218 elif cl and dir: | 1248 elif cl and dir: |
1219 msg = _('cannot specify --changelog and --dir at the same time') | 1249 msg = _(b'cannot specify --changelog and --dir at the same time') |
1220 elif cl or mf or dir: | 1250 elif cl or mf or dir: |
1221 if file_: | 1251 if file_: |
1222 msg = _('cannot specify filename with --changelog or --manifest') | 1252 msg = _(b'cannot specify filename with --changelog or --manifest') |
1223 elif not repo: | 1253 elif not repo: |
1224 msg = _( | 1254 msg = _( |
1225 'cannot specify --changelog or --manifest or --dir ' | 1255 b'cannot specify --changelog or --manifest or --dir ' |
1226 'without a repository' | 1256 b'without a repository' |
1227 ) | 1257 ) |
1228 if msg: | 1258 if msg: |
1229 raise error.Abort(msg) | 1259 raise error.Abort(msg) |
1230 | 1260 |
1231 r = None | 1261 r = None |
1232 if repo: | 1262 if repo: |
1233 if cl: | 1263 if cl: |
1234 r = repo.unfiltered().changelog | 1264 r = repo.unfiltered().changelog |
1235 elif dir: | 1265 elif dir: |
1236 if 'treemanifest' not in repo.requirements: | 1266 if b'treemanifest' not in repo.requirements: |
1237 raise error.Abort( | 1267 raise error.Abort( |
1238 _( | 1268 _( |
1239 "--dir can only be used on repos with " | 1269 b"--dir can only be used on repos with " |
1240 "treemanifest enabled" | 1270 b"treemanifest enabled" |
1241 ) | 1271 ) |
1242 ) | 1272 ) |
1243 if not dir.endswith('/'): | 1273 if not dir.endswith(b'/'): |
1244 dir = dir + '/' | 1274 dir = dir + b'/' |
1245 dirlog = repo.manifestlog.getstorage(dir) | 1275 dirlog = repo.manifestlog.getstorage(dir) |
1246 if len(dirlog): | 1276 if len(dirlog): |
1247 r = dirlog | 1277 r = dirlog |
1248 elif mf: | 1278 elif mf: |
1249 r = repo.manifestlog.getstorage(b'') | 1279 r = repo.manifestlog.getstorage(b'') |
1255 # Not all storage may be revlogs. If requested, try to return an actual | 1285 # Not all storage may be revlogs. If requested, try to return an actual |
1256 # revlog instance. | 1286 # revlog instance. |
1257 if returnrevlog: | 1287 if returnrevlog: |
1258 if isinstance(r, revlog.revlog): | 1288 if isinstance(r, revlog.revlog): |
1259 pass | 1289 pass |
1260 elif util.safehasattr(r, '_revlog'): | 1290 elif util.safehasattr(r, b'_revlog'): |
1261 r = r._revlog | 1291 r = r._revlog |
1262 elif r is not None: | 1292 elif r is not None: |
1263 raise error.Abort(_('%r does not appear to be a revlog') % r) | 1293 raise error.Abort(_(b'%r does not appear to be a revlog') % r) |
1264 | 1294 |
1265 if not r: | 1295 if not r: |
1266 if not returnrevlog: | 1296 if not returnrevlog: |
1267 raise error.Abort(_('cannot give path to non-revlog')) | 1297 raise error.Abort(_(b'cannot give path to non-revlog')) |
1268 | 1298 |
1269 if not file_: | 1299 if not file_: |
1270 raise error.CommandError(cmd, _('invalid arguments')) | 1300 raise error.CommandError(cmd, _(b'invalid arguments')) |
1271 if not os.path.isfile(file_): | 1301 if not os.path.isfile(file_): |
1272 raise error.Abort(_("revlog '%s' not found") % file_) | 1302 raise error.Abort(_(b"revlog '%s' not found") % file_) |
1273 r = revlog.revlog( | 1303 r = revlog.revlog( |
1274 vfsmod.vfs(encoding.getcwd(), audit=False), file_[:-2] + ".i" | 1304 vfsmod.vfs(encoding.getcwd(), audit=False), file_[:-2] + b".i" |
1275 ) | 1305 ) |
1276 return r | 1306 return r |
1277 | 1307 |
1278 | 1308 |
1279 def openrevlog(repo, cmd, file_, opts): | 1309 def openrevlog(repo, cmd, file_, opts): |
1294 # | 1324 # |
1295 # hgsep => pathname that uses "/" to separate directories | 1325 # hgsep => pathname that uses "/" to separate directories |
1296 # ossep => pathname that uses os.sep to separate directories | 1326 # ossep => pathname that uses os.sep to separate directories |
1297 cwd = repo.getcwd() | 1327 cwd = repo.getcwd() |
1298 targets = {} | 1328 targets = {} |
1299 after = opts.get("after") | 1329 after = opts.get(b"after") |
1300 dryrun = opts.get("dry_run") | 1330 dryrun = opts.get(b"dry_run") |
1301 wctx = repo[None] | 1331 wctx = repo[None] |
1302 | 1332 |
1303 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True) | 1333 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True) |
1304 | 1334 |
1305 def walkpat(pat): | 1335 def walkpat(pat): |
1306 srcs = [] | 1336 srcs = [] |
1307 if after: | 1337 if after: |
1308 badstates = '?' | 1338 badstates = b'?' |
1309 else: | 1339 else: |
1310 badstates = '?r' | 1340 badstates = b'?r' |
1311 m = scmutil.match(wctx, [pat], opts, globbed=True) | 1341 m = scmutil.match(wctx, [pat], opts, globbed=True) |
1312 for abs in wctx.walk(m): | 1342 for abs in wctx.walk(m): |
1313 state = repo.dirstate[abs] | 1343 state = repo.dirstate[abs] |
1314 rel = uipathfn(abs) | 1344 rel = uipathfn(abs) |
1315 exact = m.exact(abs) | 1345 exact = m.exact(abs) |
1316 if state in badstates: | 1346 if state in badstates: |
1317 if exact and state == '?': | 1347 if exact and state == b'?': |
1318 ui.warn(_('%s: not copying - file is not managed\n') % rel) | 1348 ui.warn(_(b'%s: not copying - file is not managed\n') % rel) |
1319 if exact and state == 'r': | 1349 if exact and state == b'r': |
1320 ui.warn( | 1350 ui.warn( |
1321 _( | 1351 _( |
1322 '%s: not copying - file has been marked for' | 1352 b'%s: not copying - file has been marked for' |
1323 ' remove\n' | 1353 b' remove\n' |
1324 ) | 1354 ) |
1325 % rel | 1355 % rel |
1326 ) | 1356 ) |
1327 continue | 1357 continue |
1328 # abs: hgsep | 1358 # abs: hgsep |
1333 # abssrc: hgsep | 1363 # abssrc: hgsep |
1334 # relsrc: ossep | 1364 # relsrc: ossep |
1335 # otarget: ossep | 1365 # otarget: ossep |
1336 def copyfile(abssrc, relsrc, otarget, exact): | 1366 def copyfile(abssrc, relsrc, otarget, exact): |
1337 abstarget = pathutil.canonpath(repo.root, cwd, otarget) | 1367 abstarget = pathutil.canonpath(repo.root, cwd, otarget) |
1338 if '/' in abstarget: | 1368 if b'/' in abstarget: |
1339 # We cannot normalize abstarget itself, this would prevent | 1369 # We cannot normalize abstarget itself, this would prevent |
1340 # case only renames, like a => A. | 1370 # case only renames, like a => A. |
1341 abspath, absname = abstarget.rsplit('/', 1) | 1371 abspath, absname = abstarget.rsplit(b'/', 1) |
1342 abstarget = repo.dirstate.normalize(abspath) + '/' + absname | 1372 abstarget = repo.dirstate.normalize(abspath) + b'/' + absname |
1343 reltarget = repo.pathto(abstarget, cwd) | 1373 reltarget = repo.pathto(abstarget, cwd) |
1344 target = repo.wjoin(abstarget) | 1374 target = repo.wjoin(abstarget) |
1345 src = repo.wjoin(abssrc) | 1375 src = repo.wjoin(abssrc) |
1346 state = repo.dirstate[abstarget] | 1376 state = repo.dirstate[abstarget] |
1347 | 1377 |
1349 | 1379 |
1350 # check for collisions | 1380 # check for collisions |
1351 prevsrc = targets.get(abstarget) | 1381 prevsrc = targets.get(abstarget) |
1352 if prevsrc is not None: | 1382 if prevsrc is not None: |
1353 ui.warn( | 1383 ui.warn( |
1354 _('%s: not overwriting - %s collides with %s\n') | 1384 _(b'%s: not overwriting - %s collides with %s\n') |
1355 % ( | 1385 % ( |
1356 reltarget, | 1386 reltarget, |
1357 repo.pathto(abssrc, cwd), | 1387 repo.pathto(abssrc, cwd), |
1358 repo.pathto(prevsrc, cwd), | 1388 repo.pathto(prevsrc, cwd), |
1359 ) | 1389 ) |
1366 if exists and abssrc != abstarget: | 1396 if exists and abssrc != abstarget: |
1367 if repo.dirstate.normalize(abssrc) == repo.dirstate.normalize( | 1397 if repo.dirstate.normalize(abssrc) == repo.dirstate.normalize( |
1368 abstarget | 1398 abstarget |
1369 ): | 1399 ): |
1370 if not rename: | 1400 if not rename: |
1371 ui.warn(_("%s: can't copy - same file\n") % reltarget) | 1401 ui.warn(_(b"%s: can't copy - same file\n") % reltarget) |
1372 return True # report a failure | 1402 return True # report a failure |
1373 exists = False | 1403 exists = False |
1374 samefile = True | 1404 samefile = True |
1375 | 1405 |
1376 if not after and exists or after and state in 'mn': | 1406 if not after and exists or after and state in b'mn': |
1377 if not opts['force']: | 1407 if not opts[b'force']: |
1378 if state in 'mn': | 1408 if state in b'mn': |
1379 msg = _('%s: not overwriting - file already committed\n') | 1409 msg = _(b'%s: not overwriting - file already committed\n') |
1380 if after: | 1410 if after: |
1381 flags = '--after --force' | 1411 flags = b'--after --force' |
1382 else: | 1412 else: |
1383 flags = '--force' | 1413 flags = b'--force' |
1384 if rename: | 1414 if rename: |
1385 hint = ( | 1415 hint = ( |
1386 _( | 1416 _( |
1387 "('hg rename %s' to replace the file by " | 1417 b"('hg rename %s' to replace the file by " |
1388 'recording a rename)\n' | 1418 b'recording a rename)\n' |
1389 ) | 1419 ) |
1390 % flags | 1420 % flags |
1391 ) | 1421 ) |
1392 else: | 1422 else: |
1393 hint = ( | 1423 hint = ( |
1394 _( | 1424 _( |
1395 "('hg copy %s' to replace the file by " | 1425 b"('hg copy %s' to replace the file by " |
1396 'recording a copy)\n' | 1426 b'recording a copy)\n' |
1397 ) | 1427 ) |
1398 % flags | 1428 % flags |
1399 ) | 1429 ) |
1400 else: | 1430 else: |
1401 msg = _('%s: not overwriting - file exists\n') | 1431 msg = _(b'%s: not overwriting - file exists\n') |
1402 if rename: | 1432 if rename: |
1403 hint = _("('hg rename --after' to record the rename)\n") | 1433 hint = _( |
1434 b"('hg rename --after' to record the rename)\n" | |
1435 ) | |
1404 else: | 1436 else: |
1405 hint = _("('hg copy --after' to record the copy)\n") | 1437 hint = _(b"('hg copy --after' to record the copy)\n") |
1406 ui.warn(msg % reltarget) | 1438 ui.warn(msg % reltarget) |
1407 ui.warn(hint) | 1439 ui.warn(hint) |
1408 return True # report a failure | 1440 return True # report a failure |
1409 | 1441 |
1410 if after: | 1442 if after: |
1411 if not exists: | 1443 if not exists: |
1412 if rename: | 1444 if rename: |
1413 ui.warn( | 1445 ui.warn( |
1414 _('%s: not recording move - %s does not exist\n') | 1446 _(b'%s: not recording move - %s does not exist\n') |
1415 % (relsrc, reltarget) | 1447 % (relsrc, reltarget) |
1416 ) | 1448 ) |
1417 else: | 1449 else: |
1418 ui.warn( | 1450 ui.warn( |
1419 _('%s: not recording copy - %s does not exist\n') | 1451 _(b'%s: not recording copy - %s does not exist\n') |
1420 % (relsrc, reltarget) | 1452 % (relsrc, reltarget) |
1421 ) | 1453 ) |
1422 return True # report a failure | 1454 return True # report a failure |
1423 elif not dryrun: | 1455 elif not dryrun: |
1424 try: | 1456 try: |
1425 if exists: | 1457 if exists: |
1426 os.unlink(target) | 1458 os.unlink(target) |
1427 targetdir = os.path.dirname(target) or '.' | 1459 targetdir = os.path.dirname(target) or b'.' |
1428 if not os.path.isdir(targetdir): | 1460 if not os.path.isdir(targetdir): |
1429 os.makedirs(targetdir) | 1461 os.makedirs(targetdir) |
1430 if samefile: | 1462 if samefile: |
1431 tmp = target + "~hgrename" | 1463 tmp = target + b"~hgrename" |
1432 os.rename(src, tmp) | 1464 os.rename(src, tmp) |
1433 os.rename(tmp, target) | 1465 os.rename(tmp, target) |
1434 else: | 1466 else: |
1435 # Preserve stat info on renames, not on copies; this matches | 1467 # Preserve stat info on renames, not on copies; this matches |
1436 # Linux CLI behavior. | 1468 # Linux CLI behavior. |
1437 util.copyfile(src, target, copystat=rename) | 1469 util.copyfile(src, target, copystat=rename) |
1438 srcexists = True | 1470 srcexists = True |
1439 except IOError as inst: | 1471 except IOError as inst: |
1440 if inst.errno == errno.ENOENT: | 1472 if inst.errno == errno.ENOENT: |
1441 ui.warn(_('%s: deleted in working directory\n') % relsrc) | 1473 ui.warn(_(b'%s: deleted in working directory\n') % relsrc) |
1442 srcexists = False | 1474 srcexists = False |
1443 else: | 1475 else: |
1444 ui.warn( | 1476 ui.warn( |
1445 _('%s: cannot copy - %s\n') | 1477 _(b'%s: cannot copy - %s\n') |
1446 % (relsrc, encoding.strtolocal(inst.strerror)) | 1478 % (relsrc, encoding.strtolocal(inst.strerror)) |
1447 ) | 1479 ) |
1448 return True # report a failure | 1480 return True # report a failure |
1449 | 1481 |
1450 if ui.verbose or not exact: | 1482 if ui.verbose or not exact: |
1451 if rename: | 1483 if rename: |
1452 ui.status(_('moving %s to %s\n') % (relsrc, reltarget)) | 1484 ui.status(_(b'moving %s to %s\n') % (relsrc, reltarget)) |
1453 else: | 1485 else: |
1454 ui.status(_('copying %s to %s\n') % (relsrc, reltarget)) | 1486 ui.status(_(b'copying %s to %s\n') % (relsrc, reltarget)) |
1455 | 1487 |
1456 targets[abstarget] = abssrc | 1488 targets[abstarget] = abssrc |
1457 | 1489 |
1458 # fix up dirstate | 1490 # fix up dirstate |
1459 scmutil.dirstatecopy( | 1491 scmutil.dirstatecopy( |
1460 ui, repo, wctx, abssrc, abstarget, dryrun=dryrun, cwd=cwd | 1492 ui, repo, wctx, abssrc, abstarget, dryrun=dryrun, cwd=cwd |
1461 ) | 1493 ) |
1462 if rename and not dryrun: | 1494 if rename and not dryrun: |
1463 if not after and srcexists and not samefile: | 1495 if not after and srcexists and not samefile: |
1464 rmdir = repo.ui.configbool('experimental', 'removeemptydirs') | 1496 rmdir = repo.ui.configbool(b'experimental', b'removeemptydirs') |
1465 repo.wvfs.unlinkpath(abssrc, rmdir=rmdir) | 1497 repo.wvfs.unlinkpath(abssrc, rmdir=rmdir) |
1466 wctx.forget([abssrc]) | 1498 wctx.forget([abssrc]) |
1467 | 1499 |
1468 # pat: ossep | 1500 # pat: ossep |
1469 # dest ossep | 1501 # dest ossep |
1533 res = lambda p: dest | 1565 res = lambda p: dest |
1534 return res | 1566 return res |
1535 | 1567 |
1536 pats = scmutil.expandpats(pats) | 1568 pats = scmutil.expandpats(pats) |
1537 if not pats: | 1569 if not pats: |
1538 raise error.Abort(_('no source or destination specified')) | 1570 raise error.Abort(_(b'no source or destination specified')) |
1539 if len(pats) == 1: | 1571 if len(pats) == 1: |
1540 raise error.Abort(_('no destination specified')) | 1572 raise error.Abort(_(b'no destination specified')) |
1541 dest = pats.pop() | 1573 dest = pats.pop() |
1542 destdirexists = os.path.isdir(dest) and not os.path.islink(dest) | 1574 destdirexists = os.path.isdir(dest) and not os.path.islink(dest) |
1543 if not destdirexists: | 1575 if not destdirexists: |
1544 if len(pats) > 1 or matchmod.patkind(pats[0]): | 1576 if len(pats) > 1 or matchmod.patkind(pats[0]): |
1545 raise error.Abort( | 1577 raise error.Abort( |
1546 _( | 1578 _( |
1547 'with multiple sources, destination must be an ' | 1579 b'with multiple sources, destination must be an ' |
1548 'existing directory' | 1580 b'existing directory' |
1549 ) | 1581 ) |
1550 ) | 1582 ) |
1551 if util.endswithsep(dest): | 1583 if util.endswithsep(dest): |
1552 raise error.Abort(_('destination %s is not a directory') % dest) | 1584 raise error.Abort(_(b'destination %s is not a directory') % dest) |
1553 | 1585 |
1554 tfn = targetpathfn | 1586 tfn = targetpathfn |
1555 if after: | 1587 if after: |
1556 tfn = targetpathafterfn | 1588 tfn = targetpathafterfn |
1557 copylist = [] | 1589 copylist = [] |
1559 srcs = walkpat(pat) | 1591 srcs = walkpat(pat) |
1560 if not srcs: | 1592 if not srcs: |
1561 continue | 1593 continue |
1562 copylist.append((tfn(pat, dest, srcs), srcs)) | 1594 copylist.append((tfn(pat, dest, srcs), srcs)) |
1563 if not copylist: | 1595 if not copylist: |
1564 raise error.Abort(_('no files to copy')) | 1596 raise error.Abort(_(b'no files to copy')) |
1565 | 1597 |
1566 errors = 0 | 1598 errors = 0 |
1567 for targetpath, srcs in copylist: | 1599 for targetpath, srcs in copylist: |
1568 for abssrc, relsrc, exact in srcs: | 1600 for abssrc, relsrc, exact in srcs: |
1569 if copyfile(abssrc, relsrc, targetpath(abssrc), exact): | 1601 if copyfile(abssrc, relsrc, targetpath(abssrc), exact): |
1613 updatefunc(<repo>, <node>) | 1645 updatefunc(<repo>, <node>) |
1614 """ | 1646 """ |
1615 # avoid cycle context -> subrepo -> cmdutil | 1647 # avoid cycle context -> subrepo -> cmdutil |
1616 from . import context | 1648 from . import context |
1617 | 1649 |
1618 tmpname = patchdata.get('filename') | 1650 tmpname = patchdata.get(b'filename') |
1619 message = patchdata.get('message') | 1651 message = patchdata.get(b'message') |
1620 user = opts.get('user') or patchdata.get('user') | 1652 user = opts.get(b'user') or patchdata.get(b'user') |
1621 date = opts.get('date') or patchdata.get('date') | 1653 date = opts.get(b'date') or patchdata.get(b'date') |
1622 branch = patchdata.get('branch') | 1654 branch = patchdata.get(b'branch') |
1623 nodeid = patchdata.get('nodeid') | 1655 nodeid = patchdata.get(b'nodeid') |
1624 p1 = patchdata.get('p1') | 1656 p1 = patchdata.get(b'p1') |
1625 p2 = patchdata.get('p2') | 1657 p2 = patchdata.get(b'p2') |
1626 | 1658 |
1627 nocommit = opts.get('no_commit') | 1659 nocommit = opts.get(b'no_commit') |
1628 importbranch = opts.get('import_branch') | 1660 importbranch = opts.get(b'import_branch') |
1629 update = not opts.get('bypass') | 1661 update = not opts.get(b'bypass') |
1630 strip = opts["strip"] | 1662 strip = opts[b"strip"] |
1631 prefix = opts["prefix"] | 1663 prefix = opts[b"prefix"] |
1632 sim = float(opts.get('similarity') or 0) | 1664 sim = float(opts.get(b'similarity') or 0) |
1633 | 1665 |
1634 if not tmpname: | 1666 if not tmpname: |
1635 return None, None, False | 1667 return None, None, False |
1636 | 1668 |
1637 rejects = False | 1669 rejects = False |
1644 # pickup the patch msg | 1676 # pickup the patch msg |
1645 message = message.strip() | 1677 message = message.strip() |
1646 else: | 1678 else: |
1647 # launch the editor | 1679 # launch the editor |
1648 message = None | 1680 message = None |
1649 ui.debug('message:\n%s\n' % (message or '')) | 1681 ui.debug(b'message:\n%s\n' % (message or b'')) |
1650 | 1682 |
1651 if len(parents) == 1: | 1683 if len(parents) == 1: |
1652 parents.append(repo[nullid]) | 1684 parents.append(repo[nullid]) |
1653 if opts.get('exact'): | 1685 if opts.get(b'exact'): |
1654 if not nodeid or not p1: | 1686 if not nodeid or not p1: |
1655 raise error.Abort(_('not a Mercurial patch')) | 1687 raise error.Abort(_(b'not a Mercurial patch')) |
1656 p1 = repo[p1] | 1688 p1 = repo[p1] |
1657 p2 = repo[p2 or nullid] | 1689 p2 = repo[p2 or nullid] |
1658 elif p2: | 1690 elif p2: |
1659 try: | 1691 try: |
1660 p1 = repo[p1] | 1692 p1 = repo[p1] |
1668 except error.RepoError: | 1700 except error.RepoError: |
1669 p1, p2 = parents | 1701 p1, p2 = parents |
1670 if p2.node() == nullid: | 1702 if p2.node() == nullid: |
1671 ui.warn( | 1703 ui.warn( |
1672 _( | 1704 _( |
1673 "warning: import the patch as a normal revision\n" | 1705 b"warning: import the patch as a normal revision\n" |
1674 "(use --exact to import the patch as a merge)\n" | 1706 b"(use --exact to import the patch as a merge)\n" |
1675 ) | 1707 ) |
1676 ) | 1708 ) |
1677 else: | 1709 else: |
1678 p1, p2 = parents | 1710 p1, p2 = parents |
1679 | 1711 |
1682 if p1 != parents[0]: | 1714 if p1 != parents[0]: |
1683 updatefunc(repo, p1.node()) | 1715 updatefunc(repo, p1.node()) |
1684 if p2 != parents[1]: | 1716 if p2 != parents[1]: |
1685 repo.setparents(p1.node(), p2.node()) | 1717 repo.setparents(p1.node(), p2.node()) |
1686 | 1718 |
1687 if opts.get('exact') or importbranch: | 1719 if opts.get(b'exact') or importbranch: |
1688 repo.dirstate.setbranch(branch or 'default') | 1720 repo.dirstate.setbranch(branch or b'default') |
1689 | 1721 |
1690 partial = opts.get('partial', False) | 1722 partial = opts.get(b'partial', False) |
1691 files = set() | 1723 files = set() |
1692 try: | 1724 try: |
1693 patch.patch( | 1725 patch.patch( |
1694 ui, | 1726 ui, |
1695 repo, | 1727 repo, |
1709 files = list(files) | 1741 files = list(files) |
1710 if nocommit: | 1742 if nocommit: |
1711 if message: | 1743 if message: |
1712 msgs.append(message) | 1744 msgs.append(message) |
1713 else: | 1745 else: |
1714 if opts.get('exact') or p2: | 1746 if opts.get(b'exact') or p2: |
1715 # If you got here, you either use --force and know what | 1747 # If you got here, you either use --force and know what |
1716 # you are doing or used --exact or a merge patch while | 1748 # you are doing or used --exact or a merge patch while |
1717 # being updated to its first parent. | 1749 # being updated to its first parent. |
1718 m = None | 1750 m = None |
1719 else: | 1751 else: |
1720 m = scmutil.matchfiles(repo, files or []) | 1752 m = scmutil.matchfiles(repo, files or []) |
1721 editform = mergeeditform(repo[None], 'import.normal') | 1753 editform = mergeeditform(repo[None], b'import.normal') |
1722 if opts.get('exact'): | 1754 if opts.get(b'exact'): |
1723 editor = None | 1755 editor = None |
1724 else: | 1756 else: |
1725 editor = getcommiteditor( | 1757 editor = getcommiteditor( |
1726 editform=editform, **pycompat.strkwargs(opts) | 1758 editform=editform, **pycompat.strkwargs(opts) |
1727 ) | 1759 ) |
1728 extra = {} | 1760 extra = {} |
1729 for idfunc in extrapreimport: | 1761 for idfunc in extrapreimport: |
1730 extrapreimportmap[idfunc](repo, patchdata, extra, opts) | 1762 extrapreimportmap[idfunc](repo, patchdata, extra, opts) |
1731 overrides = {} | 1763 overrides = {} |
1732 if partial: | 1764 if partial: |
1733 overrides[('ui', 'allowemptycommit')] = True | 1765 overrides[(b'ui', b'allowemptycommit')] = True |
1734 with repo.ui.configoverride(overrides, 'import'): | 1766 with repo.ui.configoverride(overrides, b'import'): |
1735 n = repo.commit( | 1767 n = repo.commit( |
1736 message, user, date, match=m, editor=editor, extra=extra | 1768 message, user, date, match=m, editor=editor, extra=extra |
1737 ) | 1769 ) |
1738 for idfunc in extrapostimport: | 1770 for idfunc in extrapostimport: |
1739 extrapostimportmap[idfunc](repo[n]) | 1771 extrapostimportmap[idfunc](repo[n]) |
1740 else: | 1772 else: |
1741 if opts.get('exact') or importbranch: | 1773 if opts.get(b'exact') or importbranch: |
1742 branch = branch or 'default' | 1774 branch = branch or b'default' |
1743 else: | 1775 else: |
1744 branch = p1.branch() | 1776 branch = p1.branch() |
1745 store = patch.filestore() | 1777 store = patch.filestore() |
1746 try: | 1778 try: |
1747 files = set() | 1779 files = set() |
1757 files, | 1789 files, |
1758 eolmode=None, | 1790 eolmode=None, |
1759 ) | 1791 ) |
1760 except error.PatchError as e: | 1792 except error.PatchError as e: |
1761 raise error.Abort(stringutil.forcebytestr(e)) | 1793 raise error.Abort(stringutil.forcebytestr(e)) |
1762 if opts.get('exact'): | 1794 if opts.get(b'exact'): |
1763 editor = None | 1795 editor = None |
1764 else: | 1796 else: |
1765 editor = getcommiteditor(editform='import.bypass') | 1797 editor = getcommiteditor(editform=b'import.bypass') |
1766 memctx = context.memctx( | 1798 memctx = context.memctx( |
1767 repo, | 1799 repo, |
1768 (p1.node(), p2.node()), | 1800 (p1.node(), p2.node()), |
1769 message, | 1801 message, |
1770 files=files, | 1802 files=files, |
1775 editor=editor, | 1807 editor=editor, |
1776 ) | 1808 ) |
1777 n = memctx.commit() | 1809 n = memctx.commit() |
1778 finally: | 1810 finally: |
1779 store.close() | 1811 store.close() |
1780 if opts.get('exact') and nocommit: | 1812 if opts.get(b'exact') and nocommit: |
1781 # --exact with --no-commit is still useful in that it does merge | 1813 # --exact with --no-commit is still useful in that it does merge |
1782 # and branch bits | 1814 # and branch bits |
1783 ui.warn(_("warning: can't check exact import with --no-commit\n")) | 1815 ui.warn(_(b"warning: can't check exact import with --no-commit\n")) |
1784 elif opts.get('exact') and (not n or hex(n) != nodeid): | 1816 elif opts.get(b'exact') and (not n or hex(n) != nodeid): |
1785 raise error.Abort(_('patch is damaged or loses information')) | 1817 raise error.Abort(_(b'patch is damaged or loses information')) |
1786 msg = _('applied to working directory') | 1818 msg = _(b'applied to working directory') |
1787 if n: | 1819 if n: |
1788 # i18n: refers to a short changeset id | 1820 # i18n: refers to a short changeset id |
1789 msg = _('created %s') % short(n) | 1821 msg = _(b'created %s') % short(n) |
1790 return msg, n, rejects | 1822 return msg, n, rejects |
1791 | 1823 |
1792 | 1824 |
1793 # facility to let extensions include additional data in an exported patch | 1825 # facility to let extensions include additional data in an exported patch |
1794 # list of identifiers to be executed in order | 1826 # list of identifiers to be executed in order |
1810 prev = parents[0] | 1842 prev = parents[0] |
1811 else: | 1843 else: |
1812 prev = nullid | 1844 prev = nullid |
1813 | 1845 |
1814 fm.context(ctx=ctx) | 1846 fm.context(ctx=ctx) |
1815 fm.plain('# HG changeset patch\n') | 1847 fm.plain(b'# HG changeset patch\n') |
1816 fm.write('user', '# User %s\n', ctx.user()) | 1848 fm.write(b'user', b'# User %s\n', ctx.user()) |
1817 fm.plain('# Date %d %d\n' % ctx.date()) | 1849 fm.plain(b'# Date %d %d\n' % ctx.date()) |
1818 fm.write('date', '# %s\n', fm.formatdate(ctx.date())) | 1850 fm.write(b'date', b'# %s\n', fm.formatdate(ctx.date())) |
1819 fm.condwrite( | 1851 fm.condwrite( |
1820 branch and branch != 'default', 'branch', '# Branch %s\n', branch | 1852 branch and branch != b'default', b'branch', b'# Branch %s\n', branch |
1821 ) | 1853 ) |
1822 fm.write('node', '# Node ID %s\n', hex(node)) | 1854 fm.write(b'node', b'# Node ID %s\n', hex(node)) |
1823 fm.plain('# Parent %s\n' % hex(prev)) | 1855 fm.plain(b'# Parent %s\n' % hex(prev)) |
1824 if len(parents) > 1: | 1856 if len(parents) > 1: |
1825 fm.plain('# Parent %s\n' % hex(parents[1])) | 1857 fm.plain(b'# Parent %s\n' % hex(parents[1])) |
1826 fm.data(parents=fm.formatlist(pycompat.maplist(hex, parents), name='node')) | 1858 fm.data(parents=fm.formatlist(pycompat.maplist(hex, parents), name=b'node')) |
1827 | 1859 |
1828 # TODO: redesign extraexportmap function to support formatter | 1860 # TODO: redesign extraexportmap function to support formatter |
1829 for headerid in extraexport: | 1861 for headerid in extraexport: |
1830 header = extraexportmap[headerid](seqno, ctx) | 1862 header = extraexportmap[headerid](seqno, ctx) |
1831 if header is not None: | 1863 if header is not None: |
1832 fm.plain('# %s\n' % header) | 1864 fm.plain(b'# %s\n' % header) |
1833 | 1865 |
1834 fm.write('desc', '%s\n', ctx.description().rstrip()) | 1866 fm.write(b'desc', b'%s\n', ctx.description().rstrip()) |
1835 fm.plain('\n') | 1867 fm.plain(b'\n') |
1836 | 1868 |
1837 if fm.isplain(): | 1869 if fm.isplain(): |
1838 chunkiter = patch.diffui(repo, prev, node, match, opts=diffopts) | 1870 chunkiter = patch.diffui(repo, prev, node, match, opts=diffopts) |
1839 for chunk, label in chunkiter: | 1871 for chunk, label in chunkiter: |
1840 fm.plain(chunk, label=label) | 1872 fm.plain(chunk, label=label) |
1846 | 1878 |
1847 def _exportfile(repo, revs, fm, dest, switch_parent, diffopts, match): | 1879 def _exportfile(repo, revs, fm, dest, switch_parent, diffopts, match): |
1848 """Export changesets to stdout or a single file""" | 1880 """Export changesets to stdout or a single file""" |
1849 for seqno, rev in enumerate(revs, 1): | 1881 for seqno, rev in enumerate(revs, 1): |
1850 ctx = repo[rev] | 1882 ctx = repo[rev] |
1851 if not dest.startswith('<'): | 1883 if not dest.startswith(b'<'): |
1852 repo.ui.note("%s\n" % dest) | 1884 repo.ui.note(b"%s\n" % dest) |
1853 fm.startitem() | 1885 fm.startitem() |
1854 _exportsingle(repo, ctx, fm, match, switch_parent, seqno, diffopts) | 1886 _exportsingle(repo, ctx, fm, match, switch_parent, seqno, diffopts) |
1855 | 1887 |
1856 | 1888 |
1857 def _exportfntemplate( | 1889 def _exportfntemplate( |
1869 ) | 1901 ) |
1870 filemap.setdefault(dest, []).append((seqno, rev)) | 1902 filemap.setdefault(dest, []).append((seqno, rev)) |
1871 | 1903 |
1872 for dest in filemap: | 1904 for dest in filemap: |
1873 with formatter.maybereopen(basefm, dest) as fm: | 1905 with formatter.maybereopen(basefm, dest) as fm: |
1874 repo.ui.note("%s\n" % dest) | 1906 repo.ui.note(b"%s\n" % dest) |
1875 for seqno, rev in filemap[dest]: | 1907 for seqno, rev in filemap[dest]: |
1876 fm.startitem() | 1908 fm.startitem() |
1877 ctx = repo[rev] | 1909 ctx = repo[rev] |
1878 _exportsingle( | 1910 _exportsingle( |
1879 repo, ctx, fm, match, switch_parent, seqno, diffopts | 1911 repo, ctx, fm, match, switch_parent, seqno, diffopts |
1891 | 1923 |
1892 def export( | 1924 def export( |
1893 repo, | 1925 repo, |
1894 revs, | 1926 revs, |
1895 basefm, | 1927 basefm, |
1896 fntemplate='hg-%h.patch', | 1928 fntemplate=b'hg-%h.patch', |
1897 switch_parent=False, | 1929 switch_parent=False, |
1898 opts=None, | 1930 opts=None, |
1899 match=None, | 1931 match=None, |
1900 ): | 1932 ): |
1901 '''export changesets as hg patches | 1933 '''export changesets as hg patches |
1921 Otherwise: All revs will be written to basefm. | 1953 Otherwise: All revs will be written to basefm. |
1922 ''' | 1954 ''' |
1923 _prefetchchangedfiles(repo, revs, match) | 1955 _prefetchchangedfiles(repo, revs, match) |
1924 | 1956 |
1925 if not fntemplate: | 1957 if not fntemplate: |
1926 _exportfile(repo, revs, basefm, '<unnamed>', switch_parent, opts, match) | 1958 _exportfile( |
1959 repo, revs, basefm, b'<unnamed>', switch_parent, opts, match | |
1960 ) | |
1927 else: | 1961 else: |
1928 _exportfntemplate( | 1962 _exportfntemplate( |
1929 repo, revs, basefm, fntemplate, switch_parent, opts, match | 1963 repo, revs, basefm, fntemplate, switch_parent, opts, match |
1930 ) | 1964 ) |
1931 | 1965 |
1932 | 1966 |
1933 def exportfile(repo, revs, fp, switch_parent=False, opts=None, match=None): | 1967 def exportfile(repo, revs, fp, switch_parent=False, opts=None, match=None): |
1934 """Export changesets to the given file stream""" | 1968 """Export changesets to the given file stream""" |
1935 _prefetchchangedfiles(repo, revs, match) | 1969 _prefetchchangedfiles(repo, revs, match) |
1936 | 1970 |
1937 dest = getattr(fp, 'name', '<unnamed>') | 1971 dest = getattr(fp, 'name', b'<unnamed>') |
1938 with formatter.formatter(repo.ui, fp, 'export', {}) as fm: | 1972 with formatter.formatter(repo.ui, fp, b'export', {}) as fm: |
1939 _exportfile(repo, revs, fm, dest, switch_parent, opts, match) | 1973 _exportfile(repo, revs, fm, dest, switch_parent, opts, match) |
1940 | 1974 |
1941 | 1975 |
1942 def showmarker(fm, marker, index=None): | 1976 def showmarker(fm, marker, index=None): |
1943 """utility function to display obsolescence marker in a readable way | 1977 """utility function to display obsolescence marker in a readable way |
1944 | 1978 |
1945 To be used by debug function.""" | 1979 To be used by debug function.""" |
1946 if index is not None: | 1980 if index is not None: |
1947 fm.write('index', '%i ', index) | 1981 fm.write(b'index', b'%i ', index) |
1948 fm.write('prednode', '%s ', hex(marker.prednode())) | 1982 fm.write(b'prednode', b'%s ', hex(marker.prednode())) |
1949 succs = marker.succnodes() | 1983 succs = marker.succnodes() |
1950 fm.condwrite( | 1984 fm.condwrite( |
1951 succs, 'succnodes', '%s ', fm.formatlist(map(hex, succs), name='node') | 1985 succs, |
1986 b'succnodes', | |
1987 b'%s ', | |
1988 fm.formatlist(map(hex, succs), name=b'node'), | |
1952 ) | 1989 ) |
1953 fm.write('flag', '%X ', marker.flags()) | 1990 fm.write(b'flag', b'%X ', marker.flags()) |
1954 parents = marker.parentnodes() | 1991 parents = marker.parentnodes() |
1955 if parents is not None: | 1992 if parents is not None: |
1956 fm.write( | 1993 fm.write( |
1957 'parentnodes', | 1994 b'parentnodes', |
1958 '{%s} ', | 1995 b'{%s} ', |
1959 fm.formatlist(map(hex, parents), name='node', sep=', '), | 1996 fm.formatlist(map(hex, parents), name=b'node', sep=b', '), |
1960 ) | 1997 ) |
1961 fm.write('date', '(%s) ', fm.formatdate(marker.date())) | 1998 fm.write(b'date', b'(%s) ', fm.formatdate(marker.date())) |
1962 meta = marker.metadata().copy() | 1999 meta = marker.metadata().copy() |
1963 meta.pop('date', None) | 2000 meta.pop(b'date', None) |
1964 smeta = pycompat.rapply(pycompat.maybebytestr, meta) | 2001 smeta = pycompat.rapply(pycompat.maybebytestr, meta) |
1965 fm.write('metadata', '{%s}', fm.formatdict(smeta, fmt='%r: %r', sep=', ')) | 2002 fm.write( |
1966 fm.plain('\n') | 2003 b'metadata', b'{%s}', fm.formatdict(smeta, fmt=b'%r: %r', sep=b', ') |
2004 ) | |
2005 fm.plain(b'\n') | |
1967 | 2006 |
1968 | 2007 |
1969 def finddate(ui, repo, date): | 2008 def finddate(ui, repo, date): |
1970 """Find the tipmost changeset that matches the given date spec""" | 2009 """Find the tipmost changeset that matches the given date spec""" |
1971 | 2010 |
1976 def prep(ctx, fns): | 2015 def prep(ctx, fns): |
1977 d = ctx.date() | 2016 d = ctx.date() |
1978 if df(d[0]): | 2017 if df(d[0]): |
1979 results[ctx.rev()] = d | 2018 results[ctx.rev()] = d |
1980 | 2019 |
1981 for ctx in walkchangerevs(repo, m, {'rev': None}, prep): | 2020 for ctx in walkchangerevs(repo, m, {b'rev': None}, prep): |
1982 rev = ctx.rev() | 2021 rev = ctx.rev() |
1983 if rev in results: | 2022 if rev in results: |
1984 ui.status( | 2023 ui.status( |
1985 _("found revision %s from %s\n") | 2024 _(b"found revision %s from %s\n") |
1986 % (rev, dateutil.datestr(results[rev])) | 2025 % (rev, dateutil.datestr(results[rev])) |
1987 ) | 2026 ) |
1988 return '%d' % rev | 2027 return b'%d' % rev |
1989 | 2028 |
1990 raise error.Abort(_("revision matching date not found")) | 2029 raise error.Abort(_(b"revision matching date not found")) |
1991 | 2030 |
1992 | 2031 |
1993 def increasingwindows(windowsize=8, sizelimit=512): | 2032 def increasingwindows(windowsize=8, sizelimit=512): |
1994 while True: | 2033 while True: |
1995 yield windowsize | 2034 yield windowsize |
1998 | 2037 |
1999 | 2038 |
2000 def _walkrevs(repo, opts): | 2039 def _walkrevs(repo, opts): |
2001 # Default --rev value depends on --follow but --follow behavior | 2040 # Default --rev value depends on --follow but --follow behavior |
2002 # depends on revisions resolved from --rev... | 2041 # depends on revisions resolved from --rev... |
2003 follow = opts.get('follow') or opts.get('follow_first') | 2042 follow = opts.get(b'follow') or opts.get(b'follow_first') |
2004 if opts.get('rev'): | 2043 if opts.get(b'rev'): |
2005 revs = scmutil.revrange(repo, opts['rev']) | 2044 revs = scmutil.revrange(repo, opts[b'rev']) |
2006 elif follow and repo.dirstate.p1() == nullid: | 2045 elif follow and repo.dirstate.p1() == nullid: |
2007 revs = smartset.baseset() | 2046 revs = smartset.baseset() |
2008 elif follow: | 2047 elif follow: |
2009 revs = repo.revs('reverse(:.)') | 2048 revs = repo.revs(b'reverse(:.)') |
2010 else: | 2049 else: |
2011 revs = smartset.spanset(repo) | 2050 revs = smartset.spanset(repo) |
2012 revs.reverse() | 2051 revs.reverse() |
2013 return revs | 2052 return revs |
2014 | 2053 |
2058 ) | 2097 ) |
2059 | 2098 |
2060 return reversed(revs) | 2099 return reversed(revs) |
2061 | 2100 |
2062 def iterfiles(): | 2101 def iterfiles(): |
2063 pctx = repo['.'] | 2102 pctx = repo[b'.'] |
2064 for filename in match.files(): | 2103 for filename in match.files(): |
2065 if follow: | 2104 if follow: |
2066 if filename not in pctx: | 2105 if filename not in pctx: |
2067 raise error.Abort( | 2106 raise error.Abort( |
2068 _('cannot follow file not in parent ' 'revision: "%s"') | 2107 _( |
2108 b'cannot follow file not in parent ' | |
2109 b'revision: "%s"' | |
2110 ) | |
2069 % filename | 2111 % filename |
2070 ) | 2112 ) |
2071 yield filename, pctx[filename].filenode() | 2113 yield filename, pctx[filename].filenode() |
2072 else: | 2114 else: |
2073 yield filename, None | 2115 yield filename, None |
2080 if node is None: | 2122 if node is None: |
2081 # A zero count may be a directory or deleted file, so | 2123 # A zero count may be a directory or deleted file, so |
2082 # try to find matching entries on the slow path. | 2124 # try to find matching entries on the slow path. |
2083 if follow: | 2125 if follow: |
2084 raise error.Abort( | 2126 raise error.Abort( |
2085 _('cannot follow nonexistent file: "%s"') % file_ | 2127 _(b'cannot follow nonexistent file: "%s"') % file_ |
2086 ) | 2128 ) |
2087 raise FileWalkError("Cannot walk via filelog") | 2129 raise FileWalkError(b"Cannot walk via filelog") |
2088 else: | 2130 else: |
2089 continue | 2131 continue |
2090 | 2132 |
2091 if node is None: | 2133 if node is None: |
2092 last = len(filelog) - 1 | 2134 last = len(filelog) - 1 |
2174 | 2216 |
2175 This function returns an iterator yielding contexts. Before | 2217 This function returns an iterator yielding contexts. Before |
2176 yielding each context, the iterator will first call the prepare | 2218 yielding each context, the iterator will first call the prepare |
2177 function on each context in the window in forward order.''' | 2219 function on each context in the window in forward order.''' |
2178 | 2220 |
2179 allfiles = opts.get('all_files') | 2221 allfiles = opts.get(b'all_files') |
2180 follow = opts.get('follow') or opts.get('follow_first') | 2222 follow = opts.get(b'follow') or opts.get(b'follow_first') |
2181 revs = _walkrevs(repo, opts) | 2223 revs = _walkrevs(repo, opts) |
2182 if not revs: | 2224 if not revs: |
2183 return [] | 2225 return [] |
2184 wanted = set() | 2226 wanted = set() |
2185 slowpath = match.anypats() or (not match.always() and opts.get('removed')) | 2227 slowpath = match.anypats() or (not match.always() and opts.get(b'removed')) |
2186 fncache = {} | 2228 fncache = {} |
2187 change = repo.__getitem__ | 2229 change = repo.__getitem__ |
2188 | 2230 |
2189 # First step is to fill wanted, the set of revisions that we want to yield. | 2231 # First step is to fill wanted, the set of revisions that we want to yield. |
2190 # When it does not induce extra cost, we also fill fncache for revisions in | 2232 # When it does not induce extra cost, we also fill fncache for revisions in |
2204 | 2246 |
2205 # We decided to fall back to the slowpath because at least one | 2247 # We decided to fall back to the slowpath because at least one |
2206 # of the paths was not a file. Check to see if at least one of them | 2248 # of the paths was not a file. Check to see if at least one of them |
2207 # existed in history, otherwise simply return | 2249 # existed in history, otherwise simply return |
2208 for path in match.files(): | 2250 for path in match.files(): |
2209 if path == '.' or path in repo.store: | 2251 if path == b'.' or path in repo.store: |
2210 break | 2252 break |
2211 else: | 2253 else: |
2212 return [] | 2254 return [] |
2213 | 2255 |
2214 if slowpath: | 2256 if slowpath: |
2215 # We have to read the changelog to match filenames against | 2257 # We have to read the changelog to match filenames against |
2216 # changed files | 2258 # changed files |
2217 | 2259 |
2218 if follow: | 2260 if follow: |
2219 raise error.Abort( | 2261 raise error.Abort( |
2220 _('can only follow copies/renames for explicit ' 'filenames') | 2262 _(b'can only follow copies/renames for explicit ' b'filenames') |
2221 ) | 2263 ) |
2222 | 2264 |
2223 # The slow path checks files modified in every changeset. | 2265 # The slow path checks files modified in every changeset. |
2224 # This is really slow on large repos, so compute the set lazily. | 2266 # This is really slow on large repos, so compute the set lazily. |
2225 class lazywantedset(object): | 2267 class lazywantedset(object): |
2253 | 2295 |
2254 wanted = lazywantedset() | 2296 wanted = lazywantedset() |
2255 | 2297 |
2256 # it might be worthwhile to do this in the iterator if the rev range | 2298 # it might be worthwhile to do this in the iterator if the rev range |
2257 # is descending and the prune args are all within that range | 2299 # is descending and the prune args are all within that range |
2258 for rev in opts.get('prune', ()): | 2300 for rev in opts.get(b'prune', ()): |
2259 rev = repo[rev].rev() | 2301 rev = repo[rev].rev() |
2260 ff = _followfilter(repo) | 2302 ff = _followfilter(repo) |
2261 stop = min(revs[0], revs[-1]) | 2303 stop = min(revs[0], revs[-1]) |
2262 for x in pycompat.xrange(rev, stop - 1, -1): | 2304 for x in pycompat.xrange(rev, stop - 1, -1): |
2263 if ff.match(x): | 2305 if ff.match(x): |
2265 | 2307 |
2266 # Now that wanted is correctly initialized, we can iterate over the | 2308 # Now that wanted is correctly initialized, we can iterate over the |
2267 # revision range, yielding only revisions in wanted. | 2309 # revision range, yielding only revisions in wanted. |
2268 def iterate(): | 2310 def iterate(): |
2269 if follow and match.always(): | 2311 if follow and match.always(): |
2270 ff = _followfilter(repo, onlyfirst=opts.get('follow_first')) | 2312 ff = _followfilter(repo, onlyfirst=opts.get(b'follow_first')) |
2271 | 2313 |
2272 def want(rev): | 2314 def want(rev): |
2273 return ff.match(rev) and rev in wanted | 2315 return ff.match(rev) and rev in wanted |
2274 | 2316 |
2275 else: | 2317 else: |
2343 if cca: | 2385 if cca: |
2344 cca(f) | 2386 cca(f) |
2345 names.append(f) | 2387 names.append(f) |
2346 if ui.verbose or not exact: | 2388 if ui.verbose or not exact: |
2347 ui.status( | 2389 ui.status( |
2348 _('adding %s\n') % uipathfn(f), label='ui.addremove.added' | 2390 _(b'adding %s\n') % uipathfn(f), label=b'ui.addremove.added' |
2349 ) | 2391 ) |
2350 | 2392 |
2351 for subpath in sorted(wctx.substate): | 2393 for subpath in sorted(wctx.substate): |
2352 sub = wctx.sub(subpath) | 2394 sub = wctx.sub(subpath) |
2353 try: | 2395 try: |
2362 bad.extend( | 2404 bad.extend( |
2363 sub.add(ui, submatch, subprefix, subuipathfn, True, **opts) | 2405 sub.add(ui, submatch, subprefix, subuipathfn, True, **opts) |
2364 ) | 2406 ) |
2365 except error.LookupError: | 2407 except error.LookupError: |
2366 ui.status( | 2408 ui.status( |
2367 _("skipping missing subrepository: %s\n") % uipathfn(subpath) | 2409 _(b"skipping missing subrepository: %s\n") % uipathfn(subpath) |
2368 ) | 2410 ) |
2369 | 2411 |
2370 if not opts.get(r'dry_run'): | 2412 if not opts.get(r'dry_run'): |
2371 rejected = wctx.add(names, prefix) | 2413 rejected = wctx.add(names, prefix) |
2372 bad.extend(f for f in rejected if f in match.files()) | 2414 bad.extend(f for f in rejected if f in match.files()) |
2373 return bad | 2415 return bad |
2374 | 2416 |
2375 | 2417 |
2376 def addwebdirpath(repo, serverpath, webconf): | 2418 def addwebdirpath(repo, serverpath, webconf): |
2377 webconf[serverpath] = repo.root | 2419 webconf[serverpath] = repo.root |
2378 repo.ui.debug('adding %s = %s\n' % (serverpath, repo.root)) | 2420 repo.ui.debug(b'adding %s = %s\n' % (serverpath, repo.root)) |
2379 | 2421 |
2380 for r in repo.revs('filelog("path:.hgsub")'): | 2422 for r in repo.revs(b'filelog("path:.hgsub")'): |
2381 ctx = repo[r] | 2423 ctx = repo[r] |
2382 for subpath in ctx.substate: | 2424 for subpath in ctx.substate: |
2383 ctx.sub(subpath).addwebdirpath(serverpath, webconf) | 2425 ctx.sub(subpath).addwebdirpath(serverpath, webconf) |
2384 | 2426 |
2385 | 2427 |
2386 def forget( | 2428 def forget( |
2387 ui, repo, match, prefix, uipathfn, explicitonly, dryrun, interactive | 2429 ui, repo, match, prefix, uipathfn, explicitonly, dryrun, interactive |
2388 ): | 2430 ): |
2389 if dryrun and interactive: | 2431 if dryrun and interactive: |
2390 raise error.Abort(_("cannot specify both --dry-run and --interactive")) | 2432 raise error.Abort(_(b"cannot specify both --dry-run and --interactive")) |
2391 bad = [] | 2433 bad = [] |
2392 badfn = lambda x, y: bad.append(x) or match.bad(x, y) | 2434 badfn = lambda x, y: bad.append(x) or match.bad(x, y) |
2393 wctx = repo[None] | 2435 wctx = repo[None] |
2394 forgot = [] | 2436 forgot = [] |
2395 | 2437 |
2409 subprefix, | 2451 subprefix, |
2410 subuipathfn, | 2452 subuipathfn, |
2411 dryrun=dryrun, | 2453 dryrun=dryrun, |
2412 interactive=interactive, | 2454 interactive=interactive, |
2413 ) | 2455 ) |
2414 bad.extend([subpath + '/' + f for f in subbad]) | 2456 bad.extend([subpath + b'/' + f for f in subbad]) |
2415 forgot.extend([subpath + '/' + f for f in subforgot]) | 2457 forgot.extend([subpath + b'/' + f for f in subforgot]) |
2416 except error.LookupError: | 2458 except error.LookupError: |
2417 ui.status( | 2459 ui.status( |
2418 _("skipping missing subrepository: %s\n") % uipathfn(subpath) | 2460 _(b"skipping missing subrepository: %s\n") % uipathfn(subpath) |
2419 ) | 2461 ) |
2420 | 2462 |
2421 if not explicitonly: | 2463 if not explicitonly: |
2422 for f in match.files(): | 2464 for f in match.files(): |
2423 if f not in repo.dirstate and not repo.wvfs.isdir(f): | 2465 if f not in repo.dirstate and not repo.wvfs.isdir(f): |
2428 # that subrepo files aren't normalized, and this op is | 2470 # that subrepo files aren't normalized, and this op is |
2429 # purely from data cached by the status walk above. | 2471 # purely from data cached by the status walk above. |
2430 if repo.dirstate.normalize(f) in repo.dirstate: | 2472 if repo.dirstate.normalize(f) in repo.dirstate: |
2431 continue | 2473 continue |
2432 ui.warn( | 2474 ui.warn( |
2433 _('not removing %s: ' 'file is already untracked\n') | 2475 _( |
2476 b'not removing %s: ' | |
2477 b'file is already untracked\n' | |
2478 ) | |
2434 % uipathfn(f) | 2479 % uipathfn(f) |
2435 ) | 2480 ) |
2436 bad.append(f) | 2481 bad.append(f) |
2437 | 2482 |
2438 if interactive: | 2483 if interactive: |
2439 responses = _( | 2484 responses = _( |
2440 '[Ynsa?]' | 2485 b'[Ynsa?]' |
2441 '$$ &Yes, forget this file' | 2486 b'$$ &Yes, forget this file' |
2442 '$$ &No, skip this file' | 2487 b'$$ &No, skip this file' |
2443 '$$ &Skip remaining files' | 2488 b'$$ &Skip remaining files' |
2444 '$$ Include &all remaining files' | 2489 b'$$ Include &all remaining files' |
2445 '$$ &? (display help)' | 2490 b'$$ &? (display help)' |
2446 ) | 2491 ) |
2447 for filename in forget[:]: | 2492 for filename in forget[:]: |
2448 r = ui.promptchoice( | 2493 r = ui.promptchoice( |
2449 _('forget %s %s') % (uipathfn(filename), responses) | 2494 _(b'forget %s %s') % (uipathfn(filename), responses) |
2450 ) | 2495 ) |
2451 if r == 4: # ? | 2496 if r == 4: # ? |
2452 while r == 4: | 2497 while r == 4: |
2453 for c, t in ui.extractchoices(responses)[1]: | 2498 for c, t in ui.extractchoices(responses)[1]: |
2454 ui.write('%s - %s\n' % (c, encoding.lower(t))) | 2499 ui.write(b'%s - %s\n' % (c, encoding.lower(t))) |
2455 r = ui.promptchoice( | 2500 r = ui.promptchoice( |
2456 _('forget %s %s') % (uipathfn(filename), responses) | 2501 _(b'forget %s %s') % (uipathfn(filename), responses) |
2457 ) | 2502 ) |
2458 if r == 0: # yes | 2503 if r == 0: # yes |
2459 continue | 2504 continue |
2460 elif r == 1: # no | 2505 elif r == 1: # no |
2461 forget.remove(filename) | 2506 forget.remove(filename) |
2467 break | 2512 break |
2468 | 2513 |
2469 for f in forget: | 2514 for f in forget: |
2470 if ui.verbose or not match.exact(f) or interactive: | 2515 if ui.verbose or not match.exact(f) or interactive: |
2471 ui.status( | 2516 ui.status( |
2472 _('removing %s\n') % uipathfn(f), label='ui.addremove.removed' | 2517 _(b'removing %s\n') % uipathfn(f), label=b'ui.addremove.removed' |
2473 ) | 2518 ) |
2474 | 2519 |
2475 if not dryrun: | 2520 if not dryrun: |
2476 rejected = wctx.forget(forget, prefix) | 2521 rejected = wctx.forget(forget, prefix) |
2477 bad.extend(f for f in rejected if f in match.files()) | 2522 bad.extend(f for f in rejected if f in match.files()) |
2480 | 2525 |
2481 | 2526 |
2482 def files(ui, ctx, m, uipathfn, fm, fmt, subrepos): | 2527 def files(ui, ctx, m, uipathfn, fm, fmt, subrepos): |
2483 ret = 1 | 2528 ret = 1 |
2484 | 2529 |
2485 needsfctx = ui.verbose or {'size', 'flags'} & fm.datahint() | 2530 needsfctx = ui.verbose or {b'size', b'flags'} & fm.datahint() |
2486 for f in ctx.matches(m): | 2531 for f in ctx.matches(m): |
2487 fm.startitem() | 2532 fm.startitem() |
2488 fm.context(ctx=ctx) | 2533 fm.context(ctx=ctx) |
2489 if needsfctx: | 2534 if needsfctx: |
2490 fc = ctx[f] | 2535 fc = ctx[f] |
2491 fm.write('size flags', '% 10d % 1s ', fc.size(), fc.flags()) | 2536 fm.write(b'size flags', b'% 10d % 1s ', fc.size(), fc.flags()) |
2492 fm.data(path=f) | 2537 fm.data(path=f) |
2493 fm.plain(fmt % uipathfn(f)) | 2538 fm.plain(fmt % uipathfn(f)) |
2494 ret = 0 | 2539 ret = 0 |
2495 | 2540 |
2496 for subpath in sorted(ctx.substate): | 2541 for subpath in sorted(ctx.substate): |
2505 == 0 | 2550 == 0 |
2506 ): | 2551 ): |
2507 ret = 0 | 2552 ret = 0 |
2508 except error.LookupError: | 2553 except error.LookupError: |
2509 ui.status( | 2554 ui.status( |
2510 _("skipping missing subrepository: %s\n") | 2555 _(b"skipping missing subrepository: %s\n") |
2511 % uipathfn(subpath) | 2556 % uipathfn(subpath) |
2512 ) | 2557 ) |
2513 | 2558 |
2514 return ret | 2559 return ret |
2515 | 2560 |
2529 else: | 2574 else: |
2530 warn = False | 2575 warn = False |
2531 | 2576 |
2532 subs = sorted(wctx.substate) | 2577 subs = sorted(wctx.substate) |
2533 progress = ui.makeprogress( | 2578 progress = ui.makeprogress( |
2534 _('searching'), total=len(subs), unit=_('subrepos') | 2579 _(b'searching'), total=len(subs), unit=_(b'subrepos') |
2535 ) | 2580 ) |
2536 for subpath in subs: | 2581 for subpath in subs: |
2537 submatch = matchmod.subdirmatcher(subpath, m) | 2582 submatch = matchmod.subdirmatcher(subpath, m) |
2538 subprefix = repo.wvfs.reljoin(prefix, subpath) | 2583 subprefix = repo.wvfs.reljoin(prefix, subpath) |
2539 subuipathfn = scmutil.subdiruipathfn(subpath, uipathfn) | 2584 subuipathfn = scmutil.subdiruipathfn(subpath, uipathfn) |
2552 warnings, | 2597 warnings, |
2553 ): | 2598 ): |
2554 ret = 1 | 2599 ret = 1 |
2555 except error.LookupError: | 2600 except error.LookupError: |
2556 warnings.append( | 2601 warnings.append( |
2557 _("skipping missing subrepository: %s\n") | 2602 _(b"skipping missing subrepository: %s\n") |
2558 % uipathfn(subpath) | 2603 % uipathfn(subpath) |
2559 ) | 2604 ) |
2560 progress.complete() | 2605 progress.complete() |
2561 | 2606 |
2562 # warn about failure to delete explicit files/dirs | 2607 # warn about failure to delete explicit files/dirs |
2563 deleteddirs = util.dirs(deleted) | 2608 deleteddirs = util.dirs(deleted) |
2564 files = m.files() | 2609 files = m.files() |
2565 progress = ui.makeprogress(_('deleting'), total=len(files), unit=_('files')) | 2610 progress = ui.makeprogress( |
2611 _(b'deleting'), total=len(files), unit=_(b'files') | |
2612 ) | |
2566 for f in files: | 2613 for f in files: |
2567 | 2614 |
2568 def insubrepo(): | 2615 def insubrepo(): |
2569 for subpath in wctx.substate: | 2616 for subpath in wctx.substate: |
2570 if f.startswith(subpath + '/'): | 2617 if f.startswith(subpath + b'/'): |
2571 return True | 2618 return True |
2572 return False | 2619 return False |
2573 | 2620 |
2574 progress.increment() | 2621 progress.increment() |
2575 isdir = f in deleteddirs or wctx.hasdir(f) | 2622 isdir = f in deleteddirs or wctx.hasdir(f) |
2576 if f in repo.dirstate or isdir or f == '.' or insubrepo() or f in subs: | 2623 if f in repo.dirstate or isdir or f == b'.' or insubrepo() or f in subs: |
2577 continue | 2624 continue |
2578 | 2625 |
2579 if repo.wvfs.exists(f): | 2626 if repo.wvfs.exists(f): |
2580 if repo.wvfs.isdir(f): | 2627 if repo.wvfs.isdir(f): |
2581 warnings.append( | 2628 warnings.append( |
2582 _('not removing %s: no tracked files\n') % uipathfn(f) | 2629 _(b'not removing %s: no tracked files\n') % uipathfn(f) |
2583 ) | 2630 ) |
2584 else: | 2631 else: |
2585 warnings.append( | 2632 warnings.append( |
2586 _('not removing %s: file is untracked\n') % uipathfn(f) | 2633 _(b'not removing %s: file is untracked\n') % uipathfn(f) |
2587 ) | 2634 ) |
2588 # missing files will generate a warning elsewhere | 2635 # missing files will generate a warning elsewhere |
2589 ret = 1 | 2636 ret = 1 |
2590 progress.complete() | 2637 progress.complete() |
2591 | 2638 |
2593 list = modified + deleted + clean + added | 2640 list = modified + deleted + clean + added |
2594 elif after: | 2641 elif after: |
2595 list = deleted | 2642 list = deleted |
2596 remaining = modified + added + clean | 2643 remaining = modified + added + clean |
2597 progress = ui.makeprogress( | 2644 progress = ui.makeprogress( |
2598 _('skipping'), total=len(remaining), unit=_('files') | 2645 _(b'skipping'), total=len(remaining), unit=_(b'files') |
2599 ) | 2646 ) |
2600 for f in remaining: | 2647 for f in remaining: |
2601 progress.increment() | 2648 progress.increment() |
2602 if ui.verbose or (f in files): | 2649 if ui.verbose or (f in files): |
2603 warnings.append( | 2650 warnings.append( |
2604 _('not removing %s: file still exists\n') % uipathfn(f) | 2651 _(b'not removing %s: file still exists\n') % uipathfn(f) |
2605 ) | 2652 ) |
2606 ret = 1 | 2653 ret = 1 |
2607 progress.complete() | 2654 progress.complete() |
2608 else: | 2655 else: |
2609 list = deleted + clean | 2656 list = deleted + clean |
2610 progress = ui.makeprogress( | 2657 progress = ui.makeprogress( |
2611 _('skipping'), total=(len(modified) + len(added)), unit=_('files') | 2658 _(b'skipping'), total=(len(modified) + len(added)), unit=_(b'files') |
2612 ) | 2659 ) |
2613 for f in modified: | 2660 for f in modified: |
2614 progress.increment() | 2661 progress.increment() |
2615 warnings.append( | 2662 warnings.append( |
2616 _( | 2663 _( |
2617 'not removing %s: file is modified (use -f' | 2664 b'not removing %s: file is modified (use -f' |
2618 ' to force removal)\n' | 2665 b' to force removal)\n' |
2619 ) | 2666 ) |
2620 % uipathfn(f) | 2667 % uipathfn(f) |
2621 ) | 2668 ) |
2622 ret = 1 | 2669 ret = 1 |
2623 for f in added: | 2670 for f in added: |
2624 progress.increment() | 2671 progress.increment() |
2625 warnings.append( | 2672 warnings.append( |
2626 _( | 2673 _( |
2627 "not removing %s: file has been marked for add" | 2674 b"not removing %s: file has been marked for add" |
2628 " (use 'hg forget' to undo add)\n" | 2675 b" (use 'hg forget' to undo add)\n" |
2629 ) | 2676 ) |
2630 % uipathfn(f) | 2677 % uipathfn(f) |
2631 ) | 2678 ) |
2632 ret = 1 | 2679 ret = 1 |
2633 progress.complete() | 2680 progress.complete() |
2634 | 2681 |
2635 list = sorted(list) | 2682 list = sorted(list) |
2636 progress = ui.makeprogress(_('deleting'), total=len(list), unit=_('files')) | 2683 progress = ui.makeprogress( |
2684 _(b'deleting'), total=len(list), unit=_(b'files') | |
2685 ) | |
2637 for f in list: | 2686 for f in list: |
2638 if ui.verbose or not m.exact(f): | 2687 if ui.verbose or not m.exact(f): |
2639 progress.increment() | 2688 progress.increment() |
2640 ui.status( | 2689 ui.status( |
2641 _('removing %s\n') % uipathfn(f), label='ui.addremove.removed' | 2690 _(b'removing %s\n') % uipathfn(f), label=b'ui.addremove.removed' |
2642 ) | 2691 ) |
2643 progress.complete() | 2692 progress.complete() |
2644 | 2693 |
2645 if not dryrun: | 2694 if not dryrun: |
2646 with repo.wlock(): | 2695 with repo.wlock(): |
2647 if not after: | 2696 if not after: |
2648 for f in list: | 2697 for f in list: |
2649 if f in added: | 2698 if f in added: |
2650 continue # we never unlink added files on remove | 2699 continue # we never unlink added files on remove |
2651 rmdir = repo.ui.configbool( | 2700 rmdir = repo.ui.configbool( |
2652 'experimental', 'removeemptydirs' | 2701 b'experimental', b'removeemptydirs' |
2653 ) | 2702 ) |
2654 repo.wvfs.unlinkpath(f, ignoremissing=True, rmdir=rmdir) | 2703 repo.wvfs.unlinkpath(f, ignoremissing=True, rmdir=rmdir) |
2655 repo[None].forget(list) | 2704 repo[None].forget(list) |
2656 | 2705 |
2657 if warn: | 2706 if warn: |
2660 | 2709 |
2661 return ret | 2710 return ret |
2662 | 2711 |
2663 | 2712 |
2664 def _catfmtneedsdata(fm): | 2713 def _catfmtneedsdata(fm): |
2665 return not fm.datahint() or 'data' in fm.datahint() | 2714 return not fm.datahint() or b'data' in fm.datahint() |
2666 | 2715 |
2667 | 2716 |
2668 def _updatecatformatter(fm, ctx, matcher, path, decode): | 2717 def _updatecatformatter(fm, ctx, matcher, path, decode): |
2669 """Hook for adding data to the formatter used by ``hg cat``. | 2718 """Hook for adding data to the formatter used by ``hg cat``. |
2670 | 2719 |
2678 data = ctx[path].data() | 2727 data = ctx[path].data() |
2679 if decode: | 2728 if decode: |
2680 data = ctx.repo().wwritedata(path, data) | 2729 data = ctx.repo().wwritedata(path, data) |
2681 fm.startitem() | 2730 fm.startitem() |
2682 fm.context(ctx=ctx) | 2731 fm.context(ctx=ctx) |
2683 fm.write('data', '%s', data) | 2732 fm.write(b'data', b'%s', data) |
2684 fm.data(path=path) | 2733 fm.data(path=path) |
2685 | 2734 |
2686 | 2735 |
2687 def cat(ui, repo, ctx, matcher, basefm, fntemplate, prefix, **opts): | 2736 def cat(ui, repo, ctx, matcher, basefm, fntemplate, prefix, **opts): |
2688 err = 1 | 2737 err = 1 |
2698 try: | 2747 try: |
2699 os.makedirs(os.path.dirname(filename)) | 2748 os.makedirs(os.path.dirname(filename)) |
2700 except OSError: | 2749 except OSError: |
2701 pass | 2750 pass |
2702 with formatter.maybereopen(basefm, filename) as fm: | 2751 with formatter.maybereopen(basefm, filename) as fm: |
2703 _updatecatformatter(fm, ctx, matcher, path, opts.get('decode')) | 2752 _updatecatformatter(fm, ctx, matcher, path, opts.get(b'decode')) |
2704 | 2753 |
2705 # Automation often uses hg cat on single files, so special case it | 2754 # Automation often uses hg cat on single files, so special case it |
2706 # for performance to avoid the cost of parsing the manifest. | 2755 # for performance to avoid the cost of parsing the manifest. |
2707 if len(matcher.files()) == 1 and not matcher.anypats(): | 2756 if len(matcher.files()) == 1 and not matcher.anypats(): |
2708 file = matcher.files()[0] | 2757 file = matcher.files()[0] |
2738 **pycompat.strkwargs(opts) | 2787 **pycompat.strkwargs(opts) |
2739 ): | 2788 ): |
2740 err = 0 | 2789 err = 0 |
2741 except error.RepoLookupError: | 2790 except error.RepoLookupError: |
2742 ui.status( | 2791 ui.status( |
2743 _("skipping missing subrepository: %s\n") % uipathfn(subpath) | 2792 _(b"skipping missing subrepository: %s\n") % uipathfn(subpath) |
2744 ) | 2793 ) |
2745 | 2794 |
2746 return err | 2795 return err |
2747 | 2796 |
2748 | 2797 |
2749 def commit(ui, repo, commitfunc, pats, opts): | 2798 def commit(ui, repo, commitfunc, pats, opts): |
2750 '''commit the specified files or all outstanding changes''' | 2799 '''commit the specified files or all outstanding changes''' |
2751 date = opts.get('date') | 2800 date = opts.get(b'date') |
2752 if date: | 2801 if date: |
2753 opts['date'] = dateutil.parsedate(date) | 2802 opts[b'date'] = dateutil.parsedate(date) |
2754 message = logmessage(ui, opts) | 2803 message = logmessage(ui, opts) |
2755 matcher = scmutil.match(repo[None], pats, opts) | 2804 matcher = scmutil.match(repo[None], pats, opts) |
2756 | 2805 |
2757 dsguard = None | 2806 dsguard = None |
2758 # extract addremove carefully -- this function can be called from a command | 2807 # extract addremove carefully -- this function can be called from a command |
2759 # that doesn't support addremove | 2808 # that doesn't support addremove |
2760 if opts.get('addremove'): | 2809 if opts.get(b'addremove'): |
2761 dsguard = dirstateguard.dirstateguard(repo, 'commit') | 2810 dsguard = dirstateguard.dirstateguard(repo, b'commit') |
2762 with dsguard or util.nullcontextmanager(): | 2811 with dsguard or util.nullcontextmanager(): |
2763 if dsguard: | 2812 if dsguard: |
2764 relative = scmutil.anypats(pats, opts) | 2813 relative = scmutil.anypats(pats, opts) |
2765 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=relative) | 2814 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=relative) |
2766 if scmutil.addremove(repo, matcher, "", uipathfn, opts) != 0: | 2815 if scmutil.addremove(repo, matcher, b"", uipathfn, opts) != 0: |
2767 raise error.Abort( | 2816 raise error.Abort( |
2768 _("failed to mark all new/missing files as added/removed") | 2817 _(b"failed to mark all new/missing files as added/removed") |
2769 ) | 2818 ) |
2770 | 2819 |
2771 return commitfunc(ui, repo, message, matcher, opts) | 2820 return commitfunc(ui, repo, message, matcher, opts) |
2772 | 2821 |
2773 | 2822 |
2790 # amend will reuse the existing user if not specified, but the obsolete | 2839 # amend will reuse the existing user if not specified, but the obsolete |
2791 # marker creation requires that the current user's name is specified. | 2840 # marker creation requires that the current user's name is specified. |
2792 if obsolete.isenabled(repo, obsolete.createmarkersopt): | 2841 if obsolete.isenabled(repo, obsolete.createmarkersopt): |
2793 ui.username() # raise exception if username not set | 2842 ui.username() # raise exception if username not set |
2794 | 2843 |
2795 ui.note(_('amending changeset %s\n') % old) | 2844 ui.note(_(b'amending changeset %s\n') % old) |
2796 base = old.p1() | 2845 base = old.p1() |
2797 | 2846 |
2798 with repo.wlock(), repo.lock(), repo.transaction('amend'): | 2847 with repo.wlock(), repo.lock(), repo.transaction(b'amend'): |
2799 # Participating changesets: | 2848 # Participating changesets: |
2800 # | 2849 # |
2801 # wctx o - workingctx that contains changes from working copy | 2850 # wctx o - workingctx that contains changes from working copy |
2802 # | to go into amending commit | 2851 # | to go into amending commit |
2803 # | | 2852 # | |
2817 | 2866 |
2818 # date-only change should be ignored? | 2867 # date-only change should be ignored? |
2819 datemaydiffer = resolvecommitoptions(ui, opts) | 2868 datemaydiffer = resolvecommitoptions(ui, opts) |
2820 | 2869 |
2821 date = old.date() | 2870 date = old.date() |
2822 if opts.get('date'): | 2871 if opts.get(b'date'): |
2823 date = dateutil.parsedate(opts.get('date')) | 2872 date = dateutil.parsedate(opts.get(b'date')) |
2824 user = opts.get('user') or old.user() | 2873 user = opts.get(b'user') or old.user() |
2825 | 2874 |
2826 if len(old.parents()) > 1: | 2875 if len(old.parents()) > 1: |
2827 # ctx.files() isn't reliable for merges, so fall back to the | 2876 # ctx.files() isn't reliable for merges, so fall back to the |
2828 # slower repo.status() method | 2877 # slower repo.status() method |
2829 files = {fn for st in base.status(old)[:3] for fn in st} | 2878 files = {fn for st in base.status(old)[:3] for fn in st} |
2833 # add/remove the files to the working copy if the "addremove" option | 2882 # add/remove the files to the working copy if the "addremove" option |
2834 # was specified. | 2883 # was specified. |
2835 matcher = scmutil.match(wctx, pats, opts) | 2884 matcher = scmutil.match(wctx, pats, opts) |
2836 relative = scmutil.anypats(pats, opts) | 2885 relative = scmutil.anypats(pats, opts) |
2837 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=relative) | 2886 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=relative) |
2838 if opts.get('addremove') and scmutil.addremove( | 2887 if opts.get(b'addremove') and scmutil.addremove( |
2839 repo, matcher, "", uipathfn, opts | 2888 repo, matcher, b"", uipathfn, opts |
2840 ): | 2889 ): |
2841 raise error.Abort( | 2890 raise error.Abort( |
2842 _("failed to mark all new/missing files as added/removed") | 2891 _(b"failed to mark all new/missing files as added/removed") |
2843 ) | 2892 ) |
2844 | 2893 |
2845 # Check subrepos. This depends on in-place wctx._status update in | 2894 # Check subrepos. This depends on in-place wctx._status update in |
2846 # subrepo.precommit(). To minimize the risk of this hack, we do | 2895 # subrepo.precommit(). To minimize the risk of this hack, we do |
2847 # nothing if .hgsub does not exist. | 2896 # nothing if .hgsub does not exist. |
2848 if '.hgsub' in wctx or '.hgsub' in old: | 2897 if b'.hgsub' in wctx or b'.hgsub' in old: |
2849 subs, commitsubs, newsubstate = subrepoutil.precommit( | 2898 subs, commitsubs, newsubstate = subrepoutil.precommit( |
2850 ui, wctx, wctx._status, matcher | 2899 ui, wctx, wctx._status, matcher |
2851 ) | 2900 ) |
2852 # amend should abort if commitsubrepos is enabled | 2901 # amend should abort if commitsubrepos is enabled |
2853 assert not commitsubs | 2902 assert not commitsubs |
2898 mctx = context.memfilectx( | 2947 mctx = context.memfilectx( |
2899 repo, | 2948 repo, |
2900 ctx_, | 2949 ctx_, |
2901 fctx.path(), | 2950 fctx.path(), |
2902 fctx.data(), | 2951 fctx.data(), |
2903 islink='l' in flags, | 2952 islink=b'l' in flags, |
2904 isexec='x' in flags, | 2953 isexec=b'x' in flags, |
2905 copysource=copied.get(path), | 2954 copysource=copied.get(path), |
2906 ) | 2955 ) |
2907 return mctx | 2956 return mctx |
2908 except KeyError: | 2957 except KeyError: |
2909 return None | 2958 return None |
2910 | 2959 |
2911 else: | 2960 else: |
2912 ui.note(_('copying changeset %s to %s\n') % (old, base)) | 2961 ui.note(_(b'copying changeset %s to %s\n') % (old, base)) |
2913 | 2962 |
2914 # Use version of files as in the old cset | 2963 # Use version of files as in the old cset |
2915 def filectxfn(repo, ctx_, path): | 2964 def filectxfn(repo, ctx_, path): |
2916 try: | 2965 try: |
2917 return old.filectx(path) | 2966 return old.filectx(path) |
2920 | 2969 |
2921 # See if we got a message from -m or -l, if not, open the editor with | 2970 # See if we got a message from -m or -l, if not, open the editor with |
2922 # the message of the changeset to amend. | 2971 # the message of the changeset to amend. |
2923 message = logmessage(ui, opts) | 2972 message = logmessage(ui, opts) |
2924 | 2973 |
2925 editform = mergeeditform(old, 'commit.amend') | 2974 editform = mergeeditform(old, b'commit.amend') |
2926 | 2975 |
2927 if not message: | 2976 if not message: |
2928 message = old.description() | 2977 message = old.description() |
2929 # Default if message isn't provided and --edit is not passed is to | 2978 # Default if message isn't provided and --edit is not passed is to |
2930 # invoke editor, but allow --no-edit. If somehow we don't have any | 2979 # invoke editor, but allow --no-edit. If somehow we don't have any |
2931 # description, let's always start the editor. | 2980 # description, let's always start the editor. |
2932 doedit = not message or opts.get('edit') in [True, None] | 2981 doedit = not message or opts.get(b'edit') in [True, None] |
2933 else: | 2982 else: |
2934 # Default if message is provided is to not invoke editor, but allow | 2983 # Default if message is provided is to not invoke editor, but allow |
2935 # --edit. | 2984 # --edit. |
2936 doedit = opts.get('edit') is True | 2985 doedit = opts.get(b'edit') is True |
2937 editor = getcommiteditor(edit=doedit, editform=editform) | 2986 editor = getcommiteditor(edit=doedit, editform=editform) |
2938 | 2987 |
2939 pureextra = extra.copy() | 2988 pureextra = extra.copy() |
2940 extra['amend_source'] = old.hex() | 2989 extra[b'amend_source'] = old.hex() |
2941 | 2990 |
2942 new = context.memctx( | 2991 new = context.memctx( |
2943 repo, | 2992 repo, |
2944 parents=[base.node(), old.p2().node()], | 2993 parents=[base.node(), old.p2().node()], |
2945 text=message, | 2994 text=message, |
2964 # | 3013 # |
2965 # This not what we expect from amend. | 3014 # This not what we expect from amend. |
2966 return old.node() | 3015 return old.node() |
2967 | 3016 |
2968 commitphase = None | 3017 commitphase = None |
2969 if opts.get('secret'): | 3018 if opts.get(b'secret'): |
2970 commitphase = phases.secret | 3019 commitphase = phases.secret |
2971 newid = repo.commitctx(new) | 3020 newid = repo.commitctx(new) |
2972 | 3021 |
2973 # Reroute the working copy parent to the new changeset | 3022 # Reroute the working copy parent to the new changeset |
2974 repo.setparents(newid, nullid) | 3023 repo.setparents(newid, nullid) |
2975 mapping = {old.node(): (newid,)} | 3024 mapping = {old.node(): (newid,)} |
2976 obsmetadata = None | 3025 obsmetadata = None |
2977 if opts.get('note'): | 3026 if opts.get(b'note'): |
2978 obsmetadata = {'note': encoding.fromlocal(opts['note'])} | 3027 obsmetadata = {b'note': encoding.fromlocal(opts[b'note'])} |
2979 backup = ui.configbool('rewrite', 'backup-bundle') | 3028 backup = ui.configbool(b'rewrite', b'backup-bundle') |
2980 scmutil.cleanupnodes( | 3029 scmutil.cleanupnodes( |
2981 repo, | 3030 repo, |
2982 mapping, | 3031 mapping, |
2983 'amend', | 3032 b'amend', |
2984 metadata=obsmetadata, | 3033 metadata=obsmetadata, |
2985 fixphase=True, | 3034 fixphase=True, |
2986 targetphase=commitphase, | 3035 targetphase=commitphase, |
2987 backup=backup, | 3036 backup=backup, |
2988 ) | 3037 ) |
3007 dirstate.drop(f) | 3056 dirstate.drop(f) |
3008 | 3057 |
3009 return newid | 3058 return newid |
3010 | 3059 |
3011 | 3060 |
3012 def commiteditor(repo, ctx, subs, editform=''): | 3061 def commiteditor(repo, ctx, subs, editform=b''): |
3013 if ctx.description(): | 3062 if ctx.description(): |
3014 return ctx.description() | 3063 return ctx.description() |
3015 return commitforceeditor( | 3064 return commitforceeditor( |
3016 repo, ctx, subs, editform=editform, unchangedmessagedetection=True | 3065 repo, ctx, subs, editform=editform, unchangedmessagedetection=True |
3017 ) | 3066 ) |
3021 repo, | 3070 repo, |
3022 ctx, | 3071 ctx, |
3023 subs, | 3072 subs, |
3024 finishdesc=None, | 3073 finishdesc=None, |
3025 extramsg=None, | 3074 extramsg=None, |
3026 editform='', | 3075 editform=b'', |
3027 unchangedmessagedetection=False, | 3076 unchangedmessagedetection=False, |
3028 ): | 3077 ): |
3029 if not extramsg: | 3078 if not extramsg: |
3030 extramsg = _("Leave message empty to abort commit.") | 3079 extramsg = _(b"Leave message empty to abort commit.") |
3031 | 3080 |
3032 forms = [e for e in editform.split('.') if e] | 3081 forms = [e for e in editform.split(b'.') if e] |
3033 forms.insert(0, 'changeset') | 3082 forms.insert(0, b'changeset') |
3034 templatetext = None | 3083 templatetext = None |
3035 while forms: | 3084 while forms: |
3036 ref = '.'.join(forms) | 3085 ref = b'.'.join(forms) |
3037 if repo.ui.config('committemplate', ref): | 3086 if repo.ui.config(b'committemplate', ref): |
3038 templatetext = committext = buildcommittemplate( | 3087 templatetext = committext = buildcommittemplate( |
3039 repo, ctx, subs, extramsg, ref | 3088 repo, ctx, subs, extramsg, ref |
3040 ) | 3089 ) |
3041 break | 3090 break |
3042 forms.pop() | 3091 forms.pop() |
3057 ctx.user(), | 3106 ctx.user(), |
3058 ctx.extra(), | 3107 ctx.extra(), |
3059 editform=editform, | 3108 editform=editform, |
3060 pending=pending, | 3109 pending=pending, |
3061 repopath=repo.path, | 3110 repopath=repo.path, |
3062 action='commit', | 3111 action=b'commit', |
3063 ) | 3112 ) |
3064 text = editortext | 3113 text = editortext |
3065 | 3114 |
3066 # strip away anything below this special string (used for editors that want | 3115 # strip away anything below this special string (used for editors that want |
3067 # to display the diff) | 3116 # to display the diff) |
3068 stripbelow = re.search(_linebelow, text, flags=re.MULTILINE) | 3117 stripbelow = re.search(_linebelow, text, flags=re.MULTILINE) |
3069 if stripbelow: | 3118 if stripbelow: |
3070 text = text[: stripbelow.start()] | 3119 text = text[: stripbelow.start()] |
3071 | 3120 |
3072 text = re.sub("(?m)^HG:.*(\n|$)", "", text) | 3121 text = re.sub(b"(?m)^HG:.*(\n|$)", b"", text) |
3073 os.chdir(olddir) | 3122 os.chdir(olddir) |
3074 | 3123 |
3075 if finishdesc: | 3124 if finishdesc: |
3076 text = finishdesc(text) | 3125 text = finishdesc(text) |
3077 if not text.strip(): | 3126 if not text.strip(): |
3078 raise error.Abort(_("empty commit message")) | 3127 raise error.Abort(_(b"empty commit message")) |
3079 if unchangedmessagedetection and editortext == templatetext: | 3128 if unchangedmessagedetection and editortext == templatetext: |
3080 raise error.Abort(_("commit message unchanged")) | 3129 raise error.Abort(_(b"commit message unchanged")) |
3081 | 3130 |
3082 return text | 3131 return text |
3083 | 3132 |
3084 | 3133 |
3085 def buildcommittemplate(repo, ctx, subs, extramsg, ref): | 3134 def buildcommittemplate(repo, ctx, subs, extramsg, ref): |
3086 ui = repo.ui | 3135 ui = repo.ui |
3087 spec = formatter.templatespec(ref, None, None) | 3136 spec = formatter.templatespec(ref, None, None) |
3088 t = logcmdutil.changesettemplater(ui, repo, spec) | 3137 t = logcmdutil.changesettemplater(ui, repo, spec) |
3089 t.t.cache.update( | 3138 t.t.cache.update( |
3090 (k, templater.unquotestring(v)) | 3139 (k, templater.unquotestring(v)) |
3091 for k, v in repo.ui.configitems('committemplate') | 3140 for k, v in repo.ui.configitems(b'committemplate') |
3092 ) | 3141 ) |
3093 | 3142 |
3094 if not extramsg: | 3143 if not extramsg: |
3095 extramsg = '' # ensure that extramsg is string | 3144 extramsg = b'' # ensure that extramsg is string |
3096 | 3145 |
3097 ui.pushbuffer() | 3146 ui.pushbuffer() |
3098 t.show(ctx, extramsg=extramsg) | 3147 t.show(ctx, extramsg=extramsg) |
3099 return ui.popbuffer() | 3148 return ui.popbuffer() |
3100 | 3149 |
3101 | 3150 |
3102 def hgprefix(msg): | 3151 def hgprefix(msg): |
3103 return "\n".join(["HG: %s" % a for a in msg.split("\n") if a]) | 3152 return b"\n".join([b"HG: %s" % a for a in msg.split(b"\n") if a]) |
3104 | 3153 |
3105 | 3154 |
3106 def buildcommittext(repo, ctx, subs, extramsg): | 3155 def buildcommittext(repo, ctx, subs, extramsg): |
3107 edittext = [] | 3156 edittext = [] |
3108 modified, added, removed = ctx.modified(), ctx.added(), ctx.removed() | 3157 modified, added, removed = ctx.modified(), ctx.added(), ctx.removed() |
3109 if ctx.description(): | 3158 if ctx.description(): |
3110 edittext.append(ctx.description()) | 3159 edittext.append(ctx.description()) |
3111 edittext.append("") | 3160 edittext.append(b"") |
3112 edittext.append("") # Empty line between message and comments. | 3161 edittext.append(b"") # Empty line between message and comments. |
3113 edittext.append( | 3162 edittext.append( |
3114 hgprefix( | 3163 hgprefix( |
3115 _( | 3164 _( |
3116 "Enter commit message." | 3165 b"Enter commit message." |
3117 " Lines beginning with 'HG:' are removed." | 3166 b" Lines beginning with 'HG:' are removed." |
3118 ) | 3167 ) |
3119 ) | 3168 ) |
3120 ) | 3169 ) |
3121 edittext.append(hgprefix(extramsg)) | 3170 edittext.append(hgprefix(extramsg)) |
3122 edittext.append("HG: --") | 3171 edittext.append(b"HG: --") |
3123 edittext.append(hgprefix(_("user: %s") % ctx.user())) | 3172 edittext.append(hgprefix(_(b"user: %s") % ctx.user())) |
3124 if ctx.p2(): | 3173 if ctx.p2(): |
3125 edittext.append(hgprefix(_("branch merge"))) | 3174 edittext.append(hgprefix(_(b"branch merge"))) |
3126 if ctx.branch(): | 3175 if ctx.branch(): |
3127 edittext.append(hgprefix(_("branch '%s'") % ctx.branch())) | 3176 edittext.append(hgprefix(_(b"branch '%s'") % ctx.branch())) |
3128 if bookmarks.isactivewdirparent(repo): | 3177 if bookmarks.isactivewdirparent(repo): |
3129 edittext.append(hgprefix(_("bookmark '%s'") % repo._activebookmark)) | 3178 edittext.append(hgprefix(_(b"bookmark '%s'") % repo._activebookmark)) |
3130 edittext.extend([hgprefix(_("subrepo %s") % s) for s in subs]) | 3179 edittext.extend([hgprefix(_(b"subrepo %s") % s) for s in subs]) |
3131 edittext.extend([hgprefix(_("added %s") % f) for f in added]) | 3180 edittext.extend([hgprefix(_(b"added %s") % f) for f in added]) |
3132 edittext.extend([hgprefix(_("changed %s") % f) for f in modified]) | 3181 edittext.extend([hgprefix(_(b"changed %s") % f) for f in modified]) |
3133 edittext.extend([hgprefix(_("removed %s") % f) for f in removed]) | 3182 edittext.extend([hgprefix(_(b"removed %s") % f) for f in removed]) |
3134 if not added and not modified and not removed: | 3183 if not added and not modified and not removed: |
3135 edittext.append(hgprefix(_("no files changed"))) | 3184 edittext.append(hgprefix(_(b"no files changed"))) |
3136 edittext.append("") | 3185 edittext.append(b"") |
3137 | 3186 |
3138 return "\n".join(edittext) | 3187 return b"\n".join(edittext) |
3139 | 3188 |
3140 | 3189 |
3141 def commitstatus(repo, node, branch, bheads=None, opts=None): | 3190 def commitstatus(repo, node, branch, bheads=None, opts=None): |
3142 if opts is None: | 3191 if opts is None: |
3143 opts = {} | 3192 opts = {} |
3144 ctx = repo[node] | 3193 ctx = repo[node] |
3145 parents = ctx.parents() | 3194 parents = ctx.parents() |
3146 | 3195 |
3147 if ( | 3196 if ( |
3148 not opts.get('amend') | 3197 not opts.get(b'amend') |
3149 and bheads | 3198 and bheads |
3150 and node not in bheads | 3199 and node not in bheads |
3151 and not [ | 3200 and not [ |
3152 x for x in parents if x.node() in bheads and x.branch() == branch | 3201 x for x in parents if x.node() in bheads and x.branch() == branch |
3153 ] | 3202 ] |
3154 ): | 3203 ): |
3155 repo.ui.status(_('created new head\n')) | 3204 repo.ui.status(_(b'created new head\n')) |
3156 # The message is not printed for initial roots. For the other | 3205 # The message is not printed for initial roots. For the other |
3157 # changesets, it is printed in the following situations: | 3206 # changesets, it is printed in the following situations: |
3158 # | 3207 # |
3159 # Par column: for the 2 parents with ... | 3208 # Par column: for the 2 parents with ... |
3160 # N: null or no parent | 3209 # N: null or no parent |
3180 # C C y additional head from merge | 3229 # C C y additional head from merge |
3181 # C H n merge with a head | 3230 # C H n merge with a head |
3182 # | 3231 # |
3183 # H H n head merge: head count decreases | 3232 # H H n head merge: head count decreases |
3184 | 3233 |
3185 if not opts.get('close_branch'): | 3234 if not opts.get(b'close_branch'): |
3186 for r in parents: | 3235 for r in parents: |
3187 if r.closesbranch() and r.branch() == branch: | 3236 if r.closesbranch() and r.branch() == branch: |
3188 repo.ui.status(_('reopening closed branch head %d\n') % r.rev()) | 3237 repo.ui.status( |
3238 _(b'reopening closed branch head %d\n') % r.rev() | |
3239 ) | |
3189 | 3240 |
3190 if repo.ui.debugflag: | 3241 if repo.ui.debugflag: |
3191 repo.ui.write(_('committed changeset %d:%s\n') % (ctx.rev(), ctx.hex())) | 3242 repo.ui.write( |
3243 _(b'committed changeset %d:%s\n') % (ctx.rev(), ctx.hex()) | |
3244 ) | |
3192 elif repo.ui.verbose: | 3245 elif repo.ui.verbose: |
3193 repo.ui.write(_('committed changeset %d:%s\n') % (ctx.rev(), ctx)) | 3246 repo.ui.write(_(b'committed changeset %d:%s\n') % (ctx.rev(), ctx)) |
3194 | 3247 |
3195 | 3248 |
3196 def postcommitstatus(repo, pats, opts): | 3249 def postcommitstatus(repo, pats, opts): |
3197 return repo.status(match=scmutil.match(repo[None], pats, opts)) | 3250 return repo.status(match=scmutil.match(repo[None], pats, opts)) |
3198 | 3251 |
3220 | 3273 |
3221 with repo.wlock(): | 3274 with repo.wlock(): |
3222 ## filling of the `names` mapping | 3275 ## filling of the `names` mapping |
3223 # walk dirstate to fill `names` | 3276 # walk dirstate to fill `names` |
3224 | 3277 |
3225 interactive = opts.get('interactive', False) | 3278 interactive = opts.get(b'interactive', False) |
3226 wctx = repo[None] | 3279 wctx = repo[None] |
3227 m = scmutil.match(wctx, pats, opts) | 3280 m = scmutil.match(wctx, pats, opts) |
3228 | 3281 |
3229 # we'll need this later | 3282 # we'll need this later |
3230 targetsubs = sorted(s for s in wctx.substate if m(s)) | 3283 targetsubs = sorted(s for s in wctx.substate if m(s)) |
3239 def badfn(path, msg): | 3292 def badfn(path, msg): |
3240 if path in names: | 3293 if path in names: |
3241 return | 3294 return |
3242 if path in ctx.substate: | 3295 if path in ctx.substate: |
3243 return | 3296 return |
3244 path_ = path + '/' | 3297 path_ = path + b'/' |
3245 for f in names: | 3298 for f in names: |
3246 if f.startswith(path_): | 3299 if f.startswith(path_): |
3247 return | 3300 return |
3248 ui.warn("%s: %s\n" % (uipathfn(path), msg)) | 3301 ui.warn(b"%s: %s\n" % (uipathfn(path), msg)) |
3249 | 3302 |
3250 for abs in ctx.walk(matchmod.badmatch(m, badfn)): | 3303 for abs in ctx.walk(matchmod.badmatch(m, badfn)): |
3251 if abs not in names: | 3304 if abs not in names: |
3252 names[abs] = m.exact(abs) | 3305 names[abs] = m.exact(abs) |
3253 | 3306 |
3324 | 3377 |
3325 # if f is a rename, update `names` to also revert the source | 3378 # if f is a rename, update `names` to also revert the source |
3326 for f in localchanges: | 3379 for f in localchanges: |
3327 src = repo.dirstate.copied(f) | 3380 src = repo.dirstate.copied(f) |
3328 # XXX should we check for rename down to target node? | 3381 # XXX should we check for rename down to target node? |
3329 if src and src not in names and repo.dirstate[src] == 'r': | 3382 if src and src not in names and repo.dirstate[src] == b'r': |
3330 dsremoved.add(src) | 3383 dsremoved.add(src) |
3331 names[src] = True | 3384 names[src] = True |
3332 | 3385 |
3333 # determine the exact nature of the deleted changesets | 3386 # determine the exact nature of the deleted changesets |
3334 deladded = set(_deleted) | 3387 deladded = set(_deleted) |
3338 deleted = _deleted - deladded | 3391 deleted = _deleted - deladded |
3339 | 3392 |
3340 # distinguish between file to forget and the other | 3393 # distinguish between file to forget and the other |
3341 added = set() | 3394 added = set() |
3342 for abs in dsadded: | 3395 for abs in dsadded: |
3343 if repo.dirstate[abs] != 'a': | 3396 if repo.dirstate[abs] != b'a': |
3344 added.add(abs) | 3397 added.add(abs) |
3345 dsadded -= added | 3398 dsadded -= added |
3346 | 3399 |
3347 for abs in deladded: | 3400 for abs in deladded: |
3348 if repo.dirstate[abs] == 'a': | 3401 if repo.dirstate[abs] == b'a': |
3349 dsadded.add(abs) | 3402 dsadded.add(abs) |
3350 deladded -= dsadded | 3403 deladded -= dsadded |
3351 | 3404 |
3352 # For files marked as removed, we check if an unknown file is present at | 3405 # For files marked as removed, we check if an unknown file is present at |
3353 # the same path. If a such file exists it may need to be backed up. | 3406 # the same path. If a such file exists it may need to be backed up. |
3368 dsremoved -= dsremovunk | 3421 dsremoved -= dsremovunk |
3369 | 3422 |
3370 # action to be actually performed by revert | 3423 # action to be actually performed by revert |
3371 # (<list of file>, message>) tuple | 3424 # (<list of file>, message>) tuple |
3372 actions = { | 3425 actions = { |
3373 'revert': ([], _('reverting %s\n')), | 3426 b'revert': ([], _(b'reverting %s\n')), |
3374 'add': ([], _('adding %s\n')), | 3427 b'add': ([], _(b'adding %s\n')), |
3375 'remove': ([], _('removing %s\n')), | 3428 b'remove': ([], _(b'removing %s\n')), |
3376 'drop': ([], _('removing %s\n')), | 3429 b'drop': ([], _(b'removing %s\n')), |
3377 'forget': ([], _('forgetting %s\n')), | 3430 b'forget': ([], _(b'forgetting %s\n')), |
3378 'undelete': ([], _('undeleting %s\n')), | 3431 b'undelete': ([], _(b'undeleting %s\n')), |
3379 'noop': (None, _('no changes needed to %s\n')), | 3432 b'noop': (None, _(b'no changes needed to %s\n')), |
3380 'unknown': (None, _('file not managed: %s\n')), | 3433 b'unknown': (None, _(b'file not managed: %s\n')), |
3381 } | 3434 } |
3382 | 3435 |
3383 # "constant" that convey the backup strategy. | 3436 # "constant" that convey the backup strategy. |
3384 # All set to `discard` if `no-backup` is set do avoid checking | 3437 # All set to `discard` if `no-backup` is set do avoid checking |
3385 # no_backup lower in the code. | 3438 # no_backup lower in the code. |
3386 # These values are ordered for comparison purposes | 3439 # These values are ordered for comparison purposes |
3387 backupinteractive = 3 # do backup if interactively modified | 3440 backupinteractive = 3 # do backup if interactively modified |
3388 backup = 2 # unconditionally do backup | 3441 backup = 2 # unconditionally do backup |
3389 check = 1 # check if the existing file differs from target | 3442 check = 1 # check if the existing file differs from target |
3390 discard = 0 # never do backup | 3443 discard = 0 # never do backup |
3391 if opts.get('no_backup'): | 3444 if opts.get(b'no_backup'): |
3392 backupinteractive = backup = check = discard | 3445 backupinteractive = backup = check = discard |
3393 if interactive: | 3446 if interactive: |
3394 dsmodifiedbackup = backupinteractive | 3447 dsmodifiedbackup = backupinteractive |
3395 else: | 3448 else: |
3396 dsmodifiedbackup = backup | 3449 dsmodifiedbackup = backup |
3397 tobackup = set() | 3450 tobackup = set() |
3398 | 3451 |
3399 backupanddel = actions['remove'] | 3452 backupanddel = actions[b'remove'] |
3400 if not opts.get('no_backup'): | 3453 if not opts.get(b'no_backup'): |
3401 backupanddel = actions['drop'] | 3454 backupanddel = actions[b'drop'] |
3402 | 3455 |
3403 disptable = ( | 3456 disptable = ( |
3404 # dispatch table: | 3457 # dispatch table: |
3405 # file state | 3458 # file state |
3406 # action | 3459 # action |
3407 # make backup | 3460 # make backup |
3408 ## Sets that results that will change file on disk | 3461 ## Sets that results that will change file on disk |
3409 # Modified compared to target, no local change | 3462 # Modified compared to target, no local change |
3410 (modified, actions['revert'], discard), | 3463 (modified, actions[b'revert'], discard), |
3411 # Modified compared to target, but local file is deleted | 3464 # Modified compared to target, but local file is deleted |
3412 (deleted, actions['revert'], discard), | 3465 (deleted, actions[b'revert'], discard), |
3413 # Modified compared to target, local change | 3466 # Modified compared to target, local change |
3414 (dsmodified, actions['revert'], dsmodifiedbackup), | 3467 (dsmodified, actions[b'revert'], dsmodifiedbackup), |
3415 # Added since target | 3468 # Added since target |
3416 (added, actions['remove'], discard), | 3469 (added, actions[b'remove'], discard), |
3417 # Added in working directory | 3470 # Added in working directory |
3418 (dsadded, actions['forget'], discard), | 3471 (dsadded, actions[b'forget'], discard), |
3419 # Added since target, have local modification | 3472 # Added since target, have local modification |
3420 (modadded, backupanddel, backup), | 3473 (modadded, backupanddel, backup), |
3421 # Added since target but file is missing in working directory | 3474 # Added since target but file is missing in working directory |
3422 (deladded, actions['drop'], discard), | 3475 (deladded, actions[b'drop'], discard), |
3423 # Removed since target, before working copy parent | 3476 # Removed since target, before working copy parent |
3424 (removed, actions['add'], discard), | 3477 (removed, actions[b'add'], discard), |
3425 # Same as `removed` but an unknown file exists at the same path | 3478 # Same as `removed` but an unknown file exists at the same path |
3426 (removunk, actions['add'], check), | 3479 (removunk, actions[b'add'], check), |
3427 # Removed since targe, marked as such in working copy parent | 3480 # Removed since targe, marked as such in working copy parent |
3428 (dsremoved, actions['undelete'], discard), | 3481 (dsremoved, actions[b'undelete'], discard), |
3429 # Same as `dsremoved` but an unknown file exists at the same path | 3482 # Same as `dsremoved` but an unknown file exists at the same path |
3430 (dsremovunk, actions['undelete'], check), | 3483 (dsremovunk, actions[b'undelete'], check), |
3431 ## the following sets does not result in any file changes | 3484 ## the following sets does not result in any file changes |
3432 # File with no modification | 3485 # File with no modification |
3433 (clean, actions['noop'], discard), | 3486 (clean, actions[b'noop'], discard), |
3434 # Existing file, not tracked anywhere | 3487 # Existing file, not tracked anywhere |
3435 (unknown, actions['unknown'], discard), | 3488 (unknown, actions[b'unknown'], discard), |
3436 ) | 3489 ) |
3437 | 3490 |
3438 for abs, exact in sorted(names.items()): | 3491 for abs, exact in sorted(names.items()): |
3439 # target file to be touch on disk (relative to cwd) | 3492 # target file to be touch on disk (relative to cwd) |
3440 target = repo.wjoin(abs) | 3493 target = repo.wjoin(abs) |
3455 absbakname = scmutil.backuppath(ui, repo, abs) | 3508 absbakname = scmutil.backuppath(ui, repo, abs) |
3456 bakname = os.path.relpath( | 3509 bakname = os.path.relpath( |
3457 absbakname, start=repo.root | 3510 absbakname, start=repo.root |
3458 ) | 3511 ) |
3459 ui.note( | 3512 ui.note( |
3460 _('saving current version of %s as %s\n') | 3513 _(b'saving current version of %s as %s\n') |
3461 % (uipathfn(abs), uipathfn(bakname)) | 3514 % (uipathfn(abs), uipathfn(bakname)) |
3462 ) | 3515 ) |
3463 if not opts.get('dry_run'): | 3516 if not opts.get(b'dry_run'): |
3464 if interactive: | 3517 if interactive: |
3465 util.copyfile(target, absbakname) | 3518 util.copyfile(target, absbakname) |
3466 else: | 3519 else: |
3467 util.rename(target, absbakname) | 3520 util.rename(target, absbakname) |
3468 if opts.get('dry_run'): | 3521 if opts.get(b'dry_run'): |
3469 if ui.verbose or not exact: | 3522 if ui.verbose or not exact: |
3470 ui.status(msg % uipathfn(abs)) | 3523 ui.status(msg % uipathfn(abs)) |
3471 elif exact: | 3524 elif exact: |
3472 ui.warn(msg % uipathfn(abs)) | 3525 ui.warn(msg % uipathfn(abs)) |
3473 break | 3526 break |
3474 | 3527 |
3475 if not opts.get('dry_run'): | 3528 if not opts.get(b'dry_run'): |
3476 needdata = ('revert', 'add', 'undelete') | 3529 needdata = (b'revert', b'add', b'undelete') |
3477 oplist = [actions[name][0] for name in needdata] | 3530 oplist = [actions[name][0] for name in needdata] |
3478 prefetch = scmutil.prefetchfiles | 3531 prefetch = scmutil.prefetchfiles |
3479 matchfiles = scmutil.matchfiles | 3532 matchfiles = scmutil.matchfiles |
3480 prefetch( | 3533 prefetch( |
3481 repo, | 3534 repo, |
3502 wctx.sub(sub).revert( | 3555 wctx.sub(sub).revert( |
3503 ctx.substate[sub], *pats, **pycompat.strkwargs(opts) | 3556 ctx.substate[sub], *pats, **pycompat.strkwargs(opts) |
3504 ) | 3557 ) |
3505 except KeyError: | 3558 except KeyError: |
3506 raise error.Abort( | 3559 raise error.Abort( |
3507 "subrepository '%s' does not exist in %s!" | 3560 b"subrepository '%s' does not exist in %s!" |
3508 % (sub, short(ctx.node())) | 3561 % (sub, short(ctx.node())) |
3509 ) | 3562 ) |
3510 | 3563 |
3511 | 3564 |
3512 def _performrevert( | 3565 def _performrevert( |
3535 fc = ctx[f] | 3588 fc = ctx[f] |
3536 repo.wwrite(f, fc.data(), fc.flags()) | 3589 repo.wwrite(f, fc.data(), fc.flags()) |
3537 | 3590 |
3538 def doremove(f): | 3591 def doremove(f): |
3539 try: | 3592 try: |
3540 rmdir = repo.ui.configbool('experimental', 'removeemptydirs') | 3593 rmdir = repo.ui.configbool(b'experimental', b'removeemptydirs') |
3541 repo.wvfs.unlinkpath(f, rmdir=rmdir) | 3594 repo.wvfs.unlinkpath(f, rmdir=rmdir) |
3542 except OSError: | 3595 except OSError: |
3543 pass | 3596 pass |
3544 repo.dirstate.remove(f) | 3597 repo.dirstate.remove(f) |
3545 | 3598 |
3547 exact = names[f] | 3600 exact = names[f] |
3548 if repo.ui.verbose or not exact: | 3601 if repo.ui.verbose or not exact: |
3549 repo.ui.status(actions[action][1] % uipathfn(f)) | 3602 repo.ui.status(actions[action][1] % uipathfn(f)) |
3550 | 3603 |
3551 audit_path = pathutil.pathauditor(repo.root, cached=True) | 3604 audit_path = pathutil.pathauditor(repo.root, cached=True) |
3552 for f in actions['forget'][0]: | 3605 for f in actions[b'forget'][0]: |
3553 if interactive: | 3606 if interactive: |
3554 choice = repo.ui.promptchoice( | 3607 choice = repo.ui.promptchoice( |
3555 _("forget added file %s (Yn)?$$ &Yes $$ &No") % uipathfn(f) | 3608 _(b"forget added file %s (Yn)?$$ &Yes $$ &No") % uipathfn(f) |
3556 ) | 3609 ) |
3557 if choice == 0: | 3610 if choice == 0: |
3558 prntstatusmsg('forget', f) | 3611 prntstatusmsg(b'forget', f) |
3559 repo.dirstate.drop(f) | 3612 repo.dirstate.drop(f) |
3560 else: | 3613 else: |
3561 excluded_files.append(f) | 3614 excluded_files.append(f) |
3562 else: | 3615 else: |
3563 prntstatusmsg('forget', f) | 3616 prntstatusmsg(b'forget', f) |
3564 repo.dirstate.drop(f) | 3617 repo.dirstate.drop(f) |
3565 for f in actions['remove'][0]: | 3618 for f in actions[b'remove'][0]: |
3566 audit_path(f) | 3619 audit_path(f) |
3567 if interactive: | 3620 if interactive: |
3568 choice = repo.ui.promptchoice( | 3621 choice = repo.ui.promptchoice( |
3569 _("remove added file %s (Yn)?$$ &Yes $$ &No") % uipathfn(f) | 3622 _(b"remove added file %s (Yn)?$$ &Yes $$ &No") % uipathfn(f) |
3570 ) | 3623 ) |
3571 if choice == 0: | 3624 if choice == 0: |
3572 prntstatusmsg('remove', f) | 3625 prntstatusmsg(b'remove', f) |
3573 doremove(f) | 3626 doremove(f) |
3574 else: | 3627 else: |
3575 excluded_files.append(f) | 3628 excluded_files.append(f) |
3576 else: | 3629 else: |
3577 prntstatusmsg('remove', f) | 3630 prntstatusmsg(b'remove', f) |
3578 doremove(f) | 3631 doremove(f) |
3579 for f in actions['drop'][0]: | 3632 for f in actions[b'drop'][0]: |
3580 audit_path(f) | 3633 audit_path(f) |
3581 prntstatusmsg('drop', f) | 3634 prntstatusmsg(b'drop', f) |
3582 repo.dirstate.remove(f) | 3635 repo.dirstate.remove(f) |
3583 | 3636 |
3584 normal = None | 3637 normal = None |
3585 if node == parent: | 3638 if node == parent: |
3586 # We're reverting to our parent. If possible, we'd like status | 3639 # We're reverting to our parent. If possible, we'd like status |
3592 normal = repo.dirstate.normal | 3645 normal = repo.dirstate.normal |
3593 | 3646 |
3594 newlyaddedandmodifiedfiles = set() | 3647 newlyaddedandmodifiedfiles = set() |
3595 if interactive: | 3648 if interactive: |
3596 # Prompt the user for changes to revert | 3649 # Prompt the user for changes to revert |
3597 torevert = [f for f in actions['revert'][0] if f not in excluded_files] | 3650 torevert = [f for f in actions[b'revert'][0] if f not in excluded_files] |
3598 m = scmutil.matchfiles(repo, torevert) | 3651 m = scmutil.matchfiles(repo, torevert) |
3599 diffopts = patch.difffeatureopts( | 3652 diffopts = patch.difffeatureopts( |
3600 repo.ui, | 3653 repo.ui, |
3601 whitespace=True, | 3654 whitespace=True, |
3602 section='commands', | 3655 section=b'commands', |
3603 configprefix='revert.interactive.', | 3656 configprefix=b'revert.interactive.', |
3604 ) | 3657 ) |
3605 diffopts.nodates = True | 3658 diffopts.nodates = True |
3606 diffopts.git = True | 3659 diffopts.git = True |
3607 operation = 'apply' | 3660 operation = b'apply' |
3608 if node == parent: | 3661 if node == parent: |
3609 if repo.ui.configbool( | 3662 if repo.ui.configbool( |
3610 'experimental', 'revert.interactive.select-to-keep' | 3663 b'experimental', b'revert.interactive.select-to-keep' |
3611 ): | 3664 ): |
3612 operation = 'keep' | 3665 operation = b'keep' |
3613 else: | 3666 else: |
3614 operation = 'discard' | 3667 operation = b'discard' |
3615 | 3668 |
3616 if operation == 'apply': | 3669 if operation == b'apply': |
3617 diff = patch.diff(repo, None, ctx.node(), m, opts=diffopts) | 3670 diff = patch.diff(repo, None, ctx.node(), m, opts=diffopts) |
3618 else: | 3671 else: |
3619 diff = patch.diff(repo, ctx.node(), None, m, opts=diffopts) | 3672 diff = patch.diff(repo, ctx.node(), None, m, opts=diffopts) |
3620 originalchunks = patch.parsepatch(diff) | 3673 originalchunks = patch.parsepatch(diff) |
3621 | 3674 |
3622 try: | 3675 try: |
3623 | 3676 |
3624 chunks, opts = recordfilter( | 3677 chunks, opts = recordfilter( |
3625 repo.ui, originalchunks, match, operation=operation | 3678 repo.ui, originalchunks, match, operation=operation |
3626 ) | 3679 ) |
3627 if operation == 'discard': | 3680 if operation == b'discard': |
3628 chunks = patch.reversehunks(chunks) | 3681 chunks = patch.reversehunks(chunks) |
3629 | 3682 |
3630 except error.PatchError as err: | 3683 except error.PatchError as err: |
3631 raise error.Abort(_('error parsing patch: %s') % err) | 3684 raise error.Abort(_(b'error parsing patch: %s') % err) |
3632 | 3685 |
3633 # FIXME: when doing an interactive revert of a copy, there's no way of | 3686 # FIXME: when doing an interactive revert of a copy, there's no way of |
3634 # performing a partial revert of the added file, the only option is | 3687 # performing a partial revert of the added file, the only option is |
3635 # "remove added file <name> (Yn)?", so we don't need to worry about the | 3688 # "remove added file <name> (Yn)?", so we don't need to worry about the |
3636 # alsorestore value. Ideally we'd be able to partially revert | 3689 # alsorestore value. Ideally we'd be able to partially revert |
3642 tobackup = set() | 3695 tobackup = set() |
3643 # Apply changes | 3696 # Apply changes |
3644 fp = stringio() | 3697 fp = stringio() |
3645 # chunks are serialized per file, but files aren't sorted | 3698 # chunks are serialized per file, but files aren't sorted |
3646 for f in sorted(set(c.header.filename() for c in chunks if ishunk(c))): | 3699 for f in sorted(set(c.header.filename() for c in chunks if ishunk(c))): |
3647 prntstatusmsg('revert', f) | 3700 prntstatusmsg(b'revert', f) |
3648 files = set() | 3701 files = set() |
3649 for c in chunks: | 3702 for c in chunks: |
3650 if ishunk(c): | 3703 if ishunk(c): |
3651 abs = c.header.filename() | 3704 abs = c.header.filename() |
3652 # Create a backup file only if this hunk should be backed up | 3705 # Create a backup file only if this hunk should be backed up |
3655 bakname = scmutil.backuppath(repo.ui, repo, abs) | 3708 bakname = scmutil.backuppath(repo.ui, repo, abs) |
3656 util.copyfile(target, bakname) | 3709 util.copyfile(target, bakname) |
3657 tobackup.remove(abs) | 3710 tobackup.remove(abs) |
3658 if abs not in files: | 3711 if abs not in files: |
3659 files.add(abs) | 3712 files.add(abs) |
3660 if operation == 'keep': | 3713 if operation == b'keep': |
3661 checkout(abs) | 3714 checkout(abs) |
3662 c.write(fp) | 3715 c.write(fp) |
3663 dopatch = fp.tell() | 3716 dopatch = fp.tell() |
3664 fp.seek(0) | 3717 fp.seek(0) |
3665 if dopatch: | 3718 if dopatch: |
3667 patch.internalpatch(repo.ui, repo, fp, 1, eolmode=None) | 3720 patch.internalpatch(repo.ui, repo, fp, 1, eolmode=None) |
3668 except error.PatchError as err: | 3721 except error.PatchError as err: |
3669 raise error.Abort(pycompat.bytestr(err)) | 3722 raise error.Abort(pycompat.bytestr(err)) |
3670 del fp | 3723 del fp |
3671 else: | 3724 else: |
3672 for f in actions['revert'][0]: | 3725 for f in actions[b'revert'][0]: |
3673 prntstatusmsg('revert', f) | 3726 prntstatusmsg(b'revert', f) |
3674 checkout(f) | 3727 checkout(f) |
3675 if normal: | 3728 if normal: |
3676 normal(f) | 3729 normal(f) |
3677 | 3730 |
3678 for f in actions['add'][0]: | 3731 for f in actions[b'add'][0]: |
3679 # Don't checkout modified files, they are already created by the diff | 3732 # Don't checkout modified files, they are already created by the diff |
3680 if f not in newlyaddedandmodifiedfiles: | 3733 if f not in newlyaddedandmodifiedfiles: |
3681 prntstatusmsg('add', f) | 3734 prntstatusmsg(b'add', f) |
3682 checkout(f) | 3735 checkout(f) |
3683 repo.dirstate.add(f) | 3736 repo.dirstate.add(f) |
3684 | 3737 |
3685 normal = repo.dirstate.normallookup | 3738 normal = repo.dirstate.normallookup |
3686 if node == parent and p2 == nullid: | 3739 if node == parent and p2 == nullid: |
3687 normal = repo.dirstate.normal | 3740 normal = repo.dirstate.normal |
3688 for f in actions['undelete'][0]: | 3741 for f in actions[b'undelete'][0]: |
3689 if interactive: | 3742 if interactive: |
3690 choice = repo.ui.promptchoice( | 3743 choice = repo.ui.promptchoice( |
3691 _("add back removed file %s (Yn)?$$ &Yes $$ &No") % f | 3744 _(b"add back removed file %s (Yn)?$$ &Yes $$ &No") % f |
3692 ) | 3745 ) |
3693 if choice == 0: | 3746 if choice == 0: |
3694 prntstatusmsg('undelete', f) | 3747 prntstatusmsg(b'undelete', f) |
3695 checkout(f) | 3748 checkout(f) |
3696 normal(f) | 3749 normal(f) |
3697 else: | 3750 else: |
3698 excluded_files.append(f) | 3751 excluded_files.append(f) |
3699 else: | 3752 else: |
3700 prntstatusmsg('undelete', f) | 3753 prntstatusmsg(b'undelete', f) |
3701 checkout(f) | 3754 checkout(f) |
3702 normal(f) | 3755 normal(f) |
3703 | 3756 |
3704 copied = copies.pathcopies(repo[parent], ctx) | 3757 copied = copies.pathcopies(repo[parent], ctx) |
3705 | 3758 |
3706 for f in actions['add'][0] + actions['undelete'][0] + actions['revert'][0]: | 3759 for f in ( |
3760 actions[b'add'][0] + actions[b'undelete'][0] + actions[b'revert'][0] | |
3761 ): | |
3707 if f in copied: | 3762 if f in copied: |
3708 repo.dirstate.copy(copied[f], f) | 3763 repo.dirstate.copy(copied[f], f) |
3709 | 3764 |
3710 | 3765 |
3711 # a list of (ui, repo, otherpeer, opts, missing) functions called by | 3766 # a list of (ui, repo, otherpeer, opts, missing) functions called by |
3746 | 3801 |
3747 for s in statemod._unfinishedstates: | 3802 for s in statemod._unfinishedstates: |
3748 if ( | 3803 if ( |
3749 not s._clearable | 3804 not s._clearable |
3750 or (commit and s._allowcommit) | 3805 or (commit and s._allowcommit) |
3751 or (s._opname == 'merge' and skipmerge) | 3806 or (s._opname == b'merge' and skipmerge) |
3752 or s._reportonly | 3807 or s._reportonly |
3753 ): | 3808 ): |
3754 continue | 3809 continue |
3755 if s.isunfinished(repo): | 3810 if s.isunfinished(repo): |
3756 raise error.Abort(s.msg(), hint=s.hint()) | 3811 raise error.Abort(s.msg(), hint=s.hint()) |
3765 continue | 3820 continue |
3766 if not state._clearable and state.isunfinished(repo): | 3821 if not state._clearable and state.isunfinished(repo): |
3767 raise error.Abort(state.msg(), hint=state.hint()) | 3822 raise error.Abort(state.msg(), hint=state.hint()) |
3768 | 3823 |
3769 for s in statemod._unfinishedstates: | 3824 for s in statemod._unfinishedstates: |
3770 if s._opname == 'merge' or state._reportonly: | 3825 if s._opname == b'merge' or state._reportonly: |
3771 continue | 3826 continue |
3772 if s._clearable and s.isunfinished(repo): | 3827 if s._clearable and s.isunfinished(repo): |
3773 util.unlink(repo.vfs.join(s._fname)) | 3828 util.unlink(repo.vfs.join(s._fname)) |
3774 | 3829 |
3775 | 3830 |
3791 continue is supported by the operation. | 3846 continue is supported by the operation. |
3792 | 3847 |
3793 Returns a (msg, warning) tuple. 'msg' is a string and 'warning' is | 3848 Returns a (msg, warning) tuple. 'msg' is a string and 'warning' is |
3794 a boolean. | 3849 a boolean. |
3795 ''' | 3850 ''' |
3796 contmsg = _("continue: %s") | 3851 contmsg = _(b"continue: %s") |
3797 for state in statemod._unfinishedstates: | 3852 for state in statemod._unfinishedstates: |
3798 if not state._continueflag: | 3853 if not state._continueflag: |
3799 continue | 3854 continue |
3800 if state.isunfinished(repo): | 3855 if state.isunfinished(repo): |
3801 return contmsg % state.continuemsg(), True | 3856 return contmsg % state.continuemsg(), True |
3802 if repo[None].dirty(missing=True, merge=False, branch=False): | 3857 if repo[None].dirty(missing=True, merge=False, branch=False): |
3803 return contmsg % _("hg commit"), False | 3858 return contmsg % _(b"hg commit"), False |
3804 return None, None | 3859 return None, None |
3805 | 3860 |
3806 | 3861 |
3807 def checkafterresolved(repo): | 3862 def checkafterresolved(repo): |
3808 '''Inform the user about the next action after completing hg resolve | 3863 '''Inform the user about the next action after completing hg resolve |
3813 Otherwise, it will yield repo.ui.note. | 3868 Otherwise, it will yield repo.ui.note. |
3814 ''' | 3869 ''' |
3815 msg, warning = howtocontinue(repo) | 3870 msg, warning = howtocontinue(repo) |
3816 if msg is not None: | 3871 if msg is not None: |
3817 if warning: | 3872 if warning: |
3818 repo.ui.warn("%s\n" % msg) | 3873 repo.ui.warn(b"%s\n" % msg) |
3819 else: | 3874 else: |
3820 repo.ui.note("%s\n" % msg) | 3875 repo.ui.note(b"%s\n" % msg) |
3821 | 3876 |
3822 | 3877 |
3823 def wrongtooltocontinue(repo, task): | 3878 def wrongtooltocontinue(repo, task): |
3824 '''Raise an abort suggesting how to properly continue if there is an | 3879 '''Raise an abort suggesting how to properly continue if there is an |
3825 active task. | 3880 active task. |
3831 ''' | 3886 ''' |
3832 after = howtocontinue(repo) | 3887 after = howtocontinue(repo) |
3833 hint = None | 3888 hint = None |
3834 if after[1]: | 3889 if after[1]: |
3835 hint = after[0] | 3890 hint = after[0] |
3836 raise error.Abort(_('no %s in progress') % task, hint=hint) | 3891 raise error.Abort(_(b'no %s in progress') % task, hint=hint) |
3837 | 3892 |
3838 | 3893 |
3839 def abortgraft(ui, repo, graftstate): | 3894 def abortgraft(ui, repo, graftstate): |
3840 """abort the interrupted graft and rollbacks to the state before interrupted | 3895 """abort the interrupted graft and rollbacks to the state before interrupted |
3841 graft""" | 3896 graft""" |
3842 if not graftstate.exists(): | 3897 if not graftstate.exists(): |
3843 raise error.Abort(_("no interrupted graft to abort")) | 3898 raise error.Abort(_(b"no interrupted graft to abort")) |
3844 statedata = readgraftstate(repo, graftstate) | 3899 statedata = readgraftstate(repo, graftstate) |
3845 newnodes = statedata.get('newnodes') | 3900 newnodes = statedata.get(b'newnodes') |
3846 if newnodes is None: | 3901 if newnodes is None: |
3847 # and old graft state which does not have all the data required to abort | 3902 # and old graft state which does not have all the data required to abort |
3848 # the graft | 3903 # the graft |
3849 raise error.Abort(_("cannot abort using an old graftstate")) | 3904 raise error.Abort(_(b"cannot abort using an old graftstate")) |
3850 | 3905 |
3851 # changeset from which graft operation was started | 3906 # changeset from which graft operation was started |
3852 if len(newnodes) > 0: | 3907 if len(newnodes) > 0: |
3853 startctx = repo[newnodes[0]].p1() | 3908 startctx = repo[newnodes[0]].p1() |
3854 else: | 3909 else: |
3855 startctx = repo['.'] | 3910 startctx = repo[b'.'] |
3856 # whether to strip or not | 3911 # whether to strip or not |
3857 cleanup = False | 3912 cleanup = False |
3858 from . import hg | 3913 from . import hg |
3859 | 3914 |
3860 if newnodes: | 3915 if newnodes: |
3862 cleanup = True | 3917 cleanup = True |
3863 # checking that none of the newnodes turned public or is public | 3918 # checking that none of the newnodes turned public or is public |
3864 immutable = [c for c in newnodes if not repo[c].mutable()] | 3919 immutable = [c for c in newnodes if not repo[c].mutable()] |
3865 if immutable: | 3920 if immutable: |
3866 repo.ui.warn( | 3921 repo.ui.warn( |
3867 _("cannot clean up public changesets %s\n") | 3922 _(b"cannot clean up public changesets %s\n") |
3868 % ', '.join(bytes(repo[r]) for r in immutable), | 3923 % b', '.join(bytes(repo[r]) for r in immutable), |
3869 hint=_("see 'hg help phases' for details"), | 3924 hint=_(b"see 'hg help phases' for details"), |
3870 ) | 3925 ) |
3871 cleanup = False | 3926 cleanup = False |
3872 | 3927 |
3873 # checking that no new nodes are created on top of grafted revs | 3928 # checking that no new nodes are created on top of grafted revs |
3874 desc = set(repo.changelog.descendants(newnodes)) | 3929 desc = set(repo.changelog.descendants(newnodes)) |
3875 if desc - set(newnodes): | 3930 if desc - set(newnodes): |
3876 repo.ui.warn( | 3931 repo.ui.warn( |
3877 _( | 3932 _( |
3878 "new changesets detected on destination " | 3933 b"new changesets detected on destination " |
3879 "branch, can't strip\n" | 3934 b"branch, can't strip\n" |
3880 ) | 3935 ) |
3881 ) | 3936 ) |
3882 cleanup = False | 3937 cleanup = False |
3883 | 3938 |
3884 if cleanup: | 3939 if cleanup: |
3885 with repo.wlock(), repo.lock(): | 3940 with repo.wlock(), repo.lock(): |
3886 hg.updaterepo(repo, startctx.node(), overwrite=True) | 3941 hg.updaterepo(repo, startctx.node(), overwrite=True) |
3887 # stripping the new nodes created | 3942 # stripping the new nodes created |
3888 strippoints = [ | 3943 strippoints = [ |
3889 c.node() for c in repo.set("roots(%ld)", newnodes) | 3944 c.node() for c in repo.set(b"roots(%ld)", newnodes) |
3890 ] | 3945 ] |
3891 repair.strip(repo.ui, repo, strippoints, backup=False) | 3946 repair.strip(repo.ui, repo, strippoints, backup=False) |
3892 | 3947 |
3893 if not cleanup: | 3948 if not cleanup: |
3894 # we don't update to the startnode if we can't strip | 3949 # we don't update to the startnode if we can't strip |
3895 startctx = repo['.'] | 3950 startctx = repo[b'.'] |
3896 hg.updaterepo(repo, startctx.node(), overwrite=True) | 3951 hg.updaterepo(repo, startctx.node(), overwrite=True) |
3897 | 3952 |
3898 ui.status(_("graft aborted\n")) | 3953 ui.status(_(b"graft aborted\n")) |
3899 ui.status(_("working directory is now at %s\n") % startctx.hex()[:12]) | 3954 ui.status(_(b"working directory is now at %s\n") % startctx.hex()[:12]) |
3900 graftstate.delete() | 3955 graftstate.delete() |
3901 return 0 | 3956 return 0 |
3902 | 3957 |
3903 | 3958 |
3904 def readgraftstate(repo, graftstate): | 3959 def readgraftstate(repo, graftstate): |
3905 """read the graft state file and return a dict of the data stored in it""" | 3960 """read the graft state file and return a dict of the data stored in it""" |
3906 try: | 3961 try: |
3907 return graftstate.read() | 3962 return graftstate.read() |
3908 except error.CorruptedState: | 3963 except error.CorruptedState: |
3909 nodes = repo.vfs.read('graftstate').splitlines() | 3964 nodes = repo.vfs.read(b'graftstate').splitlines() |
3910 return {'nodes': nodes} | 3965 return {b'nodes': nodes} |
3911 | 3966 |
3912 | 3967 |
3913 def hgabortgraft(ui, repo): | 3968 def hgabortgraft(ui, repo): |
3914 """ abort logic for aborting graft using 'hg abort'""" | 3969 """ abort logic for aborting graft using 'hg abort'""" |
3915 with repo.wlock(): | 3970 with repo.wlock(): |
3916 graftstate = statemod.cmdstate(repo, 'graftstate') | 3971 graftstate = statemod.cmdstate(repo, b'graftstate') |
3917 return abortgraft(ui, repo, graftstate) | 3972 return abortgraft(ui, repo, graftstate) |