~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
2
# <aaron.bentley@utoronto.ca>
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.1.3 by Robert Collins
test and deliver basic pending-merges into bzr so that merging is recorded
25
def direct_merges(merges):
26
    """Get a list of direct merges, from a list of direct and indirect
27
    
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
    """
33
    indirect = []
34
    direct = []
35
    logs = list(merges)
147.1.5 by Robert Collins
test and implement direct merge support of 2-in-a-row patches
36
    if not logs:
37
        return []
147.1.3 by Robert Collins
test and deliver basic pending-merges into bzr so that merging is recorded
38
    for log in logs:
147.4.4 by Robert Collins
when we encounter an obviously corrupt patchlog, work around it by using the archive.
39
        try:
40
            this_indirect = [f for f in log.new_patches if f != log.revision]
41
        except pybaz.errors.NamespaceError:
42
            print
43
            print "log ", log, " unusable, attempting to use archive copy."
44
            log = pybaz.Revision(str(log.revision)).patchlog
45
            this_indirect = [f for f in log.new_patches if f != log.revision]
46
        indirect.extend(this_indirect)
147.1.7 by Robert Collins
handle inaccessible sibling archives somewhat - note version-0 is still not handled
47
        if log.continuation_of is not None:
48
            # continuations list everything in new_patches
49
            continue
50
        try:
51
            # ask baz if we can
52
            ancestor = log.revision.ancestor
53
        except pybaz.errors.ExecProblem:
54
            # baz does not know
55
            # guess
147.1.9 by Robert Collins
determine version-0 ancestors from a tree when possible
56
            if log.revision.patchlevel != 'version-0': 
57
                ancestor = namespace_previous(log.revision)
58
            else:
59
                found = False
60
                ancestor = None
61
                # ancestor might be in the tree
62
                for tree_log in pybaz.WorkingTree(log.tree).iter_logs(
63
                    log.revision.version, reverse=True):
64
                    if found:
65
                        ancestor = tree_log.revision
66
                        break
67
                    if tree_log.revision == log.revision:
68
                        found = True
69
                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
70
        if ancestor is not None:
147.1.7 by Robert Collins
handle inaccessible sibling archives somewhat - note version-0 is still not handled
71
            indirect.append(ancestor)
147.1.3 by Robert Collins
test and deliver basic pending-merges into bzr so that merging is recorded
72
    return [log for log in logs if not log.revision in indirect]
73
147.1.7 by Robert Collins
handle inaccessible sibling archives somewhat - note version-0 is still not handled
74
def namespace_previous(revision):
147.1.8 by Robert Collins
handle version-xxx and base-0 correctly in namespace_previous
75
    if revision.patchlevel == 'base-0':
76
        return None
147.1.7 by Robert Collins
handle inaccessible sibling archives somewhat - note version-0 is still not handled
77
    if revision.patchlevel == 'patch-1':
78
        return revision.version['base-0']
79
    if revision.patchlevel.startswith('patch'):
80
        level = int(revision.patchlevel[len('patch-'):]) -1
81
        return revision.version['patch-%d' % level]
82
    if revision.patchlevel == 'version-0':
83
        raise RuntimeError("cannot determine prior namespace level for a "
147.1.9 by Robert Collins
determine version-0 ancestors from a tree when possible
84
                           "version-0 patch ('%s')" % revision)
147.1.29 by Robert Collins
update to latest bzr api
85
    if revision.patchlevel == 'versionfix-1':
147.1.7 by Robert Collins
handle inaccessible sibling archives somewhat - note version-0 is still not handled
86
        return revision.version['version-0']
147.1.29 by Robert Collins
update to latest bzr api
87
    if revision.patchlevel.startswith('versionfix'):
88
        level = int(revision.patchlevel[len('versionfix-'):]) -1
89
        return revision.version['versionfix-%d' % level]
147.1.8 by Robert Collins
handle version-xxx and base-0 correctly in namespace_previous
90
    raise NotImplementedError
147.1.3 by Robert Collins
test and deliver basic pending-merges into bzr so that merging is recorded
91
147.1.24 by Robert Collins
trim fai cribbage
92
def iter_new_merges(tree, version, reverse=False):
93
    """List patchlogs that are new in this tree since the last commit.
94
95
    :param tree: The working tree to calculate new revisions in
96
    :type tree: str
97
    :param version: The version to use when determining new logs
98
    :type version: str
99
    :param reverse: If true, list backwards, from newest to oldest
100
    :type reverse: bool
101
    :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
102
    :rtype: Iterator of `pybaz.Patchlog`
147.1.24 by Robert Collins
trim fai cribbage
103
    """
147.1.26 by Robert Collins
be consistent about pybaz vs arch naming in the fai derived code
104
    assert (isinstance(version, pybaz.Version))
147.1.24 by Robert Collins
trim fai cribbage
105
    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
106
        yield pybaz.Patchlog(line, tree)
147.1.24 by Robert Collins
trim fai cribbage
107
108
def _iter_new_merges(directory, version, reverse):
109
    """List patchlogs that are new in this tree since the last commit.
110
111
    :param directory: The working tree to calculate new revisions in
112
    :type directory: str
113
    :param version: The version to use when determining new logs
114
    :type version: str
115
    :param reverse: If true, list backwards, from newest to oldest
116
    :type reverse: bool
117
    :return: An iterator for names of revisions new in this tree
118
    :rtype: Iterator of str
119
    """
120
    args = [ 'new-merges', '--dir', directory ]
121
    if reverse: 
122
        args.append('--reverse')
123
    args.append(version)
124
    return sequence_cmd(args)