3
# Copyright (C) 2005 Michael Ellerman <michael@ellerman.id.au>
5
# This program is free software; you can redistribute it and/or modify
6
# it under the terms of the GNU General Public License as published by
7
# the Free Software Foundation; either version 2 of the License, or
8
# (at your option) any later version.
10
# This program is distributed in the hope that it will be useful,
11
# but WITHOUT ANY WARRANTY; without even the implied warranty of
12
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
# GNU General Public License for more details.
15
# You should have received a copy of the GNU General Public License
16
# along with this program; if not, write to the Free Software
17
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
3
from patches import parse_patches
23
8
from bzrlib.commands import Command
26
if len(args) == 2 and args[1] == '--bzr-usage':
29
elif len(args) == 2 and args[1] == '--bzr-help':
30
print 'Shelve a patch, you can get it back later with unshelve.'
9
from bzrlib.branch import Branch
10
from bzrlib import DEFAULT_IGNORE
12
DEFAULT_IGNORE.append('./.bzr-shelf*')
15
name = os.path.basename(args.pop(0))
17
if name not in ['shelve', 'unshelve']:
18
raise Exception("Unknown command name '%s'" % name)
21
if args[0] == '--bzr-usage':
24
elif args[0] == '--bzr-help':
25
print 'Shelve a patch, you can get it back later with unshelve.'
28
raise Exception("Don't understand args %s" % args)
36
return run_bzr('root')[0].strip()
38
def shelf_suffix(index):
35
raise Exception("Don't understand args %s" % args)
51
stem = os.path.join(tree_root(), '.bzr-shelf')
52
for end in name_sequence():
54
if not os.path.exists(name):
58
stem = os.path.join(tree_root(), '.bzr-shelf')
59
shelves = glob.glob(stem)
60
shelves.extend(glob.glob(stem + '-*'))
61
def shelf_index(name):
64
return int(name[len(stem)+1:])
65
shelvenums = [shelf_index(f) for f in shelves]
68
if len(shelvenums) == 0:
70
return stem + shelf_suffix(shelvenums[-1])
72
def get_shelf_message(shelf):
74
if not shelf.startswith(prefix):
76
return shelf[len(prefix):shelf.index('\n')]
40
root = run_bzr('root')[0].strip()
41
shelf = os.path.join(root, '.bzr-shelf')
43
if not os.path.exists(shelf):
44
raise Exception("No shelf found in '%s'" % shelf)
82
raise Exception("No shelf found in '%s'" % tree_root())
46
84
patch = open(shelf, 'r').read()
48
print >>sys.stderr, "Reapplying shelved patches"
49
pipe = os.popen('patch -d %s -s -p0' % root, 'w')
86
print >>sys.stderr, "Reapplying shelved patches",
87
message = get_shelf_message(patch)
88
if message is not None:
89
print >>sys.stderr, ' "%s"' % message
91
print >>sys.stderr, ""
92
pipe = os.popen('patch -d %s -s -p0' % tree_root(), 'w')
63
diff_lines = run_bzr('diff')
64
patch_list = patches.parse_patches(diff_lines.__iter__())
65
to_shelve = prompt_user(patch_list)
67
if len(to_shelve) == 0:
105
class QuitException(Exception):
108
def shelve(message = None, revision = None, file_list = None):
110
if revision is not None:
111
cmd.extend(['--revision', str(revision[0])])
112
if file_list is not None:
113
cmd.extend(file_list)
114
patches = parse_patches(run_bzr(cmd))
116
patches = HunkSelector(patches).select()
117
except QuitException:
120
if len(patches) == 0:
68
121
print >>sys.stderr, 'Nothing to shelve'
71
root = run_bzr('root')[0].strip()
72
shelf = os.path.join(root, '.bzr-shelf')
73
125
print >>sys.stderr, "Saving shelved patches to", shelf
74
126
shelf = open(shelf, 'a')
76
for patch in to_shelve:
127
if message is not None:
128
assert '\n' not in message
129
shelf.write("# shelf: %s\n" % message)
130
for patch in patches:
77
131
shelf.write(str(patch))
103
157
raise Exception("Failed running bzr")
106
def prompt_user(patch_list):
108
for patch in patch_list:
109
total += len(patch.hunks)
116
for patch in patch_list:
117
if patch.oldname != patch.newname:
118
name = "%s -> %s" % (patch.oldname, patch.newname)
122
hunks = patch.hunks[:]
127
out.write('Shelve this change? (%d of %d) [yn] ' % (i, total))
128
line = inp.readline().strip().lower()
129
if line == 'y' or line == 'yes':
131
elif line == 'n' or line == 'no':
132
patch.hunks.remove(hunk)
137
if len(patch.hunks) > 0:
138
to_shelve.append(patch)
142
160
class cmd_shelve(Command):
143
161
"""Temporarily remove some changes from the current tree.
144
162
Use 'unshelve' to restore these changes.
164
If filenames are specified, only changes to those files will be unshelved.
165
If a revision is specified, all changes since that revision will may be
168
takes_args = ['file*']
169
takes_options = ['message', 'revision']
170
def run(self, file_list=None, message=None, revision=None):
172
if revision is not None and revision:
173
if file_list is not None and len(file_list) > 0:
174
branchdir = file_list[0]
177
b = Branch.open_containing(branchdir)
178
revision_list = ["revid:" + revision[0].in_history(b).rev_id]
180
return shelve(message=message, file_list=file_list,
181
revision=revision_list)
150
183
class cmd_unshelve(Command):
151
184
"""Restore previously-shelved changes to the current tree.
155
188
return unshelve()
192
def __init__(self, char, action, help, default=False):
195
self.default = default
199
Option('n', 'shelve', 'shelve this change for the moment.',
201
Option('y', 'keep', 'keep this change in your tree.'),
202
Option('d', 'done', 'done, skip to the end.'),
203
Option('i', 'invert', 'invert the current selection of all hunks.'),
204
Option('s', 'status', 'show status of hunks.'),
205
Option('q', 'quit', 'quit')
209
Option('y', 'continue', 'proceed to shelve selected changes.',
211
Option('r', 'restart', 'restart the hunk selection loop.'),
212
Option('s', 'status', 'show status of hunks.'),
213
Option('i', 'invert', 'invert the current selection of all hunks.'),
214
Option('q', 'quit', 'quit')
217
def __init__(self, patches):
218
self.patches = patches
220
for patch in patches:
221
for hunk in patch.hunks:
222
# everything's shelved by default
224
self.total_hunks += 1
226
def __get_option(self, char):
227
for opt in self.standard_options:
230
raise Exception('Option "%s" not found!' % char)
232
def __select_loop(self):
234
for patch in self.patches:
237
while i < len(patch.hunks):
238
hunk = patch.hunks[i]
240
print patch.get_header(), hunk
244
prompt = 'Keep this change? (%d of %d)' \
245
% (j, self.total_hunks)
248
self.__get_option('n').default = True
249
self.__get_option('y').default = False
251
self.__get_option('n').default = False
252
self.__get_option('y').default = True
254
action = self.__ask_user(prompt, self.standard_options)
257
hunk.selected = False
258
elif action == 'shelve':
260
elif action == 'done':
262
elif action == 'invert':
263
self.__invert_selection()
266
elif action == 'status':
269
elif action == 'quit':
276
if self.total_hunks == 0:
281
if not self.__select_loop():
286
prompt = "Shelve these changes, or restart?"
287
action = self.__ask_user(prompt, self.end_options)
289
if action == 'continue':
292
elif action == 'quit':
294
elif action == 'status':
296
elif action == 'invert':
297
self.__invert_selection()
298
elif action == 'restart':
302
for patch in self.patches:
304
for hunk in patch.hunks:
310
for patch in self.patches:
317
def __invert_selection(self):
318
for patch in self.patches:
319
for hunk in patch.hunks:
320
if hunk.__dict__.has_key('selected'):
321
hunk.selected = not hunk.selected
325
def __show_status(self):
327
for patch in self.patches:
328
print ' %s' % patch.oldname
331
for hunk in patch.hunks:
337
print ' %d hunks to be shelved' % shelve
338
print ' %d hunks to be kept' % keep
341
if sys.platform != "win32":
345
fd = sys.stdin.fileno()
346
settings = termios.tcgetattr(fd)
349
ch = sys.stdin.read(1)
351
termios.tcsetattr(fd, termios.TCSADRAIN, settings)
356
return msvcrt.getche()
358
def __ask_user(self, prompt, options):
360
sys.stdout.write(prompt)
361
sys.stdout.write(' [')
365
sys.stdout.write(opt.char)
366
sys.stdout.write('?] (%s): ' % default.char)
368
response = self.__getchar()
370
# default, which we see as newline, is 'n'
371
if response in ['\n', '\r', '\r\n']:
372
response = default.char
374
print response # because echo is off
377
if opt.char == response:
381
print ' %s - %s' % (opt.char, opt.help)