/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
0.54.61 by Jeff Licquia
Assign copyright to Canonical.
1
# Copyright (C) 2008 Canonical Ltd
2
#
0.54.34 by Jeff Licquia
Add copyright/license info.
3
# This program is free software; you can redistribute it and/or modify
4
# it under the terms of the GNU General Public License as published by
5
# the Free Software Foundation; either version 2 of the License, or
0.54.61 by Jeff Licquia
Assign copyright to Canonical.
6
# (at your option) any later version.
0.54.57 by Jeff Licquia
Check and fix more PEP 8 failures.
7
#
0.54.34 by Jeff Licquia
Add copyright/license info.
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
# GNU General Public License for more details.
0.54.57 by Jeff Licquia
Check and fix more PEP 8 failures.
12
#
0.54.34 by Jeff Licquia
Add copyright/license info.
13
# You should have received a copy of the GNU General Public License
14
# along with this program; if not, write to the Free Software
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16
0.54.38 by Jeff Licquia
Add plugin description docstring.
17
"Support for git-style bisection."
18
0.54.11 by Jeff Licquia
Add log file handler, give it basic I/O, and write first tests for it.
19
import sys
0.54.4 by Jeff Licquia
Add test setup and dummy test.
20
import os
0.54.12 by Jeff Licquia
Add some bzr functionality.
21
import bzrlib.bzrdir
0.54.1 by Jeff Licquia
Initial revision. The plugin skeleton is made, along with a spec for
22
from bzrlib.commands import Command, register_command
0.54.3 by Jeff Licquia
Add test suite and get plugin to load.
23
from bzrlib.errors import BzrCommandError
0.54.37 by Jeff Licquia
Import the proper things for Option to work.
24
from bzrlib.option import Option
0.54.1 by Jeff Licquia
Initial revision. The plugin skeleton is made, along with a spec for
25
0.54.60 by Jeff Licquia
Move plugin metadata to its own package, and redo versioning.
26
from meta import *
27
0.54.11 by Jeff Licquia
Add log file handler, give it basic I/O, and write first tests for it.
28
bisect_info_path = ".bzr/bisect"
0.54.25 by Jeff Licquia
Change name of revid file.
29
bisect_rev_path = ".bzr/bisect_revid"
0.54.14 by Jeff Licquia
Create a parent for the test classes, and add a BisectCurrent class
30
0.54.52 by Jeff Licquia
PEP 8 fixes.
31
0.54.14 by Jeff Licquia
Create a parent for the test classes, and add a BisectCurrent class
32
class BisectCurrent(object):
33
    "Bisect class for managing the current revision."
34
35
    def __init__(self, filename = bisect_rev_path):
36
        self._filename = filename
37
        self._bzrdir = bzrlib.bzrdir.BzrDir.open_containing(".")[0]
0.54.16 by Jeff Licquia
Fix revision ID handling in BisectCurrent.
38
        self._bzrbranch = self._bzrdir.open_branch()
0.54.14 by Jeff Licquia
Create a parent for the test classes, and add a BisectCurrent class
39
        if os.path.exists(filename):
0.54.56 by Jeff Licquia
Fix some pylint complaints.
40
            revid_file = open(filename)
41
            self._revid = revid_file.read().strip()
42
            revid_file.close()
0.54.14 by Jeff Licquia
Create a parent for the test classes, and add a BisectCurrent class
43
        else:
0.54.27 by Jeff Licquia
Use the -r parameter when setting the bisect status, instead of setting
44
            self._revid = self._bzrbranch.last_revision()
0.54.14 by Jeff Licquia
Create a parent for the test classes, and add a BisectCurrent class
45
46
    def _save(self):
0.54.56 by Jeff Licquia
Fix some pylint complaints.
47
        "Save the current revision."
48
49
        revid_file = open(self._filename, "w")
50
        revid_file.write(self._revid + "\n")
51
        revid_file.close()
0.54.14 by Jeff Licquia
Create a parent for the test classes, and add a BisectCurrent class
52
0.54.27 by Jeff Licquia
Use the -r parameter when setting the bisect status, instead of setting
53
    def get_current_revid(self):
0.54.56 by Jeff Licquia
Fix some pylint complaints.
54
        "Return the current revision id."
0.54.27 by Jeff Licquia
Use the -r parameter when setting the bisect status, instead of setting
55
        return self._revid
