Mercurial > hg
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) |