~abentley/bzrtools/bzrtools.dev

147.1.3 by Robert Collins
test and deliver basic pending-merges into bzr so that merging is recorded
1
# Copyright (C) 2004 Aaron Bentley
612 by Aaron Bentley
Update email address
2
# <aaron@aaronbentley.com>
147.1.3 by Robert Collins
test and deliver basic pending-merges into bzr so that merging is recorded
3
#
4
#    This program is free software; you can redistribute it and/or modify
5
#    it under the terms of the GNU General Public License as published by
6
#    the Free Software Foundation; either version 2 of the License, or
7
#    (at your option) any later version.
8
#
9
#    This program is distributed in the hope that it will be useful,
10
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
11
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
#    GNU General Public License for more details.
13
#
14
#    You should have received a copy of the GNU General Public License
15
#    along with this program; if not, write to the Free Software
16
#    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17
147.2.3 by Aaron Bentley
Fixed import issues w/ PyBaz
18
import pybaz
19
from pybaz.backends.baz import sequence_cmd
147.1.3 by Robert Collins
test and deliver basic pending-merges into bzr so that merging is recorded
20
import re
21
22
__docformat__ = "restructuredtext"
23
__doc__ = "Utility functions to be used by commands"
147.1.24 by Robert Collins
trim fai cribbage
24
147.4.6 by Robert Collins
Fix continuation direct_merges output, and allow reusing history in a version import
25
def direct_merges(merges, excludes=[]):
147.1.3 by Robert Collins
test and deliver basic pending-merges into bzr so that merging is recorded
26
    """Get a list of direct merges, from a list of direct and indirect
531.2.2 by Charlie Shepherd
Remove all trailing whitespace
27
147.1.3 by Robert Collins
test and deliver basic pending-merges into bzr so that merging is recorded
28
    :param merges: Iterator of merge patchlogs
147.1.26 by Robert Collins
be consistent about pybaz vs arch naming in the fai derived code
29
    :type merges: iter of `pybaz.Patchlog`
147.1.3 by Robert Collins
test and deliver basic pending-merges into bzr so that merging is recorded
30
    :return: The direct merges
147.1.26 by Robert Collins
be consistent about pybaz vs arch naming in the fai derived code
31
    :rtype: list of `pybaz.Patchlog`
147.1.3 by Robert Collins
test and deliver basic pending-merges into bzr so that merging is recorded
32
    """
147.4.7 by Robert Collins
use sets and strings to optimise finding indirect merges somewhat
33
    indirect = set()
147.1.3 by Robert Collins
test and deliver basic pending-merges into bzr so that merging is recorded
34
    logs = list(merges)
147.1.5 by Robert Collins
test and implement direct merge support of 2-in-a-row patches
35
    if not logs:
36
        return []
147.1.3 by Robert Collins
test and deliver basic pending-merges into bzr so that merging is recorded
37
    for log in logs:
147.4.4 by Robert Collins
when we encounter an obviously corrupt patchlog, work around it by using the archive.
38
        try:
531.2.2 by Charlie Shepherd
Remove all trailing whitespace
39
            this_indirect = set([str(f) for f in log.new_patches
40
                                 if f != log.revision and
147.4.7 by Robert Collins
use sets and strings to optimise finding indirect merges somewhat
41
                                     str(f) not in indirect])
147.4.4 by Robert Collins
when we encounter an obviously corrupt patchlog, work around it by using the archive.
42
        except pybaz.errors.NamespaceError:
43
            print
44
            print "log ", log, " unusable, attempting to use archive copy."
45
            log = pybaz.Revision(str(log.revision)).patchlog
531.2.2 by Charlie Shepherd
Remove all trailing whitespace
46
            this_indirect = set([str(f) for f in log.new_patches
47
                                 if f != log.revision and
147.4.7 by Robert Collins
use sets and strings to optimise finding indirect merges somewhat
48
                                     str(f) not in indirect])
49
        indirect.update(this_indirect)
147.1.7 by Robert Collins
handle inaccessible sibling archives somewhat - note version-0 is still not handled
50
        if log.continuation_of is not None:
51
            # continuations list everything in new_patches
52
            continue
53
        try:
54
            # ask baz if we can
55
            ancestor = log.revision.ancestor
56
        except pybaz.errors.ExecProblem:
57
            # baz does not know
58
            # guess
531.2.2 by Charlie Shepherd
Remove all trailing whitespace
59
            if log.revision.patchlevel != 'version-0':
147.1.9 by Robert Collins
determine version-0 ancestors from a tree when possible
60
                ancestor = namespace_previous(log.revision)
