~abentley/bzrtools/bzrtools.dev

86 by Aaron Bentley
Added Michael Ellerman's shelf/unshelf
1
#!/usr/bin/python
2
89 by Aaron Bentley
Added copyright/GPL notices
3
# Copyright (C) 2005 Michael Ellerman <michael@ellerman.id.au>
4
#
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.
9
#
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.
14
#
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
18
86 by Aaron Bentley
Added Michael Ellerman's shelf/unshelf
19
import patches
20
import os
21
import sys
22
import string
23
from bzrlib.commands import Command
24
25
def parse_args(args):
26
    if len(args) == 2 and args[1] == '--bzr-usage':
27
        print '\n'
28
        return True
29
    elif len(args) == 2 and args[1] == '--bzr-help':
30
        print 'Shelve a patch, you can get it back later with unshelve.'
31
        return True
32
    elif len(args) == 1:
33
        pass
34
    else:
35
        raise Exception("Don't understand args %s" % args)
36
37
    return False
38
39
def unshelve():
40
    root = run_bzr('root')[0].strip()
41
    shelf = os.path.join(root, '.bzr-shelf')
42
43
    if not os.path.exists(shelf):
44
        raise Exception("No shelf found in '%s'" % shelf)
45
46
    patch = open(shelf, 'r').read()
47
48
    print >>sys.stderr, "Reapplying shelved patches"
49
    pipe = os.popen('patch -d %s -s -p0' % root, 'w')
50
    pipe.write(patch)
51
    pipe.flush()
52
53
    if pipe.close() is not None:
54
        raise Exception("Failed running patch!")
55
56
    os.remove(shelf)
57
    print 'Diff status is now:'
58
    os.system('bzr diff | diffstat')
59
60
    return True
61
62
def shelve():
63
    diff_lines = run_bzr('diff')
64
    patch_list = patches.parse_patches(diff_lines.__iter__())
65
    to_shelve = prompt_user(patch_list)
66
67
    if len(to_shelve) == 0:
68
        print >>sys.stderr, 'Nothing to shelve'
69
        return True
70
71
    root = run_bzr('root')[0].strip()
72
    shelf = os.path.join(root, '.bzr-shelf')
73
    print >>sys.stderr, "Saving shelved patches to", shelf
74
    shelf = open(shelf, 'a')
75
76
    for patch in to_shelve:
77
        shelf.write(str(patch))
78
79
    shelf.flush()
80
    os.fsync(shelf.fileno())
81
    shelf.close()
82
83
    print >>sys.stderr, "Reverting shelved patches"
84
    pipe = os.popen('patch -d %s -sR -p0' % root, 'w')
85
    for patch in to_shelve:
86
       pipe.write(str(patch))
87
    pipe.flush()
88
89
    if pipe.close() is not None:
90
        raise Exception("Failed running patch!")
91
92
    print 'Diff status is now:'
93
    os.system('bzr diff | diffstat')
94
95
    return True
96
97
def run_bzr(args):
98
    if type(args) is str:
99
        args = [ args ]
100
    pipe = os.popen('bzr %s' % string.join(args, ' '), 'r')
101
    lines = pipe.readlines()
102
    if pipe.close() is not None:
103
        raise Exception("Failed running bzr")
104
    return lines
105
106
def prompt_user(patch_list):
107
    total = 0
108
    for patch in patch_list:
109
        total += len(patch.hunks)
110
111
    out = sys.stdout
112
    inp = sys.stdin
113
114
    to_shelve = []
115
    i = 1
116
    for patch in patch_list:
117
        if patch.oldname != patch.newname:
118
            name = "%s -> %s" % (patch.oldname, patch.newname)
119
        else:
120
            name = patch.oldname
121
122
        hunks = patch.hunks[:]
123
        for hunk in hunks:
124
            print name
125
            print hunk
126
            while True:
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':
130
                    break
131
                elif line == 'n' or line == 'no':
132
                    patch.hunks.remove(hunk)
133
                    break
134
135
            i += 1
136
137
        if len(patch.hunks) > 0:
138
            to_shelve.append(patch)
139
140
    return to_shelve
141
142
class cmd_shelve(Command):
143
    """Temporarily remove some changes from the current tree.
144
    Use 'unshelve' to restore these changes.
145
    """
146
147
    def run(self):
148
        return shelve()
149
150
class cmd_unshelve(Command):
151
    """Restore previously-shelved changes to the current tree.
152
    See also 'shelve'.
153
    """
154
    def run(self):
155
        return unshelve()