~abentley/bzrtools/bzrtools.dev

« back to all changes in this revision

Viewing changes to shelf.py

  • Committer: Aaron Bentley
  • Date: 2012-03-20 02:40:57 UTC
  • Revision ID: aaron@aaronbentley.com-20120320024057-mqltf93xxs09r0ry
Compatibility fixes for bzr.dev

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
#!/usr/bin/python
2
 
 
3
1
import os
4
2
import sys
5
 
import subprocess
6
3
from datetime import datetime
7
4
from errors import CommandError, PatchFailed
8
5
from hunk_selector import ShelveHunkSelector, UnshelveHunkSelector
9
 
from patchsource import PatchSource, FilePatchSource
 
6
from patch import run_patch
 
7
from patchsource import FilePatchSource
 
8
from bzrlib.osutils import rename
10
9
 
11
10
class Shelf(object):
12
11
    MESSAGE_PREFIX = "# Shelved patch: "
56
55
 
57
56
    def delete(self, patch):
58
57
        path = self.__path_from_user(patch)
59
 
        os.remove(path)
 
58
        rename(path, '%s~' % path)
60
59
 
61
 
    def display(self, patch):
62
 
        path = self.__path_from_user(patch)
 
60
    def display(self, patch=None):
 
61
        if patch is None:
 
62
            path = self.last_patch()
 
63
            if path is None:
 
64
                raise CommandError("No patches on shelf.")
 
65
        else:
 
66
            path = self.__path_from_user(patch)
63
67
        sys.stdout.write(open(path).read())
64
68
 
65
69
    def list(self):
78
82
    def __path_from_user(self, patch_id):
79
83
        try:
80
84
            patch_index = int(patch_id)
81
 
        except TypeError:
 
85
        except (TypeError, ValueError):
82
86
            raise CommandError("Invalid patch name '%s'" % patch_id)
83
87
 
84
88
        path = self.__path(patch_index)
130
134
            return None
131
135
        return patch[len(self.MESSAGE_PREFIX):patch.index('\n')]
132
136
 
133
 
    def unshelve(self, patch_source, all_hunks=False, force=False):
 
137
    def unshelve(self, patch_source, patch_name=None, all=False, force=False,
 
138
                 no_color=False):
134
139
        self._check_upgrade()
135
140
 
136
 
        patch_name = self.last_patch()
137
 
 
 
141
        if no_color is False:
 
142
            color = None
 
143
        else:
 
144
            color = False
138
145
        if patch_name is None:
 
146
            patch_path = self.last_patch()
 
147
        else:
 
148
            patch_path = self.__path_from_user(patch_name)
 
149
 
 
150
        if patch_path is None:
139
151
            raise CommandError("No patch found on shelf %s" % self.name)
140
152
 
141
 
        hunks = FilePatchSource(patch_name).readhunks()
142
 
        if all_hunks:
143
 
            to_unshelve = hunks
 
153
        patches = FilePatchSource(patch_path).readpatches()
 
154
        if all:
 
155
            to_unshelve = patches
144
156
            to_remain = []
145
157
        else:
146
 
            to_unshelve, to_remain = UnshelveHunkSelector(hunks).select()
 
158
            hs = UnshelveHunkSelector(patches, color)
 
159
            to_unshelve, to_remain = hs.select()
147
160
 
148
161
        if len(to_unshelve) == 0:
149
162
            raise CommandError('Nothing to unshelve')
150
163
 
151
 
        message = self.get_patch_message(patch_name)
 
164
        message = self.get_patch_message(patch_path)
152
165
        if message is None:
153
166
            message = "No message saved with patch."
154
167
        self.log('Unshelving from %s/%s: "%s"\n' % \
155
 
                (self.name, os.path.basename(patch_name), message))
 
168
                (self.name, os.path.basename(patch_path), message))
156
169
 
157
170
        try:
158
171
            self._run_patch(to_unshelve, dry_run=True)
159
172
            self._run_patch(to_unshelve)
160
173
        except PatchFailed:
161
174
            try:
162
 
                self._run_patch(to_unshelve, strip=0, dry_run=True)
163
 
                self._run_patch(to_unshelve, strip=0)
 
175
                self._run_patch(to_unshelve, strip=1, dry_run=True)
 
176
                self._run_patch(to_unshelve, strip=1)
164
177
            except PatchFailed:
165
178
                if force:
166
179
                    self.log('Warning: Unshelving failed, forcing as ' \
174
187
                    "longer applies cleanly to the working tree!")
175
188
 
176
189
        # Backup the shelved patch
177
 
        os.rename(patch_name, '%s~' % patch_name)
 