56
0.59.3 by Jeff Licquia
Oops; make sure to retrieve and format the dotted revno properly.
57
    def get_current_revno(self):
58
        "Return the current revision number as a tuple."
59
        revdict = self._bzrbranch.get_revision_id_to_revno_map()
60
        return revdict[self.get_current_revid()]
61
0.54.51 by Jeff Licquia
Get subtree traversal working properly at last.
62
    def get_parent_revids(self):
0.54.56 by Jeff Licquia
Fix some pylint complaints.
63
        "Return the IDs of the current revision's predecessors."
0.54.55 by Jeff Licquia
Fix more missing locks, found in testing bzr 1.0 compatibility.
64
        repo = self._bzrbranch.repository
65
        repo.lock_read()
0.54.65 by Daniel Watkins
Fixed use of deprecated Repository.get_parents interface.
66
        retval = repo.get_parent_map([self._revid]).get(self._revid, None)
0.54.55 by Jeff Licquia
Fix more missing locks, found in testing bzr 1.0 compatibility.
67
        repo.unlock()
68
        return retval
0.54.44 by Jeff Licquia
Implement is_merge_point().
69
0.54.43 by Jeff Licquia
Add non-functioning is_merge_point() method to BisectCurrent.
70
    def is_merge_point(self):
71
        "Is the current revision a merge point?"
0.54.51 by Jeff Licquia
Get subtree traversal working properly at last.
72
        return len(self.get_parent_revids()) > 1
0.54.43 by Jeff Licquia
Add non-functioning is_merge_point() method to BisectCurrent.
73
0.54.32 by Jeff Licquia
When changing revisions, print information about the revision.
74
    def show_rev_log(self, out = sys.stdout):
0.54.56 by Jeff Licquia
Fix some pylint complaints.
75
        "Write the current revision's log entry to a file."
0.54.51 by Jeff Licquia
Get subtree traversal working properly at last.
76
        rev = self._bzrbranch.repository.get_revision(self._revid)
0.59.3 by Jeff Licquia
Oops; make sure to retrieve and format the dotted revno properly.
77
        revno = ".".join([str(x) for x in self.get_current_revno()])
78
        out.write("On revision %s (%s):\n%s\n" % (revno, rev.revision_id,
0.54.56 by Jeff Licquia
Fix some pylint complaints.
79
                                                  rev.message))
0.54.32 by Jeff Licquia
When changing revisions, print information about the revision.
80
0.54.22 by Jeff Licquia
Get BisectCurrent working.
81
    def switch(self, revid):
0.54.56 by Jeff Licquia
Fix some pylint complaints.
82
        "Switch the current revision to the given revid."
83
        working = self._bzrdir.open_workingtree()
0.54.22 by Jeff Licquia
Get BisectCurrent working.
84
        if isinstance(revid, int):
85
            revid = self._bzrbranch.get_rev_id(revid)
0.54.31 by Jeff Licquia
Do revision specs properly with "bisect move".
86
        elif isinstance(revid, list):
0.54.56 by Jeff Licquia
Fix some pylint complaints.
87
            revid = revid[0].in_history(working.branch).rev_id
0.54.64 by Daniel Watkins
Fixed use of deprecated WT.revert behaviour.
88
        working.revert(None, working.branch.repository.revision_tree(revid),
0.54.56 by Jeff Licquia
Fix some pylint complaints.
89
                       False)
0.54.22 by Jeff Licquia
Get BisectCurrent working.
90
        self._revid = revid
0.54.14 by Jeff Licquia
Create a parent for the test classes, and add a BisectCurrent class
91
        self._save()
0.54.11 by Jeff Licquia
Add log file handler, give it basic I/O, and write first tests for it.
92
0.54.22 by Jeff Licquia
Get BisectCurrent working.
93
    def reset(self):
0.54.56 by Jeff Licquia
Fix some pylint complaints.
94
        "Revert bisection, setting the working tree to normal."
95
        working = self._bzrdir.open_workingtree()
96
        last_rev = working.branch.last_revision()
97
        rev_tree = working.branch.repository.revision_tree(last_rev)
0.54.64 by Daniel Watkins
Fixed use of deprecated WT.revert behaviour.
98
        working.revert(None, rev_tree, False)
