3
from patches import parse_patches
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
9
23
from bzrlib.commands import Command
12
name = os.path.basename(args.pop(0))
14
if name not in ['shelve', 'unshelve']:
15
raise Exception("Unknown command name '%s'" % name)
18
if args[0] == '--bzr-usage':
21
elif args[0] == '--bzr-help':
22
print 'Shelve a patch, you can get it back later with unshelve.'
25
raise Exception("Don't understand args %s" % args)
33
return run_bzr('root')[0].strip()
35
def shelf_suffix(index):
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.'
48
stem = os.path.join(tree_root(), '.bzr-shelf')
49
for end in name_sequence():
51
if not os.path.exists(name):
55
stem = os.path.join(tree_root(), '.bzr-shelf')
56
shelves = glob.glob(stem)
57
shelves.extend(glob.glob(stem + '-*'))
58
def shelf_index(name):
61
return int(name[len(stem)+1:])
62
shelvenums = [shelf_index(f) for f in shelves]
65
if len(shelvenums) == 0:
67
return stem + shelf_suffix(shelvenums[-1])
69
def get_shelf_message(shelf):
71
if not shelf.startswith(prefix):
73
return shelf[len(prefix):shelf.index('\n')]
35
raise Exception("Don't understand args %s" % args)
40
root = run_bzr('root')[0].strip()
41
shelf = os.path.join(root, '.bzr-shelf')
79
raise Exception("No shelf found in '%s'" % tree_root())
43
if not os.path.exists(shelf):
44
raise Exception("No shelf found in '%s'" % shelf)
81
46
patch = open(shelf, 'r').read()
83
print >>sys.stderr, "Reapplying shelved patches",
84
message = get_shelf_message(patch)
85
if message is not None:
86
print >>sys.stderr, ' "%s"' % message
88
print >>sys.stderr, ""
89
pipe = os.popen('patch -d %s -s -p0' % tree_root(), 'w')
48
print >>sys.stderr, "Reapplying shelved patches"
49
pipe = os.popen('patch -d %s -s -p0' % root, 'w')
102
class QuitException(Exception):
105
def shelve(message = None, revision = None, file_list = None):
107
if revision is not None:
108
cmd.extend(['--revision', str(revision[0])])
109
if file_list is not None:
110
cmd.extend(file_list)
111
patches = parse_patches(run_bzr(cmd))
113
patches = HunkSelector(patches).select()
114
except QuitException:
117
if len(patches) == 0:
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:
118
68
print >>sys.stderr, 'Nothing to shelve'
71
root = run_bzr('root')[0].strip()
72
shelf = os.path.join(root, '.bzr-shelf')
122
73
print >>sys.stderr, "Saving shelved patches to", shelf
123
74
shelf = open(shelf, 'a')
124
if message is not None:
125
assert '\n' not in message
126
shelf.write("# shelf: %s\n" % message)
127
for patch in patches:
76
for patch in to_shelve:
128
77
shelf.write(str(patch))
154
103
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)
157
142
class cmd_shelve(Command):
158
143
"""Temporarily remove some changes from the current tree.
159
144
Use 'unshelve' to restore these changes.
161
If filenames are specified, only changes to those files will be unshelved.
162
If a revision is specified, all changes since that revision will may be
165
takes_args = ['file*']
166
takes_options = ['message', 'revision']
167
def run(self, file_list=None, message=None, revision=None):
168
return shelve(message=message, file_list=file_list, revision=revision)
170
150
class cmd_unshelve(Command):
171
151
"""Restore previously-shelved changes to the current tree.
175
155
return unshelve()
179
def __init__(self, char, action, help, default=False):
182
self.default = default
186
Option('n', 'shelve', 'shelve this change for the moment.',
188
Option('y', 'keep', 'keep this change in your tree.'),
189
Option('d', 'done', 'done, skip to the end.'),
190
Option('i', 'invert', 'invert the current selection of all hunks.'),
191
Option('s', 'status', 'show status of hunks.'),
192
Option('q', 'quit', 'quit')
196
Option('y', 'continue', 'proceed to shelve selected changes.',
198
Option('r', 'restart', 'restart the hunk selection loop.'),
199
Option('s', 'status', 'show status of hunks.'),
200
Option('i', 'invert', 'invert the current selection of all hunks.'),
201
Option('q', 'quit', 'quit')
204
def __init__(self, patches):
205
self.patches = patches
207
for patch in patches:
208
for hunk in patch.hunks:
209
# everything's shelved by default
211
self.total_hunks += 1
213
def __get_option(self, char):
214
for opt in self.standard_options:
217
raise Exception('Option "%s" not found!' % char)
219
def __select_loop(self):
221
for patch in self.patches:
224
while i < len(patch.hunks):
225
hunk = patch.hunks[i]
227
print patch.get_header(), hunk
231
prompt = 'Keep this change? (%d of %d)' \
232
% (j, self.total_hunks)
235
self.__get_option('n').default = True
236
self.__get_option('y').default = False
238
self.__get_option('n').default = False
239
self.__get_option('y').default = True
241
action = self.__ask_user(prompt, self.standard_options)
244
hunk.selected = False
245
elif action == 'shelve':
247
elif action == 'done':
249
elif action == 'invert':
250
self.__invert_selection()
253
elif action == 'status':
256
elif action == 'quit':
263
if self.total_hunks == 0:
268
if not self.__select_loop():
273
prompt = "Shelve these changes, or restart?"
274
action = self.__ask_user(prompt, self.end_options)
276
if action == 'continue':
279
elif action == 'quit':
281
elif action == 'status':
283
elif action == 'invert':
284
self.__invert_selection()
285
elif action == 'restart':
289
for patch in self.patches:
291
for hunk in patch.hunks:
297
for patch in self.patches:
304
def __invert_selection(self):
305
for patch in self.patches:
306
for hunk in patch.hunks:
307
if hunk.__dict__.has_key('selected'):
308
hunk.selected = not hunk.selected
312
def __show_status(self):
314
for patch in self.patches:
315
print ' %s' % patch.oldname
318
for hunk in patch.hunks:
324
print ' %d hunks to be shelved' % shelve
325
print ' %d hunks to be kept' % keep
329
fd = sys.stdin.fileno()
330
settings = termios.tcgetattr(fd)
333
ch = sys.stdin.read(1)
335
termios.tcsetattr(fd, termios.TCSADRAIN, settings)
338
def __ask_user(self, prompt, options):
340
sys.stdout.write(prompt)
341
sys.stdout.write(' [')
345
sys.stdout.write(opt.char)
346
sys.stdout.write('?] (%s): ' % default.char)
348
response = self.__getchar()
350
# default, which we see as newline, is 'n'
351
if response in ['\n', '\r', '\r\n']:
352
response = default.char
354
print response # because echo is off
357
if opt.char == response:
361
print ' %s - %s' % (opt.char, opt.help)