190
        rename(patch_path, '%s~' % patch_path)
178
191
 
179
192
        if len(to_remain) > 0:
180
 
            f = open(patch_name, 'w')
181
 
            for hunk in to_remain:
182
 
                f.write(str(hunk))
 
193
            f = open(patch_path, 'w')
 
194
            for patch in to_remain:
 
195
                f.write(str(patch))
183
196
            f.close()
184
197
 
185
 
    def shelve(self, patch_source, all_hunks=False, message=None):
 
198
    def shelve(self, patch_source, all=False, message=None, no_color=False):
186
199
        self._check_upgrade()
187
 
 
188
 
        hunks = patch_source.readhunks()
189
 
 
190
 
        if all_hunks:
191
 
            to_shelve = hunks
192
 
        else:
193
 
            to_shelve = ShelveHunkSelector(hunks).select()[0]
 
200
        if no_color is False:
 
201
            color = None
 
202
        else:
 
203
            color = False
 
204
 
 
205
        patches = patch_source.readpatches()
 
206
 
 
207
        if all:
 
208
            to_shelve = patches
 
209
        else:
 
210
            to_shelve = ShelveHunkSelector(patches, color).select()[0]
194
211
 
195
212
        if len(to_shelve) == 0:
196
213
            raise CommandError('Nothing to shelve')
199
216
            timestamp = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
200
217
            message = "Changes shelved on %s" % timestamp
201
218
 
202
 
        patch_name = self.next_patch()
 
219
        patch_path = self.next_patch()
203
220
        self.log('Shelving to %s/%s: "%s"\n' % \
204
 
                (self.name, os.path.basename(patch_name), message))
 
221
                (self.name, os.path.basename(patch_path), message))
205
222
 
206
 
        patch = open(patch_name, 'a')
 
223
        f = open(patch_path, 'a')
207
224
 
208
225
        assert '\n' not in message
209
 
        patch.write("%s%s\n" % (self.MESSAGE_PREFIX, message))
210
 
 
211
 
        for hunk in to_shelve:
212
 
            patch.write(str(hunk))
213
 
 
214
 
        patch.flush()
215
 
        os.fsync(patch.fileno())
216
 
        patch.close()
 
226
        f.write("%s%s\n" % (self.MESSAGE_PREFIX, message))
 
227
 
 
228
        for patch in to_shelve:
 
229
            f.write(str(patch))
 
230
 
 
231
        f.flush()
 
232
        os.fsync(f.fileno())
 
233
        f.close()
217
234
 
218
235
        try:
219
236
            self._run_patch(to_shelve, reverse=True, dry_run=True)
220
237
            self._run_patch(to_shelve, reverse=True)
221
238
        except PatchFailed:
222
239
            try:
223
 
                self._run_patch(to_shelve, reverse=True, strip=0, dry_run=True)
224
 
                self._run_patch(to_shelve, reverse=True, strip=0)
 
240
                self._run_patch(to_shelve, reverse=True, strip=1, dry_run=True)
 
241
                self._run_patch(to_shelve, reverse=True, strip=1)
225
242
            except PatchFailed:
226
243
                raise CommandError("Failed removing shelved changes from the"
227
244
                    "working tree!")
228
245
 
229
 
    def _run_patch(self, patches, strip=1, reverse=False, dry_run=False):
230
 
        args = ['patch', '-d', self.base, '-s', '-p%d' % strip, '-f']
231
 
        if reverse:
232
 
            args.append('-R')
233
 
        if dry_run:
234
 
            args.append('--dry-run')
235
 
            stdout = stderr = subprocess.PIPE
236
 
        else:
237
 
            stdout = stderr = None
238
 
 
239
 
        process = subprocess.Popen(args, stdin=subprocess.PIPE, stdout=stdout,
240
 
                        stderr=stderr)
241
 
        for patch in patches:
242
 
            process.stdin.write(str(patch))
243
 
 
244
 
        process.communicate()
245
 
 
246
 
        result = process.wait()
247
 
        if result != 0:
248
 
            raise PatchFailed()
249
 
 
250
 
        return result
 
246
    def _run_patch(self, patches, strip=0, reverse=False, dry_run=False):
 
247
        run_patch(self.base, patches, strip, reverse, dry_run)
251
248
 
252
249
    def _check_upgrade(self):
253
250
        if len(self._list_old_shelves()) > 0:
304
301
            new_file.close()
305
302
            self.log('Copied %s to %s/%s\n' % (os.path.basename(patch),
306
303
                self.name, os.path.basename(new_path)))
307
 
            os.rename(patch, patch + '~')
 
304
            rename(patch, patch + '~')