0.54.24 by Jeff Licquia
Only remove the bzr revno file if it exists.
99
        if os.path.exists(bisect_rev_path):
100
            os.unlink(bisect_rev_path)
0.54.22 by Jeff Licquia
Get BisectCurrent working.
101
0.54.52 by Jeff Licquia
PEP 8 fixes.
102
0.54.11 by Jeff Licquia
Add log file handler, give it basic I/O, and write first tests for it.
103
class BisectLog(object):
104
    "Bisect log file handler."
105
106
    def __init__(self, filename = bisect_info_path):
107
        self._items = []
0.54.16 by Jeff Licquia
Fix revision ID handling in BisectCurrent.
108
        self._current = BisectCurrent()
0.54.12 by Jeff Licquia
Add some bzr functionality.
109
        self._bzrdir = None
0.54.51 by Jeff Licquia
Get subtree traversal working properly at last.
110
        self._high_revid = None
111
        self._low_revid = None
0.54.45 by Jeff Licquia
Refactor finding range and middle; store the middle revid, not revno.
112
        self._middle_revid = None
0.54.56 by Jeff Licquia
Fix some pylint complaints.
113
        self._filename = filename
0.54.11 by Jeff Licquia
Add log file handler, give it basic I/O, and write first tests for it.
114
        self.load()
115
116
    def _open_for_read(self):
0.54.56 by Jeff Licquia
Fix some pylint complaints.
117
        "Open log file for reading."
0.54.11 by Jeff Licquia
Add log file handler, give it basic I/O, and write first tests for it.
118
        if self._filename:
119
            return open(self._filename)
120
        else:
121
            return sys.stdin
122
123
    def _open_for_write(self):
0.54.56 by Jeff Licquia
Fix some pylint complaints.
124
        "Open log file for writing."
0.54.11 by Jeff Licquia
Add log file handler, give it basic I/O, and write first tests for it.
125
        if self._filename:
126
            return open(self._filename, "w")
127
        else:
128
            return sys.stdout
129
0.54.12 by Jeff Licquia
Add some bzr functionality.
130
    def _load_bzr_tree(self):
0.54.56 by Jeff Licquia
Fix some pylint complaints.
131
        "Load bzr information."
0.54.12 by Jeff Licquia
Add some bzr functionality.
132
        if not self._bzrdir:
133
            self._bzrdir = bzrlib.bzrdir.BzrDir.open_containing('.')[0]
134
            self._bzrbranch = self._bzrdir.open_branch()
135
0.54.51 by Jeff Licquia
Get subtree traversal working properly at last.
136
    def _find_range_and_middle(self, branch_last_rev = None):
0.54.56 by Jeff Licquia
Fix some pylint complaints.
137
        "Find the current revision range, and the midpoint."
0.54.12 by Jeff Licquia
Add some bzr functionality.
138
        self._load_bzr_tree()
0.54.47 by Jeff Licquia
Refactor: when finding the middle, iterate over revids instead of
139
        self._middle_revid = None
0.54.21 by Jeff Licquia
The bisect call should detect a missing range, and just silently return.
140
0.54.51 by Jeff Licquia
Get subtree traversal working properly at last.
141
        if not branch_last_rev:
142
            last_revid = self._bzrbranch.last_revision()
143
        else:
144
            last_revid = branch_last_rev
145
0.54.52 by Jeff Licquia
PEP 8 fixes.
146
        repo = self._bzrbranch.repository
0.54.55 by Jeff Licquia
Fix more missing locks, found in testing bzr 1.0 compatibility.
147
        repo.lock_read()
0.54.52 by Jeff Licquia
PEP 8 fixes.
148
        rev_sequence = repo.iter_reverse_revision_history(last_revid)
0.54.47 by Jeff Licquia
Refactor: when finding the middle, iterate over revids instead of
149
        high_revid = None
150
        low_revid = None
151
        between_revs = []
0.54.48 by Jeff Licquia
More refactoring: go backwards from a high revision when finding the
152
        for revision in rev_sequence:
153
            between_revs.insert(0, revision)
0.54.52 by Jeff Licquia
PEP 8 fixes.
154
            matches = [x[1] for x in self._items
0.54.20 by Jeff Licquia
When looking for range, only use revision entries that have been
155
                       if x[0] == revision and x[1] in ('yes', 'no')]
