~abentley/bzrtools/bzrtools.dev

0.1.1 by Michael Ellerman
Initial import
1
#!/usr/bin/python
2
0.1.6 by Michael Ellerman
Move selection code into HunkSelector class
3
from patches import parse_patches
0.1.1 by Michael Ellerman
Initial import
4
import os
5
import sys
6
import string
0.1.23 by Michael Ellerman
Incorporate Aaron's changes from bzrtools.
7
import glob
8
import bzrlib
9
from bzrlib.commands import Command
10
from bzrlib.branch import Branch
11
from bzrlib import DEFAULT_IGNORE
12
from hunk_selector import HunkSelector
0.1.35 by Michael Ellerman
Use DiffStat rather than calling out to /bin/diffstat
13
from diffstat import DiffStat
0.1.23 by Michael Ellerman
Incorporate Aaron's changes from bzrtools.
14
15
DEFAULT_IGNORE.append('./.bzr-shelf*')
0.1.1 by Michael Ellerman
Initial import
16
0.1.27 by Michael Ellerman
Move all shelf functions into a class. Only logic change is we save the
17
class QuitException(Exception):
18
    pass
19
20
class Shelf(object):
0.1.38 by Michael Ellerman
Shelf() takes a location which specifies where to open the branch.
21
    def __init__(self, location):
22
        self.branch = Branch.open_containing(location)[0]
0.1.27 by Michael Ellerman
Move all shelf functions into a class. Only logic change is we save the
23
24
    def shelf_suffix(self, index):
25
        if index == 0:
26
            return ""
27
        else:
28
            return "-%d" % index
29
30
    def next_shelf(self):
31
        def name_sequence():
32
            i = 0
33
            while True:
34
                yield self.shelf_suffix(i)
35
                i = i + 1
36
0.1.31 by Michael Ellerman
- Keep our branch around, and use it directly instead of bzr_root.
37
        stem = os.path.join(self.branch.base, '.bzr-shelf')
0.1.27 by Michael Ellerman
Move all shelf functions into a class. Only logic change is we save the
38
        for end in name_sequence():
39
            name = stem + end
40
            if not os.path.exists(name):
41
                return name
42
43
    def last_shelf(self):
0.1.31 by Michael Ellerman
- Keep our branch around, and use it directly instead of bzr_root.
44
        stem = os.path.join(self.branch.base, '.bzr-shelf')
0.1.27 by Michael Ellerman
Move all shelf functions into a class. Only logic change is we save the
45
        shelves = glob.glob(stem)
46
        shelves.extend(glob.glob(stem + '-*'))
47
        def shelf_index(name):
48
            if name == stem:
49
                return 0
50
            return int(name[len(stem)+1:])
51
        shelvenums = [shelf_index(f) for f in shelves]
52
        shelvenums.sort()
53
54
        if len(shelvenums) == 0:
55
            return None
56
        return stem + self.shelf_suffix(shelvenums[-1])
57
58
    def get_shelf_message(self, shelf):
59
        prefix = "# shelf: "
60
        if not shelf.startswith(prefix):
61
            return None
62
        return shelf[len(prefix):shelf.index('\n')]
63
64
    def unshelve(self):
65
        shelf = self.last_shelf()
66
67
        if shelf is None:
0.1.31 by Michael Ellerman
- Keep our branch around, and use it directly instead of bzr_root.
68
            raise Exception("No shelf found in '%s'" % self.branch.base)
0.1.27 by Michael Ellerman
Move all shelf functions into a class. Only logic change is we save the
69
70
        patch = open(shelf, 'r').read()
71
72
        print >>sys.stderr, "Reapplying shelved patches",
73
        message = self.get_shelf_message(patch)
74
        if message is not None:
75
            print >>sys.stderr, ' "%s"' % message
76
        else:
77
            print >>sys.stderr, ""
0.1.31 by Michael Ellerman
- Keep our branch around, and use it directly instead of bzr_root.
78
        pipe = os.popen('patch -d %s -s -p0' % self.branch.base, 'w')
0.1.27 by Michael Ellerman
Move all shelf functions into a class. Only logic change is we save the
79
        pipe.write(patch)
80
        pipe.flush()
81
82
        if pipe.close() is not None:
83
            raise Exception("Failed running patch!")
84
85
        os.remove(shelf)
0.1.35 by Michael Ellerman
Use DiffStat rather than calling out to /bin/diffstat
86
87
        diff_stat = DiffStat(self.get_patches(None, None))
88
        print 'Diff status is now:\n', diff_stat
0.1.27 by Michael Ellerman
Move all shelf functions into a class. Only logic change is we save the
89
90
        return True
91
0.1.31 by Michael Ellerman
- Keep our branch around, and use it directly instead of bzr_root.
92
    def get_patches(self, revision, file_list):
93
        from StringIO import StringIO
94
        from bzrlib.diff import show_diff
95
        out = StringIO()
96
        show_diff(self.branch, revision, specific_files=file_list, output=out)
97
        out.seek(0)
98
        return out.readlines()
99
0.1.28 by Michael Ellerman
Implement "bzr shelve --all".
100
    def shelve(self, all_hunks=False, message=None, revision=None,
101
             file_list=None):
0.1.31 by Michael Ellerman
- Keep our branch around, and use it directly instead of bzr_root.
102
        patches = parse_patches(self.get_patches(revision, file_list))
103
0.1.28 by Michael Ellerman
Implement "bzr shelve --all".
104
        if not all_hunks:
105
            try:
106
                patches = HunkSelector(patches).select()
107
            except QuitException:
108
                return False
0.1.27 by Michael Ellerman
Move all shelf functions into a class. Only logic change is we save the
109
110
        if len(patches) == 0:
111
            print >>sys.stderr, 'Nothing to shelve'
112
            return True
113
114
        shelf = self.next_shelf()
115
        print >>sys.stderr, "Saving shelved patches to", shelf
116
        shelf = open(shelf, 'a')
117
        if message is not None:
118
            assert '\n' not in message
119
            shelf.write("# shelf: %s\n" % message)
120
        for patch in patches:
121
            shelf.write(str(patch))
122
123
        shelf.flush()
124
        os.fsync(shelf.fileno())
125
        shelf.close()
126
127
        print >>sys.stderr, "Reverting shelved patches"
0.1.31 by Michael Ellerman
- Keep our branch around, and use it directly instead of bzr_root.
128
        pipe = os.popen('patch -d %s -sR -p0' % self.branch.base, 'w')
0.1.27 by Michael Ellerman
Move all shelf functions into a class. Only logic change is we save the
129
        for patch in patches:
130
            pipe.write(str(patch))
131
        pipe.flush()
132
133
        if pipe.close() is not None:
134
            raise Exception("Failed running patch!")
135
0.1.35 by Michael Ellerman
Use DiffStat rather than calling out to /bin/diffstat
136
        diff_stat = DiffStat(self.get_patches(None, None))
137
        print 'Diff status is now:\n', diff_stat
0.1.27 by Michael Ellerman
Move all shelf functions into a class. Only logic change is we save the
138
139
        return True
140