61
            else:
62
                found = False
63
                ancestor = None
64
                # ancestor might be in the tree
65
                for tree_log in pybaz.WorkingTree(log.tree).iter_logs(
66
                    log.revision.version, reverse=True):
67
                    if found:
68
                        ancestor = tree_log.revision
69
                        break
70
                    if tree_log.revision == log.revision:
71
                        found = True
72
                print "ancestor of %s is %s" % (log.revision, ancestor)
147.1.8 by Robert Collins
handle version-xxx and base-0 correctly in namespace_previous
73
        if ancestor is not None:
147.4.7 by Robert Collins
use sets and strings to optimise finding indirect merges somewhat
74
            indirect.add(str(ancestor))
75
    return [log.revision for log in logs if not str(log.revision) in indirect
76
            and log.revision not in excludes]
77
147.1.3 by Robert Collins
test and deliver basic pending-merges into bzr so that merging is recorded
78
147.1.7 by Robert Collins
handle inaccessible sibling archives somewhat - note version-0 is still not handled
79
def namespace_previous(revision):
147.1.8 by Robert Collins
handle version-xxx and base-0 correctly in namespace_previous
80
    if revision.patchlevel == 'base-0':
81
        return None
147.1.7 by Robert Collins
handle inaccessible sibling archives somewhat - note version-0 is still not handled
82
    if revision.patchlevel == 'patch-1':
83
        return revision.version['base-0']
84
    if revision.patchlevel.startswith('patch'):
85
        level = int(revision.patchlevel[len('patch-'):]) -1
86
        return revision.version['patch-%d' % level]
87
    if revision.patchlevel == 'version-0':
88
        raise RuntimeError("cannot determine prior namespace level for a "
147.1.9 by Robert Collins
determine version-0 ancestors from a tree when possible
89
                           "version-0 patch ('%s')" % revision)
147.1.29 by Robert Collins
update to latest bzr api
90
    if revision.patchlevel == 'versionfix-1':
147.1.7 by Robert Collins
handle inaccessible sibling archives somewhat - note version-0 is still not handled
91
        return revision.version['version-0']
147.1.29 by Robert Collins
update to latest bzr api
92
    if revision.patchlevel.startswith('versionfix'):
93
        level = int(revision.patchlevel[len('versionfix-'):]) -1
94
        return revision.version['versionfix-%d' % level]
147.1.8 by Robert Collins
handle version-xxx and base-0 correctly in namespace_previous
95
    raise NotImplementedError
147.1.3 by Robert Collins
test and deliver basic pending-merges into bzr so that merging is recorded
96
147.1.24 by Robert Collins
trim fai cribbage
97
def iter_new_merges(tree, version, reverse=False):
98
    """List patchlogs that are new in this tree since the last commit.
99
100
    :param tree: The working tree to calculate new revisions in
101
    :type tree: str
102
    :param version: The version to use when determining new logs
103
    :type version: str
104
    :param reverse: If true, list backwards, from newest to oldest
105
    :type reverse: bool
106
    :return: An iterator for new revision logs in this tree
147.1.26 by Robert Collins
be consistent about pybaz vs arch naming in the fai derived code
107
    :rtype: Iterator of `pybaz.Patchlog`
147.1.24 by Robert Collins
trim fai cribbage
108
    """
147.1.26 by Robert Collins
be consistent about pybaz vs arch naming in the fai derived code
109
    assert (isinstance(version, pybaz.Version))
147.1.24 by Robert Collins
trim fai cribbage
110
    for line in _iter_new_merges(tree, version.fullname, reverse):
147.1.26 by Robert Collins
be consistent about pybaz vs arch naming in the fai derived code
111
        yield pybaz.Patchlog(line, tree)
147.1.24 by Robert Collins
trim fai cribbage
112
113
def _iter_new_merges(directory, version, reverse):
114
    """List patchlogs that are new in this tree since the last commit.
115
116
    :param directory: The working tree to calculate new revisions in
117
    :type directory: str
118
    :param version: The version to use when determining new logs
119
    :type version: str
120
    :param reverse: If true, list backwards, from newest to oldest
121
    :type reverse: bool
122
    :return: An iterator for names of revisions new in this tree
123
    :rtype: Iterator of str
124
    """
125
    args = [ 'new-merges', '--dir', directory ]
531.2.2 by Charlie Shepherd
Remove all trailing whitespace
126
    if reverse:
147.1.24 by Robert Collins
trim fai cribbage
127
        args.append('--reverse')
128
    args.append(version)
129
    return sequence_cmd(args)