0.54.12 by Jeff Licquia
Add some bzr functionality.
156
            if not matches:
157
                continue
158
            if len(matches) > 1:
0.54.47 by Jeff Licquia
Refactor: when finding the middle, iterate over revids instead of
159
                raise RuntimeError("revision %s duplicated" % revision)
0.54.12 by Jeff Licquia
Add some bzr functionality.
160
            if matches[0] == "yes":
0.54.47 by Jeff Licquia
Refactor: when finding the middle, iterate over revids instead of
161
                high_revid = revision
0.54.48 by Jeff Licquia
More refactoring: go backwards from a high revision when finding the
162
                between_revs = []
0.54.12 by Jeff Licquia
Add some bzr functionality.
163
            elif matches[0] == "no":
0.54.47 by Jeff Licquia
Refactor: when finding the middle, iterate over revids instead of
164
                low_revid = revision
0.54.48 by Jeff Licquia
More refactoring: go backwards from a high revision when finding the
165
                del between_revs[0]
166
                break
0.54.47 by Jeff Licquia
Refactor: when finding the middle, iterate over revids instead of
167
168
        if not high_revid:
169
            high_revid = last_revid
0.54.51 by Jeff Licquia
Get subtree traversal working properly at last.
170
        if not low_revid:
171
            low_revid = self._bzrbranch.get_rev_id(1)
0.54.47 by Jeff Licquia
Refactor: when finding the middle, iterate over revids instead of
172
0.54.55 by Jeff Licquia
Fix more missing locks, found in testing bzr 1.0 compatibility.
173
        repo.unlock()
174
0.54.47 by Jeff Licquia
Refactor: when finding the middle, iterate over revids instead of
175
        # The spread must include the high revision, to bias
176
        # odd numbers of intervening revisions towards the high
177
        # side.
178
179
        spread = len(between_revs) + 1
180
        if spread < 2:
181
            middle_index = 0
182
        else:
183
            middle_index = (spread / 2) - 1
184
185
        if len(between_revs) > 0:
186
            self._middle_revid = between_revs[middle_index]
187
        else:
188
            self._middle_revid = high_revid
0.54.12 by Jeff Licquia
Add some bzr functionality.
189
0.54.51 by Jeff Licquia
Get subtree traversal working properly at last.
190
        self._high_revid = high_revid
191
        self._low_revid = low_revid
192
0.54.12 by Jeff Licquia
Add some bzr functionality.
193
    def _switch_wc_to_revno(self, revno):
0.54.56 by Jeff Licquia
Fix some pylint complaints.
194
        "Move the working tree to the given revno."
0.54.18 by Jeff Licquia
Incorporate use of new BisectCurrent objects where appropriate.
195
        self._current.switch(revno)
0.54.32 by Jeff Licquia
When changing revisions, print information about the revision.
196
        self._current.show_rev_log()
0.54.12 by Jeff Licquia
Add some bzr functionality.
197
0.54.30 by Jeff Licquia
Distinguish between revision specs and revision ids, and do the right
198
    def _set_status(self, revid, status):
0.54.56 by Jeff Licquia
Fix some pylint complaints.
199
        "Set the bisect status for the given revid."
0.59.7 by Jeff Licquia
Tests for detecting "done" status, plus a first run at implementation.
200
        if not self.is_done():
201
            if status != "done" and revid in [x[0] for x in self._items 
202
                                              if x[1] in ['yes', 'no']]:
203
                raise RuntimeError("attempting to add revid %s twice" % revid)
204
            self._items.append((revid, status))
0.54.30 by Jeff Licquia
Distinguish between revision specs and revision ids, and do the right
205
0.54.11 by Jeff Licquia
Add log file handler, give it basic I/O, and write first tests for it.
206
    def change_file_name(self, filename):
0.54.56 by Jeff Licquia
Fix some pylint complaints.
207
        "Switch log files."
0.54.11 by Jeff Licquia
Add log file handler, give it basic I/O, and write first tests for it.
208
        self._filename = filename
209
210
    def load(self):
0.54.56 by Jeff Licquia
Fix some pylint complaints.
211
        "Load the bisection log."
0.54.11 by Jeff Licquia
Add log file handler, give it basic I/O, and write first tests for it.
212
        self._items = []
213
        if os.path.exists(self._filename):
