/brz/remove-bazaar

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