comparison mercurial/shelve.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
54 from .utils import ( 54 from .utils import (
55 dateutil, 55 dateutil,
56 stringutil, 56 stringutil,
57 ) 57 )
58 58
59 backupdir = 'shelve-backup' 59 backupdir = b'shelve-backup'
60 shelvedir = 'shelved' 60 shelvedir = b'shelved'
61 shelvefileextensions = ['hg', 'patch', 'shelve'] 61 shelvefileextensions = [b'hg', b'patch', b'shelve']
62 # universal extension is present in all types of shelves 62 # universal extension is present in all types of shelves
63 patchextension = 'patch' 63 patchextension = b'patch'
64 64
65 # we never need the user, so we use a 65 # we never need the user, so we use a
66 # generic user for all shelve operations 66 # generic user for all shelve operations
67 shelveuser = 'shelve@localhost' 67 shelveuser = b'shelve@localhost'
68 68
69 69
70 class shelvedfile(object): 70 class shelvedfile(object):
71 """Helper for the file storing a single shelve 71 """Helper for the file storing a single shelve
72 72
78 self.name = name 78 self.name = name
79 self.vfs = vfsmod.vfs(repo.vfs.join(shelvedir)) 79 self.vfs = vfsmod.vfs(repo.vfs.join(shelvedir))
80 self.backupvfs = vfsmod.vfs(repo.vfs.join(backupdir)) 80 self.backupvfs = vfsmod.vfs(repo.vfs.join(backupdir))
81 self.ui = self.repo.ui 81 self.ui = self.repo.ui
82 if filetype: 82 if filetype:
83 self.fname = name + '.' + filetype 83 self.fname = name + b'.' + filetype
84 else: 84 else:
85 self.fname = name 85 self.fname = name
86 86
87 def exists(self): 87 def exists(self):
88 return self.vfs.exists(self.fname) 88 return self.vfs.exists(self.fname)
91 return self.vfs.join(self.fname) 91 return self.vfs.join(self.fname)
92 92
93 def backupfilename(self): 93 def backupfilename(self):
94 def gennames(base): 94 def gennames(base):
95 yield base 95 yield base
96 base, ext = base.rsplit('.', 1) 96 base, ext = base.rsplit(b'.', 1)
97 for i in itertools.count(1): 97 for i in itertools.count(1):
98 yield '%s-%d.%s' % (base, i, ext) 98 yield b'%s-%d.%s' % (base, i, ext)
99 99
100 name = self.backupvfs.join(self.fname) 100 name = self.backupvfs.join(self.fname)
101 for n in gennames(name): 101 for n in gennames(name):
102 if not self.backupvfs.exists(n): 102 if not self.backupvfs.exists(n):
103 return n 103 return n
108 util.rename(self.filename(), self.backupfilename()) 108 util.rename(self.filename(), self.backupfilename())
109 109
110 def stat(self): 110 def stat(self):
111 return self.vfs.stat(self.fname) 111 return self.vfs.stat(self.fname)
112 112
113 def opener(self, mode='rb'): 113 def opener(self, mode=b'rb'):
114 try: 114 try:
115 return self.vfs(self.fname, mode) 115 return self.vfs(self.fname, mode)
116 except IOError as err: 116 except IOError as err:
117 if err.errno != errno.ENOENT: 117 if err.errno != errno.ENOENT:
118 raise 118 raise
119 raise error.Abort(_("shelved change '%s' not found") % self.name) 119 raise error.Abort(_(b"shelved change '%s' not found") % self.name)
120 120
121 def applybundle(self, tr): 121 def applybundle(self, tr):
122 fp = self.opener() 122 fp = self.opener()
123 try: 123 try:
124 targetphase = phases.internal 124 targetphase = phases.internal
125 if not phases.supportinternal(self.repo): 125 if not phases.supportinternal(self.repo):
126 targetphase = phases.secret 126 targetphase = phases.secret
127 gen = exchange.readbundle(self.repo.ui, fp, self.fname, self.vfs) 127 gen = exchange.readbundle(self.repo.ui, fp, self.fname, self.vfs)
128 pretip = self.repo['tip'] 128 pretip = self.repo[b'tip']
129 bundle2.applybundle( 129 bundle2.applybundle(
130 self.repo, 130 self.repo,
131 gen, 131 gen,
132 tr, 132 tr,
133 source='unshelve', 133 source=b'unshelve',
134 url='bundle:' + self.vfs.join(self.fname), 134 url=b'bundle:' + self.vfs.join(self.fname),
135 targetphase=targetphase, 135 targetphase=targetphase,
136 ) 136 )
137 shelvectx = self.repo['tip'] 137 shelvectx = self.repo[b'tip']
138 if pretip == shelvectx: 138 if pretip == shelvectx:
139 shelverev = tr.changes['revduplicates'][-1] 139 shelverev = tr.changes[b'revduplicates'][-1]
140 shelvectx = self.repo[shelverev] 140 shelvectx = self.repo[shelverev]
141 return shelvectx 141 return shelvectx
142 finally: 142 finally:
143 fp.close() 143 fp.close()
144 144
145 def bundlerepo(self): 145 def bundlerepo(self):
146 path = self.vfs.join(self.fname) 146 path = self.vfs.join(self.fname)
147 return bundlerepo.instance( 147 return bundlerepo.instance(
148 self.repo.baseui, 'bundle://%s+%s' % (self.repo.root, path) 148 self.repo.baseui, b'bundle://%s+%s' % (self.repo.root, path)
149 ) 149 )
150 150
151 def writebundle(self, bases, node): 151 def writebundle(self, bases, node):
152 cgversion = changegroup.safeversion(self.repo) 152 cgversion = changegroup.safeversion(self.repo)
153 if cgversion == '01': 153 if cgversion == b'01':
154 btype = 'HG10BZ' 154 btype = b'HG10BZ'
155 compression = None 155 compression = None
156 else: 156 else:
157 btype = 'HG20' 157 btype = b'HG20'
158 compression = 'BZ' 158 compression = b'BZ'
159 159
160 repo = self.repo.unfiltered() 160 repo = self.repo.unfiltered()
161 161
162 outgoing = discovery.outgoing( 162 outgoing = discovery.outgoing(
163 repo, missingroots=bases, missingheads=[node] 163 repo, missingroots=bases, missingheads=[node]
164 ) 164 )
165 cg = changegroup.makechangegroup(repo, outgoing, cgversion, 'shelve') 165 cg = changegroup.makechangegroup(repo, outgoing, cgversion, b'shelve')
166 166
167 bundle2.writebundle( 167 bundle2.writebundle(
168 self.ui, cg, self.fname, btype, self.vfs, compression=compression 168 self.ui, cg, self.fname, btype, self.vfs, compression=compression
169 ) 169 )
170 170
181 Handles saving and restoring a shelved state. Ensures that different 181 Handles saving and restoring a shelved state. Ensures that different
182 versions of a shelved state are possible and handles them appropriately. 182 versions of a shelved state are possible and handles them appropriately.
183 """ 183 """
184 184
185 _version = 2 185 _version = 2
186 _filename = 'shelvedstate' 186 _filename = b'shelvedstate'
187 _keep = 'keep' 187 _keep = b'keep'
188 _nokeep = 'nokeep' 188 _nokeep = b'nokeep'
189 # colon is essential to differentiate from a real bookmark name 189 # colon is essential to differentiate from a real bookmark name
190 _noactivebook = ':no-active-bookmark' 190 _noactivebook = b':no-active-bookmark'
191 _interactive = 'interactive' 191 _interactive = b'interactive'
192 192
193 @classmethod 193 @classmethod
194 def _verifyandtransform(cls, d): 194 def _verifyandtransform(cls, d):
195 """Some basic shelvestate syntactic verification and transformation""" 195 """Some basic shelvestate syntactic verification and transformation"""
196 try: 196 try:
197 d['originalwctx'] = nodemod.bin(d['originalwctx']) 197 d[b'originalwctx'] = nodemod.bin(d[b'originalwctx'])
198 d['pendingctx'] = nodemod.bin(d['pendingctx']) 198 d[b'pendingctx'] = nodemod.bin(d[b'pendingctx'])
199 d['parents'] = [nodemod.bin(h) for h in d['parents'].split(' ')] 199 d[b'parents'] = [nodemod.bin(h) for h in d[b'parents'].split(b' ')]
200 d['nodestoremove'] = [ 200 d[b'nodestoremove'] = [
201 nodemod.bin(h) for h in d['nodestoremove'].split(' ') 201 nodemod.bin(h) for h in d[b'nodestoremove'].split(b' ')
202 ] 202 ]
203 except (ValueError, TypeError, KeyError) as err: 203 except (ValueError, TypeError, KeyError) as err:
204 raise error.CorruptedState(pycompat.bytestr(err)) 204 raise error.CorruptedState(pycompat.bytestr(err))
205 205
206 @classmethod 206 @classmethod
220 """Read the old position-based version of a shelvestate file""" 220 """Read the old position-based version of a shelvestate file"""
221 # Order is important, because old shelvestate file uses it 221 # Order is important, because old shelvestate file uses it
222 # to detemine values of fields (i.g. name is on the second line, 222 # to detemine values of fields (i.g. name is on the second line,
223 # originalwctx is on the third and so forth). Please do not change. 223 # originalwctx is on the third and so forth). Please do not change.
224 keys = [ 224 keys = [
225 'version', 225 b'version',
226 'name', 226 b'name',
227 'originalwctx', 227 b'originalwctx',
228 'pendingctx', 228 b'pendingctx',
229 'parents', 229 b'parents',
230 'nodestoremove', 230 b'nodestoremove',
231 'branchtorestore', 231 b'branchtorestore',
232 'keep', 232 b'keep',
233 'activebook', 233 b'activebook',
234 ] 234 ]
235 # this is executed only seldomly, so it is not a big deal 235 # this is executed only seldomly, so it is not a big deal
236 # that we open this file twice 236 # that we open this file twice
237 fp = repo.vfs(cls._filename) 237 fp = repo.vfs(cls._filename)
238 d = {} 238 d = {}
253 firstlinenonkeyval=True 253 firstlinenonkeyval=True
254 ) 254 )
255 else: 255 else:
256 raise error.Abort( 256 raise error.Abort(
257 _( 257 _(
258 'this version of shelve is incompatible ' 258 b'this version of shelve is incompatible '
259 'with the version used in this repo' 259 b'with the version used in this repo'
260 ) 260 )
261 ) 261 )
262 262
263 cls._verifyandtransform(d) 263 cls._verifyandtransform(d)
264 try: 264 try:
265 obj = cls() 265 obj = cls()
266 obj.name = d['name'] 266 obj.name = d[b'name']
267 obj.wctx = repo[d['originalwctx']] 267 obj.wctx = repo[d[b'originalwctx']]
268 obj.pendingctx = repo[d['pendingctx']] 268 obj.pendingctx = repo[d[b'pendingctx']]
269 obj.parents = d['parents'] 269 obj.parents = d[b'parents']
270 obj.nodestoremove = d['nodestoremove'] 270 obj.nodestoremove = d[b'nodestoremove']
271 obj.branchtorestore = d.get('branchtorestore', '') 271 obj.branchtorestore = d.get(b'branchtorestore', b'')
272 obj.keep = d.get('keep') == cls._keep 272 obj.keep = d.get(b'keep') == cls._keep
273 obj.activebookmark = '' 273 obj.activebookmark = b''
274 if d.get('activebook', '') != cls._noactivebook: 274 if d.get(b'activebook', b'') != cls._noactivebook:
275 obj.activebookmark = d.get('activebook', '') 275 obj.activebookmark = d.get(b'activebook', b'')
276 obj.interactive = d.get('interactive') == cls._interactive 276 obj.interactive = d.get(b'interactive') == cls._interactive
277 except (error.RepoLookupError, KeyError) as err: 277 except (error.RepoLookupError, KeyError) as err:
278 raise error.CorruptedState(pycompat.bytestr(err)) 278 raise error.CorruptedState(pycompat.bytestr(err))
279 279
280 return obj 280 return obj
281 281
287 originalwctx, 287 originalwctx,
288 pendingctx, 288 pendingctx,
289 nodestoremove, 289 nodestoremove,
290 branchtorestore, 290 branchtorestore,
291 keep=False, 291 keep=False,
292 activebook='', 292 activebook=b'',
293 interactive=False, 293 interactive=False,
294 ): 294 ):
295 info = { 295 info = {
296 "name": name, 296 b"name": name,
297 "originalwctx": nodemod.hex(originalwctx.node()), 297 b"originalwctx": nodemod.hex(originalwctx.node()),
298 "pendingctx": nodemod.hex(pendingctx.node()), 298 b"pendingctx": nodemod.hex(pendingctx.node()),
299 "parents": ' '.join( 299 b"parents": b' '.join(
300 [nodemod.hex(p) for p in repo.dirstate.parents()] 300 [nodemod.hex(p) for p in repo.dirstate.parents()]
301 ), 301 ),
302 "nodestoremove": ' '.join([nodemod.hex(n) for n in nodestoremove]), 302 b"nodestoremove": b' '.join(
303 "branchtorestore": branchtorestore, 303 [nodemod.hex(n) for n in nodestoremove]
304 "keep": cls._keep if keep else cls._nokeep, 304 ),
305 "activebook": activebook or cls._noactivebook, 305 b"branchtorestore": branchtorestore,
306 b"keep": cls._keep if keep else cls._nokeep,
307 b"activebook": activebook or cls._noactivebook,
306 } 308 }
307 if interactive: 309 if interactive:
308 info['interactive'] = cls._interactive 310 info[b'interactive'] = cls._interactive
309 scmutil.simplekeyvaluefile(repo.vfs, cls._filename).write( 311 scmutil.simplekeyvaluefile(repo.vfs, cls._filename).write(
310 info, firstline=("%d" % cls._version) 312 info, firstline=(b"%d" % cls._version)
311 ) 313 )
312 314
313 @classmethod 315 @classmethod
314 def clear(cls, repo): 316 def clear(cls, repo):
315 repo.vfs.unlinkpath(cls._filename, ignoremissing=True) 317 repo.vfs.unlinkpath(cls._filename, ignoremissing=True)
316 318
317 319
318 def cleanupoldbackups(repo): 320 def cleanupoldbackups(repo):
319 vfs = vfsmod.vfs(repo.vfs.join(backupdir)) 321 vfs = vfsmod.vfs(repo.vfs.join(backupdir))
320 maxbackups = repo.ui.configint('shelve', 'maxbackups') 322 maxbackups = repo.ui.configint(b'shelve', b'maxbackups')
321 hgfiles = [f for f in vfs.listdir() if f.endswith('.' + patchextension)] 323 hgfiles = [f for f in vfs.listdir() if f.endswith(b'.' + patchextension)]
322 hgfiles = sorted([(vfs.stat(f)[stat.ST_MTIME], f) for f in hgfiles]) 324 hgfiles = sorted([(vfs.stat(f)[stat.ST_MTIME], f) for f in hgfiles])
323 if maxbackups > 0 and maxbackups < len(hgfiles): 325 if maxbackups > 0 and maxbackups < len(hgfiles):
324 bordermtime = hgfiles[-maxbackups][0] 326 bordermtime = hgfiles[-maxbackups][0]
325 else: 327 else:
326 bordermtime = None 328 bordermtime = None
328 if mtime == bordermtime: 330 if mtime == bordermtime:
329 # keep it, because timestamp can't decide exact order of backups 331 # keep it, because timestamp can't decide exact order of backups
330 continue 332 continue
331 base = f[: -(1 + len(patchextension))] 333 base = f[: -(1 + len(patchextension))]
332 for ext in shelvefileextensions: 334 for ext in shelvefileextensions:
333 vfs.tryunlink(base + '.' + ext) 335 vfs.tryunlink(base + b'.' + ext)
334 336
335 337
336 def _backupactivebookmark(repo): 338 def _backupactivebookmark(repo):
337 activebookmark = repo._activebookmark 339 activebookmark = repo._activebookmark
338 if activebookmark: 340 if activebookmark:
346 348
347 349
348 def _aborttransaction(repo, tr): 350 def _aborttransaction(repo, tr):
349 '''Abort current transaction for shelve/unshelve, but keep dirstate 351 '''Abort current transaction for shelve/unshelve, but keep dirstate
350 ''' 352 '''
351 dirstatebackupname = 'dirstate.shelve' 353 dirstatebackupname = b'dirstate.shelve'
352 repo.dirstate.savebackup(tr, dirstatebackupname) 354 repo.dirstate.savebackup(tr, dirstatebackupname)
353 tr.abort() 355 tr.abort()
354 repo.dirstate.restorebackup(None, dirstatebackupname) 356 repo.dirstate.restorebackup(None, dirstatebackupname)
355 357
356 358
358 """Decide on the name this shelve is going to have""" 360 """Decide on the name this shelve is going to have"""
359 361
360 def gennames(): 362 def gennames():
361 yield label 363 yield label
362 for i in itertools.count(1): 364 for i in itertools.count(1):
363 yield '%s-%02d' % (label, i) 365 yield b'%s-%02d' % (label, i)
364 366
365 name = opts.get('name') 367 name = opts.get(b'name')
366 label = repo._activebookmark or parent.branch() or 'default' 368 label = repo._activebookmark or parent.branch() or b'default'
367 # slashes aren't allowed in filenames, therefore we rename it 369 # slashes aren't allowed in filenames, therefore we rename it
368 label = label.replace('/', '_') 370 label = label.replace(b'/', b'_')
369 label = label.replace('\\', '_') 371 label = label.replace(b'\\', b'_')
370 # filenames must not start with '.' as it should not be hidden 372 # filenames must not start with '.' as it should not be hidden
371 if label.startswith('.'): 373 if label.startswith(b'.'):
372 label = label.replace('.', '_', 1) 374 label = label.replace(b'.', b'_', 1)
373 375
374 if name: 376 if name:
375 if shelvedfile(repo, name, patchextension).exists(): 377 if shelvedfile(repo, name, patchextension).exists():
376 e = _("a shelved change named '%s' already exists") % name 378 e = _(b"a shelved change named '%s' already exists") % name
377 raise error.Abort(e) 379 raise error.Abort(e)
378 380
379 # ensure we are not creating a subdirectory or a hidden file 381 # ensure we are not creating a subdirectory or a hidden file
380 if '/' in name or '\\' in name: 382 if b'/' in name or b'\\' in name:
381 raise error.Abort(_('shelved change names can not contain slashes')) 383 raise error.Abort(
382 if name.startswith('.'): 384 _(b'shelved change names can not contain slashes')
383 raise error.Abort(_("shelved change names can not start with '.'")) 385 )
386 if name.startswith(b'.'):
387 raise error.Abort(_(b"shelved change names can not start with '.'"))
384 388
385 else: 389 else:
386 for n in gennames(): 390 for n in gennames():
387 if not shelvedfile(repo, n, patchextension).exists(): 391 if not shelvedfile(repo, n, patchextension).exists():
388 name = n 392 name = n
409 visit.append(parent) 413 visit.append(parent)
410 414
411 415
412 def getcommitfunc(extra, interactive, editor=False): 416 def getcommitfunc(extra, interactive, editor=False):
413 def commitfunc(ui, repo, message, match, opts): 417 def commitfunc(ui, repo, message, match, opts):
414 hasmq = util.safehasattr(repo, 'mq') 418 hasmq = util.safehasattr(repo, b'mq')
415 if hasmq: 419 if hasmq:
416 saved, repo.mq.checkapplied = repo.mq.checkapplied, False 420 saved, repo.mq.checkapplied = repo.mq.checkapplied, False
417 421
418 targetphase = phases.internal 422 targetphase = phases.internal
419 if not phases.supportinternal(repo): 423 if not phases.supportinternal(repo):
420 targetphase = phases.secret 424 targetphase = phases.secret
421 overrides = {('phases', 'new-commit'): targetphase} 425 overrides = {(b'phases', b'new-commit'): targetphase}
422 try: 426 try:
423 editor_ = False 427 editor_ = False
424 if editor: 428 if editor:
425 editor_ = cmdutil.getcommiteditor( 429 editor_ = cmdutil.getcommiteditor(
426 editform='shelve.shelve', **pycompat.strkwargs(opts) 430 editform=b'shelve.shelve', **pycompat.strkwargs(opts)
427 ) 431 )
428 with repo.ui.configoverride(overrides): 432 with repo.ui.configoverride(overrides):
429 return repo.commit( 433 return repo.commit(
430 message, 434 message,
431 shelveuser, 435 shelveuser,
432 opts.get('date'), 436 opts.get(b'date'),
433 match, 437 match,
434 editor=editor_, 438 editor=editor_,
435 extra=extra, 439 extra=extra,
436 ) 440 )
437 finally: 441 finally:
438 if hasmq: 442 if hasmq:
439 repo.mq.checkapplied = saved 443 repo.mq.checkapplied = saved
440 444
441 def interactivecommitfunc(ui, repo, *pats, **opts): 445 def interactivecommitfunc(ui, repo, *pats, **opts):
442 opts = pycompat.byteskwargs(opts) 446 opts = pycompat.byteskwargs(opts)
443 match = scmutil.match(repo['.'], pats, {}) 447 match = scmutil.match(repo[b'.'], pats, {})
444 message = opts['message'] 448 message = opts[b'message']
445 return commitfunc(ui, repo, message, match, opts) 449 return commitfunc(ui, repo, message, match, opts)
446 450
447 return interactivecommitfunc if interactive else commitfunc 451 return interactivecommitfunc if interactive else commitfunc
448 452
449 453
450 def _nothingtoshelvemessaging(ui, repo, pats, opts): 454 def _nothingtoshelvemessaging(ui, repo, pats, opts):
451 stat = repo.status(match=scmutil.match(repo[None], pats, opts)) 455 stat = repo.status(match=scmutil.match(repo[None], pats, opts))
452 if stat.deleted: 456 if stat.deleted:
453 ui.status( 457 ui.status(
454 _("nothing changed (%d missing files, see " "'hg status')\n") 458 _(b"nothing changed (%d missing files, see " b"'hg status')\n")
455 % len(stat.deleted) 459 % len(stat.deleted)
456 ) 460 )
457 else: 461 else:
458 ui.status(_("nothing changed\n")) 462 ui.status(_(b"nothing changed\n"))
459 463
460 464
461 def _shelvecreatedcommit(repo, node, name, match): 465 def _shelvecreatedcommit(repo, node, name, match):
462 info = {'node': nodemod.hex(node)} 466 info = {b'node': nodemod.hex(node)}
463 shelvedfile(repo, name, 'shelve').writeinfo(info) 467 shelvedfile(repo, name, b'shelve').writeinfo(info)
464 bases = list(mutableancestors(repo[node])) 468 bases = list(mutableancestors(repo[node]))
465 shelvedfile(repo, name, 'hg').writebundle(bases, node) 469 shelvedfile(repo, name, b'hg').writebundle(bases, node)
466 with shelvedfile(repo, name, patchextension).opener('wb') as fp: 470 with shelvedfile(repo, name, patchextension).opener(b'wb') as fp:
467 cmdutil.exportfile( 471 cmdutil.exportfile(
468 repo, [node], fp, opts=mdiff.diffopts(git=True), match=match 472 repo, [node], fp, opts=mdiff.diffopts(git=True), match=match
469 ) 473 )
470 474
471 475
472 def _includeunknownfiles(repo, pats, opts, extra): 476 def _includeunknownfiles(repo, pats, opts, extra):
473 s = repo.status(match=scmutil.match(repo[None], pats, opts), unknown=True) 477 s = repo.status(match=scmutil.match(repo[None], pats, opts), unknown=True)
474 if s.unknown: 478 if s.unknown:
475 extra['shelve_unknown'] = '\0'.join(s.unknown) 479 extra[b'shelve_unknown'] = b'\0'.join(s.unknown)
476 repo[None].add(s.unknown) 480 repo[None].add(s.unknown)
477 481
478 482
479 def _finishshelve(repo, tr): 483 def _finishshelve(repo, tr):
480 if phases.supportinternal(repo): 484 if phases.supportinternal(repo):
495 parents = wctx.parents() 499 parents = wctx.parents()
496 parent = parents[0] 500 parent = parents[0]
497 origbranch = wctx.branch() 501 origbranch = wctx.branch()
498 502
499 if parent.node() != nodemod.nullid: 503 if parent.node() != nodemod.nullid:
500 desc = "changes to: %s" % parent.description().split('\n', 1)[0] 504 desc = b"changes to: %s" % parent.description().split(b'\n', 1)[0]
501 else: 505 else:
502 desc = '(changes in empty repository)' 506 desc = b'(changes in empty repository)'
503 507
504 if not opts.get('message'): 508 if not opts.get(b'message'):
505 opts['message'] = desc 509 opts[b'message'] = desc
506 510
507 lock = tr = activebookmark = None 511 lock = tr = activebookmark = None
508 try: 512 try:
509 lock = repo.lock() 513 lock = repo.lock()
510 514
511 # use an uncommitted transaction to generate the bundle to avoid 515 # use an uncommitted transaction to generate the bundle to avoid
512 # pull races. ensure we don't print the abort message to stderr. 516 # pull races. ensure we don't print the abort message to stderr.
513 tr = repo.transaction('shelve', report=lambda x: None) 517 tr = repo.transaction(b'shelve', report=lambda x: None)
514 518
515 interactive = opts.get('interactive', False) 519 interactive = opts.get(b'interactive', False)
516 includeunknown = opts.get('unknown', False) and not opts.get( 520 includeunknown = opts.get(b'unknown', False) and not opts.get(
517 'addremove', False 521 b'addremove', False
518 ) 522 )
519 523
520 name = getshelvename(repo, parent, opts) 524 name = getshelvename(repo, parent, opts)
521 activebookmark = _backupactivebookmark(repo) 525 activebookmark = _backupactivebookmark(repo)
522 extra = {'internal': 'shelve'} 526 extra = {b'internal': b'shelve'}
523 if includeunknown: 527 if includeunknown:
524 _includeunknownfiles(repo, pats, opts, extra) 528 _includeunknownfiles(repo, pats, opts, extra)
525 529
526 if _iswctxonnewbranch(repo) and not _isbareshelve(pats, opts): 530 if _iswctxonnewbranch(repo) and not _isbareshelve(pats, opts):
527 # In non-bare shelve we don't store newly created branch 531 # In non-bare shelve we don't store newly created branch
528 # at bundled commit 532 # at bundled commit
529 repo.dirstate.setbranch(repo['.'].branch()) 533 repo.dirstate.setbranch(repo[b'.'].branch())
530 534
531 commitfunc = getcommitfunc(extra, interactive, editor=True) 535 commitfunc = getcommitfunc(extra, interactive, editor=True)
532 if not interactive: 536 if not interactive:
533 node = cmdutil.commit(ui, repo, commitfunc, pats, opts) 537 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
534 else: 538 else:
552 match = scmutil.matchfiles(repo, repo[node].files()) 556 match = scmutil.matchfiles(repo, repo[node].files())
553 _shelvecreatedcommit(repo, node, name, match) 557 _shelvecreatedcommit(repo, node, name, match)
554 558
555 if ui.formatted(): 559 if ui.formatted():
556 desc = stringutil.ellipsis(desc, ui.termwidth()) 560 desc = stringutil.ellipsis(desc, ui.termwidth())
557 ui.status(_('shelved as %s\n') % name) 561 ui.status(_(b'shelved as %s\n') % name)
558 if opts['keep']: 562 if opts[b'keep']:
559 with repo.dirstate.parentchange(): 563 with repo.dirstate.parentchange():
560 scmutil.movedirstate(repo, parent, match) 564 scmutil.movedirstate(repo, parent, match)
561 else: 565 else:
562 hg.update(repo, parent.node()) 566 hg.update(repo, parent.node())
563 if origbranch != repo['.'].branch() and not _isbareshelve(pats, opts): 567 if origbranch != repo[b'.'].branch() and not _isbareshelve(pats, opts):
564 repo.dirstate.setbranch(origbranch) 568 repo.dirstate.setbranch(origbranch)
565 569
566 _finishshelve(repo, tr) 570 _finishshelve(repo, tr)
567 finally: 571 finally:
568 _restoreactivebookmark(repo, activebookmark) 572 _restoreactivebookmark(repo, activebookmark)
570 574
571 575
572 def _isbareshelve(pats, opts): 576 def _isbareshelve(pats, opts):
573 return ( 577 return (
574 not pats 578 not pats
575 and not opts.get('interactive', False) 579 and not opts.get(b'interactive', False)
576 and not opts.get('include', False) 580 and not opts.get(b'include', False)
577 and not opts.get('exclude', False) 581 and not opts.get(b'exclude', False)
578 ) 582 )
579 583
580 584
581 def _iswctxonnewbranch(repo): 585 def _iswctxonnewbranch(repo):
582 return repo[None].branch() != repo['.'].branch() 586 return repo[None].branch() != repo[b'.'].branch()
583 587
584 588
585 def cleanupcmd(ui, repo): 589 def cleanupcmd(ui, repo):
586 """subcommand that deletes all shelves""" 590 """subcommand that deletes all shelves"""
587 591
588 with repo.wlock(): 592 with repo.wlock():
589 for (name, _type) in repo.vfs.readdir(shelvedir): 593 for (name, _type) in repo.vfs.readdir(shelvedir):
590 suffix = name.rsplit('.', 1)[-1] 594 suffix = name.rsplit(b'.', 1)[-1]
591 if suffix in shelvefileextensions: 595 if suffix in shelvefileextensions:
592 shelvedfile(repo, name).movetobackup() 596 shelvedfile(repo, name).movetobackup()
593 cleanupoldbackups(repo) 597 cleanupoldbackups(repo)
594 598
595 599
596 def deletecmd(ui, repo, pats): 600 def deletecmd(ui, repo, pats):
597 """subcommand that deletes a specific shelve""" 601 """subcommand that deletes a specific shelve"""
598 if not pats: 602 if not pats:
599 raise error.Abort(_('no shelved changes specified!')) 603 raise error.Abort(_(b'no shelved changes specified!'))
600 with repo.wlock(): 604 with repo.wlock():
601 try: 605 try:
602 for name in pats: 606 for name in pats:
603 for suffix in shelvefileextensions: 607 for suffix in shelvefileextensions:
604 shfile = shelvedfile(repo, name, suffix) 608 shfile = shelvedfile(repo, name, suffix)
611 shfile.movetobackup() 615 shfile.movetobackup()
612 cleanupoldbackups(repo) 616 cleanupoldbackups(repo)
613 except OSError as err: 617 except OSError as err:
614 if err.errno != errno.ENOENT: 618 if err.errno != errno.ENOENT:
615 raise 619 raise
616 raise error.Abort(_("shelved change '%s' not found") % name) 620 raise error.Abort(_(b"shelved change '%s' not found") % name)
617 621
618 622
619 def listshelves(repo): 623 def listshelves(repo):
620 """return all shelves in repo as list of (time, filename)""" 624 """return all shelves in repo as list of (time, filename)"""
621 try: 625 try:
624 if err.errno != errno.ENOENT: 628 if err.errno != errno.ENOENT:
625 raise 629 raise
626 return [] 630 return []
627 info = [] 631 info = []
628 for (name, _type) in names: 632 for (name, _type) in names:
629 pfx, sfx = name.rsplit('.', 1) 633 pfx, sfx = name.rsplit(b'.', 1)
630 if not pfx or sfx != patchextension: 634 if not pfx or sfx != patchextension:
631 continue 635 continue
632 st = shelvedfile(repo, name).stat() 636 st = shelvedfile(repo, name).stat()
633 info.append((st[stat.ST_MTIME], shelvedfile(repo, pfx).filename())) 637 info.append((st[stat.ST_MTIME], shelvedfile(repo, pfx).filename()))
634 return sorted(info, reverse=True) 638 return sorted(info, reverse=True)
638 """subcommand that displays the list of shelves""" 642 """subcommand that displays the list of shelves"""
639 pats = set(pats) 643 pats = set(pats)
640 width = 80 644 width = 80
641 if not ui.plain(): 645 if not ui.plain():
642 width = ui.termwidth() 646 width = ui.termwidth()
643 namelabel = 'shelve.newest' 647 namelabel = b'shelve.newest'
644 ui.pager('shelve') 648 ui.pager(b'shelve')
645 for mtime, name in listshelves(repo): 649 for mtime, name in listshelves(repo):
646 sname = util.split(name)[1] 650 sname = util.split(name)[1]
647 if pats and sname not in pats: 651 if pats and sname not in pats:
648 continue 652 continue
649 ui.write(sname, label=namelabel) 653 ui.write(sname, label=namelabel)
650 namelabel = 'shelve.name' 654 namelabel = b'shelve.name'
651 if ui.quiet: 655 if ui.quiet:
652 ui.write('\n') 656 ui.write(b'\n')
653 continue 657 continue
654 ui.write(' ' * (16 - len(sname))) 658 ui.write(b' ' * (16 - len(sname)))
655 used = 16 659 used = 16
656 date = dateutil.makedate(mtime) 660 date = dateutil.makedate(mtime)
657 age = '(%s)' % templatefilters.age(date, abbrev=True) 661 age = b'(%s)' % templatefilters.age(date, abbrev=True)
658 ui.write(age, label='shelve.age') 662 ui.write(age, label=b'shelve.age')
659 ui.write(' ' * (12 - len(age))) 663 ui.write(b' ' * (12 - len(age)))
660 used += 12 664 used += 12
661 with open(name + '.' + patchextension, 'rb') as fp: 665 with open(name + b'.' + patchextension, b'rb') as fp:
662 while True: 666 while True:
663 line = fp.readline() 667 line = fp.readline()
664 if not line: 668 if not line:
665 break 669 break
666 if not line.startswith('#'): 670 if not line.startswith(b'#'):
667 desc = line.rstrip() 671 desc = line.rstrip()
668 if ui.formatted(): 672 if ui.formatted():
669 desc = stringutil.ellipsis(desc, width - used) 673 desc = stringutil.ellipsis(desc, width - used)
670 ui.write(desc) 674 ui.write(desc)
671 break 675 break
672 ui.write('\n') 676 ui.write(b'\n')
673 if not (opts['patch'] or opts['stat']): 677 if not (opts[b'patch'] or opts[b'stat']):
674 continue 678 continue
675 difflines = fp.readlines() 679 difflines = fp.readlines()
676 if opts['patch']: 680 if opts[b'patch']:
677 for chunk, label in patch.difflabel(iter, difflines): 681 for chunk, label in patch.difflabel(iter, difflines):
678 ui.write(chunk, label=label) 682 ui.write(chunk, label=label)
679 if opts['stat']: 683 if opts[b'stat']:
680 for chunk, label in patch.diffstatui(difflines, width=width): 684 for chunk, label in patch.diffstatui(difflines, width=width):
681 ui.write(chunk, label=label) 685 ui.write(chunk, label=label)
682 686
683 687
684 def patchcmds(ui, repo, pats, opts): 688 def patchcmds(ui, repo, pats, opts):
685 """subcommand that displays shelves""" 689 """subcommand that displays shelves"""
686 if len(pats) == 0: 690 if len(pats) == 0:
687 shelves = listshelves(repo) 691 shelves = listshelves(repo)
688 if not shelves: 692 if not shelves:
689 raise error.Abort(_("there are no shelves to show")) 693 raise error.Abort(_(b"there are no shelves to show"))
690 mtime, name = shelves[0] 694 mtime, name = shelves[0]
691 sname = util.split(name)[1] 695 sname = util.split(name)[1]
692 pats = [sname] 696 pats = [sname]
693 697
694 for shelfname in pats: 698 for shelfname in pats:
695 if not shelvedfile(repo, shelfname, patchextension).exists(): 699 if not shelvedfile(repo, shelfname, patchextension).exists():
696 raise error.Abort(_("cannot find shelf %s") % shelfname) 700 raise error.Abort(_(b"cannot find shelf %s") % shelfname)
697 701
698 listcmd(ui, repo, pats, opts) 702 listcmd(ui, repo, pats, opts)
699 703
700 704
701 def checkparents(repo, state): 705 def checkparents(repo, state):
702 """check parent while resuming an unshelve""" 706 """check parent while resuming an unshelve"""
703 if state.parents != repo.dirstate.parents(): 707 if state.parents != repo.dirstate.parents():
704 raise error.Abort( 708 raise error.Abort(
705 _('working directory parents do not match unshelve ' 'state') 709 _(b'working directory parents do not match unshelve ' b'state')
706 ) 710 )
707 711
708 712
709 def _loadshelvedstate(ui, repo, opts): 713 def _loadshelvedstate(ui, repo, opts):
710 try: 714 try:
711 state = shelvedstate.load(repo) 715 state = shelvedstate.load(repo)
712 if opts.get('keep') is None: 716 if opts.get(b'keep') is None:
713 opts['keep'] = state.keep 717 opts[b'keep'] = state.keep
714 except IOError as err: 718 except IOError as err:
715 if err.errno != errno.ENOENT: 719 if err.errno != errno.ENOENT:
716 raise 720 raise
717 cmdutil.wrongtooltocontinue(repo, _('unshelve')) 721 cmdutil.wrongtooltocontinue(repo, _(b'unshelve'))
718 except error.CorruptedState as err: 722 except error.CorruptedState as err:
719 ui.debug(pycompat.bytestr(err) + '\n') 723 ui.debug(pycompat.bytestr(err) + b'\n')
720 if opts.get('continue'): 724 if opts.get(b'continue'):
721 msg = _('corrupted shelved state file') 725 msg = _(b'corrupted shelved state file')
722 hint = _( 726 hint = _(
723 'please run hg unshelve --abort to abort unshelve ' 'operation' 727 b'please run hg unshelve --abort to abort unshelve '
728 b'operation'
724 ) 729 )
725 raise error.Abort(msg, hint=hint) 730 raise error.Abort(msg, hint=hint)
726 elif opts.get('abort'): 731 elif opts.get(b'abort'):
727 shelvedstate.clear(repo) 732 shelvedstate.clear(repo)
728 raise error.Abort( 733 raise error.Abort(
729 _( 734 _(
730 'could not read shelved state file, your ' 735 b'could not read shelved state file, your '
731 'working copy may be in an unexpected state\n' 736 b'working copy may be in an unexpected state\n'
732 'please update to some commit\n' 737 b'please update to some commit\n'
733 ) 738 )
734 ) 739 )
735 return state 740 return state
736 741
737 742
745 if state.activebookmark and state.activebookmark in repo._bookmarks: 750 if state.activebookmark and state.activebookmark in repo._bookmarks:
746 bookmarks.activate(repo, state.activebookmark) 751 bookmarks.activate(repo, state.activebookmark)
747 mergefiles(ui, repo, state.wctx, state.pendingctx) 752 mergefiles(ui, repo, state.wctx, state.pendingctx)
748 if not phases.supportinternal(repo): 753 if not phases.supportinternal(repo):
749 repair.strip( 754 repair.strip(
750 ui, repo, state.nodestoremove, backup=False, topic='shelve' 755 ui, repo, state.nodestoremove, backup=False, topic=b'shelve'
751 ) 756 )
752 finally: 757 finally:
753 shelvedstate.clear(repo) 758 shelvedstate.clear(repo)
754 ui.warn(_("unshelve of '%s' aborted\n") % state.name) 759 ui.warn(_(b"unshelve of '%s' aborted\n") % state.name)
755 760
756 761
757 def hgabortunshelve(ui, repo): 762 def hgabortunshelve(ui, repo):
758 """logic to abort unshelve using 'hg abort""" 763 """logic to abort unshelve using 'hg abort"""
759 with repo.wlock(): 764 with repo.wlock():
760 state = _loadshelvedstate(ui, repo, {'abort': True}) 765 state = _loadshelvedstate(ui, repo, {b'abort': True})
761 return unshelveabort(ui, repo, state) 766 return unshelveabort(ui, repo, state)
762 767
763 768
764 def mergefiles(ui, repo, wctx, shelvectx): 769 def mergefiles(ui, repo, wctx, shelvectx):
765 """updates to wctx and merges the changes from shelvectx into the 770 """updates to wctx and merges the changes from shelvectx into the
766 dirstate.""" 771 dirstate."""
767 with ui.configoverride({('ui', 'quiet'): True}): 772 with ui.configoverride({(b'ui', b'quiet'): True}):
768 hg.update(repo, wctx.node()) 773 hg.update(repo, wctx.node())
769 ui.pushbuffer(True) 774 ui.pushbuffer(True)
770 cmdutil.revert(ui, repo, shelvectx, repo.dirstate.parents()) 775 cmdutil.revert(ui, repo, shelvectx, repo.dirstate.parents())
771 ui.popbuffer() 776 ui.popbuffer()
772 777
773 778
774 def restorebranch(ui, repo, branchtorestore): 779 def restorebranch(ui, repo, branchtorestore):
775 if branchtorestore and branchtorestore != repo.dirstate.branch(): 780 if branchtorestore and branchtorestore != repo.dirstate.branch():
776 repo.dirstate.setbranch(branchtorestore) 781 repo.dirstate.setbranch(branchtorestore)
777 ui.status( 782 ui.status(
778 _('marked working directory as branch %s\n') % branchtorestore 783 _(b'marked working directory as branch %s\n') % branchtorestore
779 ) 784 )
780 785
781 786
782 def unshelvecleanup(ui, repo, name, opts): 787 def unshelvecleanup(ui, repo, name, opts):
783 """remove related files after an unshelve""" 788 """remove related files after an unshelve"""
784 if not opts.get('keep'): 789 if not opts.get(b'keep'):
785 for filetype in shelvefileextensions: 790 for filetype in shelvefileextensions:
786 shfile = shelvedfile(repo, name, filetype) 791 shfile = shelvedfile(repo, name, filetype)
787 if shfile.exists(): 792 if shfile.exists():
788 shfile.movetobackup() 793 shfile.movetobackup()
789 cleanupoldbackups(repo) 794 cleanupoldbackups(repo)
798 with repo.lock(): 803 with repo.lock():
799 checkparents(repo, state) 804 checkparents(repo, state)
800 ms = merge.mergestate.read(repo) 805 ms = merge.mergestate.read(repo)
801 if list(ms.unresolved()): 806 if list(ms.unresolved()):
802 raise error.Abort( 807 raise error.Abort(
803 _("unresolved conflicts, can't continue"), 808 _(b"unresolved conflicts, can't continue"),
804 hint=_("see 'hg resolve', then 'hg unshelve --continue'"), 809 hint=_(b"see 'hg resolve', then 'hg unshelve --continue'"),
805 ) 810 )
806 811
807 shelvectx = repo[state.parents[1]] 812 shelvectx = repo[state.parents[1]]
808 pendingctx = state.pendingctx 813 pendingctx = state.pendingctx
809 814
812 repo.dirstate.write(repo.currenttransaction()) 817 repo.dirstate.write(repo.currenttransaction())
813 818
814 targetphase = phases.internal 819 targetphase = phases.internal
815 if not phases.supportinternal(repo): 820 if not phases.supportinternal(repo):
816 targetphase = phases.secret 821 targetphase = phases.secret
817 overrides = {('phases', 'new-commit'): targetphase} 822 overrides = {(b'phases', b'new-commit'): targetphase}
818 with repo.ui.configoverride(overrides, 'unshelve'): 823 with repo.ui.configoverride(overrides, b'unshelve'):
819 with repo.dirstate.parentchange(): 824 with repo.dirstate.parentchange():
820 repo.setparents(state.parents[0], nodemod.nullid) 825 repo.setparents(state.parents[0], nodemod.nullid)
821 newnode, ispartialunshelve = _createunshelvectx( 826 newnode, ispartialunshelve = _createunshelvectx(
822 ui, repo, shelvectx, basename, interactive, opts 827 ui, repo, shelvectx, basename, interactive, opts
823 ) 828 )
827 # merge state clean-up path doesn't happen, so do it 832 # merge state clean-up path doesn't happen, so do it
828 # here. Fix issue5494 833 # here. Fix issue5494
829 merge.mergestate.clean(repo) 834 merge.mergestate.clean(repo)
830 shelvectx = state.pendingctx 835 shelvectx = state.pendingctx
831 msg = _( 836 msg = _(
832 'note: unshelved changes already existed ' 837 b'note: unshelved changes already existed '
833 'in the working copy\n' 838 b'in the working copy\n'
834 ) 839 )
835 ui.status(msg) 840 ui.status(msg)
836 else: 841 else:
837 # only strip the shelvectx if we produced one 842 # only strip the shelvectx if we produced one
838 state.nodestoremove.append(newnode) 843 state.nodestoremove.append(newnode)
842 mergefiles(ui, repo, state.wctx, shelvectx) 847 mergefiles(ui, repo, state.wctx, shelvectx)
843 restorebranch(ui, repo, state.branchtorestore) 848 restorebranch(ui, repo, state.branchtorestore)
844 849
845 if not phases.supportinternal(repo): 850 if not phases.supportinternal(repo):
846 repair.strip( 851 repair.strip(
847 ui, repo, state.nodestoremove, backup=False, topic='shelve' 852 ui, repo, state.nodestoremove, backup=False, topic=b'shelve'
848 ) 853 )
849 shelvedstate.clear(repo) 854 shelvedstate.clear(repo)
850 if not ispartialunshelve: 855 if not ispartialunshelve:
851 unshelvecleanup(ui, repo, state.name, opts) 856 unshelvecleanup(ui, repo, state.name, opts)
852 _restoreactivebookmark(repo, state.activebookmark) 857 _restoreactivebookmark(repo, state.activebookmark)
853 ui.status(_("unshelve of '%s' complete\n") % state.name) 858 ui.status(_(b"unshelve of '%s' complete\n") % state.name)
854 859
855 860
856 def hgcontinueunshelve(ui, repo): 861 def hgcontinueunshelve(ui, repo):
857 """logic to resume unshelve using 'hg continue'""" 862 """logic to resume unshelve using 'hg continue'"""
858 with repo.wlock(): 863 with repo.wlock():
859 state = _loadshelvedstate(ui, repo, {'continue': True}) 864 state = _loadshelvedstate(ui, repo, {b'continue': True})
860 return unshelvecontinue(ui, repo, state, {'keep': state.keep}) 865 return unshelvecontinue(ui, repo, state, {b'keep': state.keep})
861 866
862 867
863 def _commitworkingcopychanges(ui, repo, opts, tmpwctx): 868 def _commitworkingcopychanges(ui, repo, opts, tmpwctx):
864 """Temporarily commit working copy changes before moving unshelve commit""" 869 """Temporarily commit working copy changes before moving unshelve commit"""
865 # Store pending changes in a commit and remember added in case a shelve 870 # Store pending changes in a commit and remember added in case a shelve
868 addedbefore = frozenset(s.added) 873 addedbefore = frozenset(s.added)
869 if not (s.modified or s.added or s.removed): 874 if not (s.modified or s.added or s.removed):
870 return tmpwctx, addedbefore 875 return tmpwctx, addedbefore
871 ui.status( 876 ui.status(
872 _( 877 _(
873 "temporarily committing pending changes " 878 b"temporarily committing pending changes "
874 "(restore with 'hg unshelve --abort')\n" 879 b"(restore with 'hg unshelve --abort')\n"
875 ) 880 )
876 ) 881 )
877 extra = {'internal': 'shelve'} 882 extra = {b'internal': b'shelve'}
878 commitfunc = getcommitfunc(extra=extra, interactive=False, editor=False) 883 commitfunc = getcommitfunc(extra=extra, interactive=False, editor=False)
879 tempopts = {} 884 tempopts = {}
880 tempopts['message'] = "pending changes temporary commit" 885 tempopts[b'message'] = b"pending changes temporary commit"
881 tempopts['date'] = opts.get('date') 886 tempopts[b'date'] = opts.get(b'date')
882 with ui.configoverride({('ui', 'quiet'): True}): 887 with ui.configoverride({(b'ui', b'quiet'): True}):
883 node = cmdutil.commit(ui, repo, commitfunc, [], tempopts) 888 node = cmdutil.commit(ui, repo, commitfunc, [], tempopts)
884 tmpwctx = repo[node] 889 tmpwctx = repo[node]
885 return tmpwctx, addedbefore 890 return tmpwctx, addedbefore
886 891
887 892
888 def _unshelverestorecommit(ui, repo, tr, basename): 893 def _unshelverestorecommit(ui, repo, tr, basename):
889 """Recreate commit in the repository during the unshelve""" 894 """Recreate commit in the repository during the unshelve"""
890 repo = repo.unfiltered() 895 repo = repo.unfiltered()
891 node = None 896 node = None
892 if shelvedfile(repo, basename, 'shelve').exists(): 897 if shelvedfile(repo, basename, b'shelve').exists():
893 node = shelvedfile(repo, basename, 'shelve').readinfo()['node'] 898 node = shelvedfile(repo, basename, b'shelve').readinfo()[b'node']
894 if node is None or node not in repo: 899 if node is None or node not in repo:
895 with ui.configoverride({('ui', 'quiet'): True}): 900 with ui.configoverride({(b'ui', b'quiet'): True}):
896 shelvectx = shelvedfile(repo, basename, 'hg').applybundle(tr) 901 shelvectx = shelvedfile(repo, basename, b'hg').applybundle(tr)
897 # We might not strip the unbundled changeset, so we should keep track of 902 # We might not strip the unbundled changeset, so we should keep track of
898 # the unshelve node in case we need to reuse it (eg: unshelve --keep) 903 # the unshelve node in case we need to reuse it (eg: unshelve --keep)
899 if node is None: 904 if node is None:
900 info = {'node': nodemod.hex(shelvectx.node())} 905 info = {b'node': nodemod.hex(shelvectx.node())}
901 shelvedfile(repo, basename, 'shelve').writeinfo(info) 906 shelvedfile(repo, basename, b'shelve').writeinfo(info)
902 else: 907 else:
903 shelvectx = repo[node] 908 shelvectx = repo[node]
904 909
905 return repo, shelvectx 910 return repo, shelvectx
906 911
924 changes to unshelve at that time and the latter is shelved for future. 929 changes to unshelve at that time and the latter is shelved for future.
925 930
926 Here, we return both the newnode which is created interactively and a 931 Here, we return both the newnode which is created interactively and a
927 bool to know whether the shelve is partly done or completely done. 932 bool to know whether the shelve is partly done or completely done.
928 """ 933 """
929 opts['message'] = shelvectx.description() 934 opts[b'message'] = shelvectx.description()
930 opts['interactive-unshelve'] = True 935 opts[b'interactive-unshelve'] = True
931 pats = [] 936 pats = []
932 if not interactive: 937 if not interactive:
933 newnode = repo.commit( 938 newnode = repo.commit(
934 text=shelvectx.description(), 939 text=shelvectx.description(),
935 extra=shelvectx.extra(), 940 extra=shelvectx.extra(),
975 activebookmark, 980 activebookmark,
976 ): 981 ):
977 """Rebase restored commit from its original location to a destination""" 982 """Rebase restored commit from its original location to a destination"""
978 # If the shelve is not immediately on top of the commit 983 # If the shelve is not immediately on top of the commit
979 # we'll be merging with, rebase it to be on top. 984 # we'll be merging with, rebase it to be on top.
980 interactive = opts.get('interactive') 985 interactive = opts.get(b'interactive')
981 if tmpwctx.node() == shelvectx.p1().node() and not interactive: 986 if tmpwctx.node() == shelvectx.p1().node() and not interactive:
982 # We won't skip on interactive mode because, the user might want to 987 # We won't skip on interactive mode because, the user might want to
983 # unshelve certain changes only. 988 # unshelve certain changes only.
984 return shelvectx, False 989 return shelvectx, False
985 990
986 overrides = { 991 overrides = {
987 ('ui', 'forcemerge'): opts.get('tool', ''), 992 (b'ui', b'forcemerge'): opts.get(b'tool', b''),
988 ('phases', 'new-commit'): phases.secret, 993 (b'phases', b'new-commit'): phases.secret,
989 } 994 }
990 with repo.ui.configoverride(overrides, 'unshelve'): 995 with repo.ui.configoverride(overrides, b'unshelve'):
991 ui.status(_('rebasing shelved changes\n')) 996 ui.status(_(b'rebasing shelved changes\n'))
992 stats = merge.graft( 997 stats = merge.graft(
993 repo, 998 repo,
994 shelvectx, 999 shelvectx,
995 shelvectx.p1(), 1000 shelvectx.p1(),
996 labels=['shelve', 'working-copy'], 1001 labels=[b'shelve', b'working-copy'],
997 keepconflictparent=True, 1002 keepconflictparent=True,
998 ) 1003 )
999 if stats.unresolvedcount: 1004 if stats.unresolvedcount:
1000 tr.close() 1005 tr.close()
1001 1006
1008 basename, 1013 basename,
1009 pctx, 1014 pctx,
1010 tmpwctx, 1015 tmpwctx,
1011 nodestoremove, 1016 nodestoremove,
1012 branchtorestore, 1017 branchtorestore,
1013 opts.get('keep'), 1018 opts.get(b'keep'),
1014 activebookmark, 1019 activebookmark,
1015 interactive, 1020 interactive,
1016 ) 1021 )
1017 raise error.InterventionRequired( 1022 raise error.InterventionRequired(
1018 _( 1023 _(
1019 "unresolved conflicts (see 'hg resolve', then " 1024 b"unresolved conflicts (see 'hg resolve', then "
1020 "'hg unshelve --continue')" 1025 b"'hg unshelve --continue')"
1021 ) 1026 )
1022 ) 1027 )
1023 1028
1024 with repo.dirstate.parentchange(): 1029 with repo.dirstate.parentchange():
1025 repo.setparents(tmpwctx.node(), nodemod.nullid) 1030 repo.setparents(tmpwctx.node(), nodemod.nullid)
1032 # merge state clean-up path doesn't happen, so do it 1037 # merge state clean-up path doesn't happen, so do it
1033 # here. Fix issue5494 1038 # here. Fix issue5494
1034 merge.mergestate.clean(repo) 1039 merge.mergestate.clean(repo)
1035 shelvectx = tmpwctx 1040 shelvectx = tmpwctx
1036 msg = _( 1041 msg = _(
1037 'note: unshelved changes already existed ' 1042 b'note: unshelved changes already existed '
1038 'in the working copy\n' 1043 b'in the working copy\n'
1039 ) 1044 )
1040 ui.status(msg) 1045 ui.status(msg)
1041 else: 1046 else:
1042 shelvectx = repo[newnode] 1047 shelvectx = repo[newnode]
1043 hg.updaterepo(repo, tmpwctx.node(), False) 1048 hg.updaterepo(repo, tmpwctx.node(), False)
1046 1051
1047 1052
1048 def _forgetunknownfiles(repo, shelvectx, addedbefore): 1053 def _forgetunknownfiles(repo, shelvectx, addedbefore):
1049 # Forget any files that were unknown before the shelve, unknown before 1054 # Forget any files that were unknown before the shelve, unknown before
1050 # unshelve started, but are now added. 1055 # unshelve started, but are now added.
1051 shelveunknown = shelvectx.extra().get('shelve_unknown') 1056 shelveunknown = shelvectx.extra().get(b'shelve_unknown')
1052 if not shelveunknown: 1057 if not shelveunknown:
1053 return 1058 return
1054 shelveunknown = frozenset(shelveunknown.split('\0')) 1059 shelveunknown = frozenset(shelveunknown.split(b'\0'))
1055 addedafter = frozenset(repo.status().added) 1060 addedafter = frozenset(repo.status().added)
1056 toforget = (addedafter & shelveunknown) - addedbefore 1061 toforget = (addedafter & shelveunknown) - addedbefore
1057 repo[None].forget(toforget) 1062 repo[None].forget(toforget)
1058 1063
1059 1064
1072 copy having untracked changes.""" 1077 copy having untracked changes."""
1073 wcdeleted = set(repo.status().deleted) 1078 wcdeleted = set(repo.status().deleted)
1074 shelvetouched = set(shelvectx.files()) 1079 shelvetouched = set(shelvectx.files())
1075 intersection = wcdeleted.intersection(shelvetouched) 1080 intersection = wcdeleted.intersection(shelvetouched)
1076 if intersection: 1081 if intersection:
1077 m = _("shelved change touches missing files") 1082 m = _(b"shelved change touches missing files")
1078 hint = _("run hg status to see which files are missing") 1083 hint = _(b"run hg status to see which files are missing")
1079 raise error.Abort(m, hint=hint) 1084 raise error.Abort(m, hint=hint)
1080 1085
1081 1086
1082 def dounshelve(ui, repo, *shelved, **opts): 1087 def dounshelve(ui, repo, *shelved, **opts):
1083 opts = pycompat.byteskwargs(opts) 1088 opts = pycompat.byteskwargs(opts)
1084 abortf = opts.get('abort') 1089 abortf = opts.get(b'abort')
1085 continuef = opts.get('continue') 1090 continuef = opts.get(b'continue')
1086 interactive = opts.get('interactive') 1091 interactive = opts.get(b'interactive')
1087 if not abortf and not continuef: 1092 if not abortf and not continuef:
1088 cmdutil.checkunfinished(repo) 1093 cmdutil.checkunfinished(repo)
1089 shelved = list(shelved) 1094 shelved = list(shelved)
1090 if opts.get("name"): 1095 if opts.get(b"name"):
1091 shelved.append(opts["name"]) 1096 shelved.append(opts[b"name"])
1092 1097
1093 if interactive and opts.get('keep'): 1098 if interactive and opts.get(b'keep'):
1094 raise error.Abort(_('--keep on --interactive is not yet supported')) 1099 raise error.Abort(_(b'--keep on --interactive is not yet supported'))
1095 if abortf or continuef: 1100 if abortf or continuef:
1096 if abortf and continuef: 1101 if abortf and continuef:
1097 raise error.Abort(_('cannot use both abort and continue')) 1102 raise error.Abort(_(b'cannot use both abort and continue'))
1098 if shelved: 1103 if shelved:
1099 raise error.Abort( 1104 raise error.Abort(
1100 _( 1105 _(
1101 'cannot combine abort/continue with ' 1106 b'cannot combine abort/continue with '
1102 'naming a shelved change' 1107 b'naming a shelved change'
1103 ) 1108 )
1104 ) 1109 )
1105 if abortf and opts.get('tool', False): 1110 if abortf and opts.get(b'tool', False):
1106 ui.warn(_('tool option will be ignored\n')) 1111 ui.warn(_(b'tool option will be ignored\n'))
1107 1112
1108 state = _loadshelvedstate(ui, repo, opts) 1113 state = _loadshelvedstate(ui, repo, opts)
1109 if abortf: 1114 if abortf:
1110 return unshelveabort(ui, repo, state) 1115 return unshelveabort(ui, repo, state)
1111 elif continuef and interactive: 1116 elif continuef and interactive:
1112 raise error.Abort(_('cannot use both continue and interactive')) 1117 raise error.Abort(_(b'cannot use both continue and interactive'))
1113 elif continuef: 1118 elif continuef:
1114 return unshelvecontinue(ui, repo, state, opts) 1119 return unshelvecontinue(ui, repo, state, opts)
1115 elif len(shelved) > 1: 1120 elif len(shelved) > 1:
1116 raise error.Abort(_('can only unshelve one change at a time')) 1121 raise error.Abort(_(b'can only unshelve one change at a time'))
1117 elif not shelved: 1122 elif not shelved:
1118 shelved = listshelves(repo) 1123 shelved = listshelves(repo)
1119 if not shelved: 1124 if not shelved:
1120 raise error.Abort(_('no shelved changes to apply!')) 1125 raise error.Abort(_(b'no shelved changes to apply!'))
1121 basename = util.split(shelved[0][1])[1] 1126 basename = util.split(shelved[0][1])[1]
1122 ui.status(_("unshelving change '%s'\n") % basename) 1127 ui.status(_(b"unshelving change '%s'\n") % basename)
1123 else: 1128 else:
1124 basename = shelved[0] 1129 basename = shelved[0]
1125 1130
1126 if not shelvedfile(repo, basename, patchextension).exists(): 1131 if not shelvedfile(repo, basename, patchextension).exists():
1127 raise error.Abort(_("shelved change '%s' not found") % basename) 1132 raise error.Abort(_(b"shelved change '%s' not found") % basename)
1128 1133
1129 repo = repo.unfiltered() 1134 repo = repo.unfiltered()
1130 lock = tr = None 1135 lock = tr = None
1131 try: 1136 try:
1132 lock = repo.lock() 1137 lock = repo.lock()
1133 tr = repo.transaction('unshelve', report=lambda x: None) 1138 tr = repo.transaction(b'unshelve', report=lambda x: None)
1134 oldtiprev = len(repo) 1139 oldtiprev = len(repo)
1135 1140
1136 pctx = repo['.'] 1141 pctx = repo[b'.']
1137 tmpwctx = pctx 1142 tmpwctx = pctx
1138 # The goal is to have a commit structure like so: 1143 # The goal is to have a commit structure like so:
1139 # ...-> pctx -> tmpwctx -> shelvectx 1144 # ...-> pctx -> tmpwctx -> shelvectx
1140 # where tmpwctx is an optional commit with the user's pending changes 1145 # where tmpwctx is an optional commit with the user's pending changes
1141 # and shelvectx is the unshelved changes. Then we merge it all down 1146 # and shelvectx is the unshelved changes. Then we merge it all down
1145 tmpwctx, addedbefore = _commitworkingcopychanges( 1150 tmpwctx, addedbefore = _commitworkingcopychanges(
1146 ui, repo, opts, tmpwctx 1151 ui, repo, opts, tmpwctx
1147 ) 1152 )
1148 repo, shelvectx = _unshelverestorecommit(ui, repo, tr, basename) 1153 repo, shelvectx = _unshelverestorecommit(ui, repo, tr, basename)
1149 _checkunshelveuntrackedproblems(ui, repo, shelvectx) 1154 _checkunshelveuntrackedproblems(ui, repo, shelvectx)
1150 branchtorestore = '' 1155 branchtorestore = b''
1151 if shelvectx.branch() != shelvectx.p1().branch(): 1156 if shelvectx.branch() != shelvectx.p1().branch():
1152 branchtorestore = shelvectx.branch() 1157 branchtorestore = shelvectx.branch()
1153 1158
1154 shelvectx, ispartialunshelve = _rebaserestoredcommit( 1159 shelvectx, ispartialunshelve = _rebaserestoredcommit(
1155 ui, 1160 ui,
1162 tmpwctx, 1167 tmpwctx,
1163 shelvectx, 1168 shelvectx,
1164 branchtorestore, 1169 branchtorestore,
1165 activebookmark, 1170 activebookmark,
1166 ) 1171 )
1167 overrides = {('ui', 'forcemerge'): opts.get('tool', '')} 1172 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
1168 with ui.configoverride(overrides, 'unshelve'): 1173 with ui.configoverride(overrides, b'unshelve'):
1169 mergefiles(ui, repo, pctx, shelvectx) 1174 mergefiles(ui, repo, pctx, shelvectx)
1170 restorebranch(ui, repo, branchtorestore) 1175 restorebranch(ui, repo, branchtorestore)
1171 shelvedstate.clear(repo) 1176 shelvedstate.clear(repo)
1172 _finishunshelve(repo, oldtiprev, tr, activebookmark) 1177 _finishunshelve(repo, oldtiprev, tr, activebookmark)
1173 _forgetunknownfiles(repo, shelvectx, addedbefore) 1178 _forgetunknownfiles(repo, shelvectx, addedbefore)