0.54.56 by Jeff Licquia
Fix some pylint complaints.
214
            revlog = self._open_for_read()
215
            for line in revlog:
0.54.11 by Jeff Licquia
Add log file handler, give it basic I/O, and write first tests for it.
216
                (revid, status) = line.split()
217
                self._items.append((revid, status))
218
219
    def save(self):
0.54.56 by Jeff Licquia
Fix some pylint complaints.
220
        "Save the bisection log."
221
        revlog = self._open_for_write()
0.54.11 by Jeff Licquia
Add log file handler, give it basic I/O, and write first tests for it.
222
        for (revid, status) in self._items:
0.54.56 by Jeff Licquia
Fix some pylint complaints.
223
            revlog.write("%s %s\n" % (revid, status))
0.54.11 by Jeff Licquia
Add log file handler, give it basic I/O, and write first tests for it.
224
0.59.7 by Jeff Licquia
Tests for detecting "done" status, plus a first run at implementation.
225
    def is_done(self):
226
        "Report whether we've found the right revision."
227
        return len(self._items) > 0 and self._items[-1][1] == "done"
228
0.54.30 by Jeff Licquia
Distinguish between revision specs and revision ids, and do the right
229
    def set_status_from_revspec(self, revspec, status):
0.54.56 by Jeff Licquia
Fix some pylint complaints.
230
        "Set the bisection status for the revision in revspec."
0.54.30 by Jeff Licquia
Distinguish between revision specs and revision ids, and do the right
231
        self._load_bzr_tree()
232
        revid = revspec[0].in_history(self._bzrbranch).rev_id
233
        self._set_status(revid, status)
0.54.27 by Jeff Licquia
Use the -r parameter when setting the bisect status, instead of setting
234
0.54.12 by Jeff Licquia
Add some bzr functionality.
235
    def set_current(self, status):
0.54.56 by Jeff Licquia
Fix some pylint complaints.
236
        "Set the current revision to the given bisection status."
0.54.30 by Jeff Licquia
Distinguish between revision specs and revision ids, and do the right
237
        self._set_status(self._current.get_current_revid(), status)
0.54.12 by Jeff Licquia
Add some bzr functionality.
238
239
    def bisect(self):
0.54.56 by Jeff Licquia
Fix some pylint complaints.
240
        "Using the current revision's status, do a bisection."
0.54.51 by Jeff Licquia
Get subtree traversal working properly at last.
241
        self._find_range_and_middle()
242
        self._switch_wc_to_revno(self._middle_revid)
243
244
        # If we've found the "final" revision, check for a
245
        # merge point.
246
0.59.7 by Jeff Licquia
Tests for detecting "done" status, plus a first run at implementation.
247
        if self._middle_revid == self._high_revid or \
248
           self._middle_revid == self._low_revid:
249
            if self._current.is_merge_point():
250
                for parent in self._current.get_parent_revids():
251
                    if parent == self._low_revid:
252
                        continue
253
                    else:
254
                        self._find_range_and_middle(parent)
255
                        self._switch_wc_to_revno(self._middle_revid)
256
                        break
257
            else:
258
                self.set_current("done")
0.54.12 by Jeff Licquia
Add some bzr functionality.
259
0.54.52 by Jeff Licquia
PEP 8 fixes.
260
0.54.1 by Jeff Licquia
Initial revision. The plugin skeleton is made, along with a spec for
261
class cmd_bisect(Command):
262
    """Find an interesting commit using a binary search.
263
264
    Bisecting, in a nutshell, is a way to find the commit at which
265
    some testable change was made, such as the introduction of a bug
266
    or feature.  By identifying a version which did not have the
267
    interesting change and a later version which did, a developer
268
    can test for the presence of the change at various points in
269
    the history, eventually ending up at the precise commit when
270
    the change was first introduced.
271
272
    This command uses subcommands to implement the search, each
273
    of which changes the state of the bisection.  The
274
    subcommands are:
275
276
    bzr bisect start
277
        Start a bisect, possibly clearing out a previous bisect.
278
279
    bzr bisect yes [-r rev]
280
        The specified revision (or the current revision, if not given)
281
        has the characteristic we're looking for,
282
283
    bzr bisect no [-r rev]
284
        The specified revision (or the current revision, if not given)
0.55.1 by Doug Lee
Minor spello fix.
285
        does not have the characteristic we're looking for,
0.54.1 by Jeff Licquia
Initial revision. The plugin skeleton is made, along with a spec for
286
0.54.13 by Jeff Licquia
Since bzr does not store a "current revision" other than the last
287
    bzr bisect move -r rev
288
        Switch to a different revision manually.  Use if the bisect
289
        algorithm chooses a revision that is not suitable.  Try to
290
        move as little as possible.
291
0.54.1 by Jeff Licquia
Initial revision. The plugin skeleton is made, along with a spec for
292
    bzr bisect reset
293
        Clear out a bisection in progress.
294
0.54.36 by Jeff Licquia
Add -o for log, and use it in the tests to capture the log.
295
    bzr bisect log [-o file]
296
        Output a log of the current bisection to standard output, or
297
        to the specified file.
0.54.1 by Jeff Licquia
Initial revision. The plugin skeleton is made, along with a spec for
298
299
    bzr bisect replay <logfile>
300
        Replay a previously-saved bisect log, forgetting any bisection
301
        that might be in progress.
0.54.62 by Daniel Watkins
Added 'run' docs.
302
303
    bzr bisect run <script>
304
        Bisect automatically using <script> to determine 'yes' or 'no'.
0.54.2 by Jeff Licquia
Set up the subcommand dispatcher.
305
    """
306
307
    takes_args = ['subcommand', 'args*']
0.54.36 by Jeff Licquia
Add -o for log, and use it in the tests to capture the log.
308
    takes_options = [Option('output', short_name='o',
309
                            help='Write log to this file.', type=unicode),
310
                     'revision']
0.54.2 by Jeff Licquia
Set up the subcommand dispatcher.
311
0.54.11 by Jeff Licquia
Add log file handler, give it basic I/O, and write first tests for it.
312
    def _check(self):
0.54.56 by Jeff Licquia
Fix some pylint complaints.
313
        "Check preconditions for most operations to work."
0.54.11 by Jeff Licquia
Add log file handler, give it basic I/O, and write first tests for it.
314
        if not os.path.exists(bisect_info_path):
315
            raise BzrCommandError("No bisect info found")
316
0.54.29 by Jeff Licquia
Oops! Mark start of method properly.
317
    def _set_state(self, revspec, state):
0.54.70 by Daniel Watkins
Modified to avoid getting stuck in loop when complete.
318
        """Set the state of the given revspec and bisecting.
319
320
        Returns boolean indicating if bisection is done."""
0.54.56 by Jeff Licquia
Fix some pylint complaints.
321
        bisect_log = BisectLog()
0.59.7 by Jeff Licquia
Tests for detecting "done" status, plus a first run at implementation.
322
        if bisect_log.is_done():
323
            sys.stdout.write("No further bisection is possible.\n")
324
            bisect_log._current.show_rev_log(sys.stdout)
0.54.70 by Daniel Watkins
Modified to avoid getting stuck in loop when complete.
325
            return True
0.59.7 by Jeff Licquia
Tests for detecting "done" status, plus a first run at implementation.
326
0.54.28 by Jeff Licquia
Refactor shared code to prevent cut-n-paste errors.
327
        if revspec:
0.54.56 by Jeff Licquia
Fix some pylint complaints.
328
            bisect_log.set_status_from_revspec(revspec, state)
0.54.28 by Jeff Licquia
Refactor shared code to prevent cut-n-paste errors.
329
        else:
0.54.56 by Jeff Licquia
Fix some pylint complaints.
330
            bisect_log.set_current(state)
331
        bisect_log.bisect()
332
        bisect_log.save()
0.54.70 by Daniel Watkins
Modified to avoid getting stuck in loop when complete.
333
        return False
0.54.28 by Jeff Licquia
Refactor shared code to prevent cut-n-paste errors.
334
0.54.36 by Jeff Licquia
Add -o for log, and use it in the tests to capture the log.
335
    def run(self, subcommand, args_list, revision=None, output=None):
0.54.56 by Jeff Licquia
Fix some pylint complaints.
336
        "Handle the bisect command."
0.54.2 by Jeff Licquia
Set up the subcommand dispatcher.
337
338
        log_fn = None
0.54.13 by Jeff Licquia
Since bzr does not store a "current revision" other than the last
339
        if subcommand in ('yes', 'no', 'move') and revision:
0.54.8 by Jeff Licquia
Fix dispatcher.
340
            pass
0.54.57 by Jeff Licquia
Check and fix more PEP 8 failures.
341
        elif subcommand in ('replay', ) and args_list and len(args_list) == 1:
0.54.2 by Jeff Licquia
Set up the subcommand dispatcher.
342
            log_fn = args_list[0]
0.54.57 by Jeff Licquia
Check and fix more PEP 8 failures.
343
        elif subcommand in ('move', ) and not revision:
0.54.52 by Jeff Licquia
PEP 8 fixes.
344
            raise BzrCommandError(
345
                "The 'bisect move' command requires a revision.")
0.54.63 by Daniel Watkins
Added frontend logic of 'run'.
346
        elif subcommand in ('run', ):
347
            run_script = args_list[0]
0.54.8 by Jeff Licquia
Fix dispatcher.
348
        elif args_list or revision:
0.54.52 by Jeff Licquia
PEP 8 fixes.
349
            raise BzrCommandError(
350
                "Improper arguments to bisect " + subcommand)
0.54.2 by Jeff Licquia
Set up the subcommand dispatcher.
351
352
        # Dispatch.
353
354
        if subcommand == "start":
355
            self.start()
356
        elif subcommand == "yes":
357
            self.yes(revision)
358
        elif subcommand == "no":
359
            self.no(revision)
0.54.13 by Jeff Licquia
Since bzr does not store a "current revision" other than the last
360
        elif subcommand == "move":
361
            self.move(revision)
0.54.2 by Jeff Licquia
Set up the subcommand dispatcher.
362
        elif subcommand == "reset":
363
            self.reset()
364
        elif subcommand == "log":
0.54.36 by Jeff Licquia
Add -o for log, and use it in the tests to capture the log.
365
            self.log(output)
0.54.2 by Jeff Licquia
Set up the subcommand dispatcher.
366
        elif subcommand == "replay":
367
            self.replay(log_fn)
0.54.63 by Daniel Watkins
Added frontend logic of 'run'.
368
        elif subcommand == "run":
369
            self.run_bisect(run_script)
0.59.5 by Jeff Licquia
Report an error on unrecognized subcommands.
370
        else:
371
            raise BzrCommandError(
372
                "Unknown bisect command: " + subcommand)
0.54.2 by Jeff Licquia
Set up the subcommand dispatcher.
373
374
    def reset(self):
375
        "Reset the bisect state to no state."
0.54.11 by Jeff Licquia
Add log file handler, give it basic I/O, and write first tests for it.
376
377
        if os.path.exists(bisect_info_path):
0.59.4 by Jeff Licquia
Make reset a no-op if no bisection is in progress.
378
            BisectCurrent().reset()
0.54.11 by Jeff Licquia
Add log file handler, give it basic I/O, and write first tests for it.
379
            os.unlink(bisect_info_path)
0.59.4 by Jeff Licquia
Make reset a no-op if no bisection is in progress.
380
        else:
381
            sys.stdout.write("No bisection in progress; nothing to do.\n")
0.54.2 by Jeff Licquia
Set up the subcommand dispatcher.
382
383
    def start(self):
384
        "Reset the bisect state, then prepare for a new bisection."
0.54.11 by Jeff Licquia
Add log file handler, give it basic I/O, and write first tests for it.
385
0.59.6 by Jeff Licquia
Get rid of spew when starting a bisect.
386
        if os.path.exists(bisect_info_path):
387
            BisectCurrent().reset()
388
            os.unlink(bisect_info_path)
389
0.54.56 by Jeff Licquia
Fix some pylint complaints.
390
        bisect_log = BisectLog()
391
        bisect_log.set_current("start")
392
        bisect_log.save()
0.54.2 by Jeff Licquia
Set up the subcommand dispatcher.
393
0.54.28 by Jeff Licquia
Refactor shared code to prevent cut-n-paste errors.
394
    def yes(self, revspec):
0.54.2 by Jeff Licquia
Set up the subcommand dispatcher.
395
        "Mark that a given revision has the state we're looking for."
0.54.12 by Jeff Licquia
Add some bzr functionality.
396
0.54.28 by Jeff Licquia
Refactor shared code to prevent cut-n-paste errors.
397
        self._set_state(revspec, "yes")
0.54.2 by Jeff Licquia
Set up the subcommand dispatcher.
398
0.54.28 by Jeff Licquia
Refactor shared code to prevent cut-n-paste errors.
399
    def no(self, revspec):
0.54.2 by Jeff Licquia
Set up the subcommand dispatcher.
400
        "Mark that a given revision does not have the state we're looking for."
0.54.12 by Jeff Licquia
Add some bzr functionality.
401
0.54.28 by Jeff Licquia
Refactor shared code to prevent cut-n-paste errors.
402
        self._set_state(revspec, "no")
0.54.2 by Jeff Licquia
Set up the subcommand dispatcher.
403
0.54.31 by Jeff Licquia
Do revision specs properly with "bisect move".
404
    def move(self, revspec):
0.54.13 by Jeff Licquia
Since bzr does not store a "current revision" other than the last
405
        "Move to a different revision manually."
406
0.54.56 by Jeff Licquia
Fix some pylint complaints.
407
        current = BisectCurrent()
408
        current.switch(revspec)
409
        current.show_rev_log()
0.54.13 by Jeff Licquia
Since bzr does not store a "current revision" other than the last
410
0.54.2 by Jeff Licquia
Set up the subcommand dispatcher.
411
    def log(self, filename):
412
        "Write the current bisect log to a file."
0.54.11 by Jeff Licquia
Add log file handler, give it basic I/O, and write first tests for it.
413
414
        self._check()
415
0.54.56 by Jeff Licquia
Fix some pylint complaints.
416
        bisect_log = BisectLog()
417
        bisect_log.change_file_name(filename)
418
        bisect_log.save()
0.54.2 by Jeff Licquia
Set up the subcommand dispatcher.
419
420
    def replay(self, filename):
421
        """Apply the given log file to a clean state, so the state is
422
        exactly as it was when the log was saved."""
0.54.11 by Jeff Licquia
Add log file handler, give it basic I/O, and write first tests for it.
423
424
        self.reset()
425
0.54.56 by Jeff Licquia
Fix some pylint complaints.
426
        bisect_log = BisectLog(filename)
427
        bisect_log.change_file_name(bisect_info_path)
428
        bisect_log.save()
0.54.1 by Jeff Licquia
Initial revision. The plugin skeleton is made, along with a spec for
429
0.54.56 by Jeff Licquia
Fix some pylint complaints.
430
        bisect_log.bisect()
0.54.12 by Jeff Licquia
Add some bzr functionality.
431
0.54.67 by Daniel Watkins
First pass at run_bisect.
432
    def run_bisect(self, script):
433
        import subprocess
434
        print "Starting bisect."
435
        self.start()
436
        while True:
437
            try:
0.54.68 by Daniel Watkins
Correct stupid error, command now basically working.
438
                process = subprocess.Popen(script, shell=True)
439
                process.wait()
440
                retcode = process.returncode
0.54.67 by Daniel Watkins
First pass at run_bisect.
441
                if retcode == 0:
0.54.70 by Daniel Watkins
Modified to avoid getting stuck in loop when complete.
442
                    done = self._set_state(None, 'yes')
0.54.67 by Daniel Watkins
First pass at run_bisect.
443
                elif retcode == 125:
444
                    break
445
                else:
0.54.70 by Daniel Watkins
Modified to avoid getting stuck in loop when complete.
446
                    done = self._set_state(None, 'no')
447
                if done:
448
                    break
0.54.67 by Daniel Watkins
First pass at run_bisect.
449
            except RuntimeError:
450
                break
451
0.54.1 by Jeff Licquia
Initial revision. The plugin skeleton is made, along with a spec for
452
register_command(cmd_bisect)
0.54.3 by Jeff Licquia
Add test suite and get plugin to load.
453
0.54.52 by Jeff Licquia
PEP 8 fixes.
454
0.54.3 by Jeff Licquia
Add test suite and get plugin to load.
455
def test_suite():
0.54.56 by Jeff Licquia
Fix some pylint complaints.
456
    "Set up the test suite for the plugin."
0.54.40 by Jeff Licquia
Move the tests to their own module.
457
    from bzrlib.plugins.bisect import tests
0.54.53 by Jeff Licquia
Move test suite detection function to the test module.
458
    return tests.test_suite()