/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
0.436.169 by Jelmer Vernooij
Add 'pseudonyms' command.
1
# Copyright (C) 2009 by Jelmer Vernooij <jelmer@samba.org>
0.436.177 by Jelmer Vernooij
Remove trailing whitespace.
2
#
0.436.169 by Jelmer Vernooij
Add 'pseudonyms' command.
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
6
# (at your option) any later version.
7
#
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.
12
#
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
17
"""Revision pseudonyms."""
18
19
from collections import defaultdict
0.436.174 by Jelmer Vernooij
Support git-svn-id.
20
import urllib
0.436.169 by Jelmer Vernooij
Add 'pseudonyms' command.
21
22
from bzrlib import (
23
    errors,
24
    foreign,
25
    ui,
26
    )
27
28
0.436.174 by Jelmer Vernooij
Support git-svn-id.
29
def parse_git_svn_id(text):
0.436.221 by Jelmer Vernooij
Add deb-md5 support in pseudonyms.
30
    """Parse a git svn id string.
31
32
    :param text: git svn id
33
    :return: URL, revision number, uuid
34
    """
0.436.174 by Jelmer Vernooij
Support git-svn-id.
35
    (head, uuid) = text.rsplit(" ", 1)
36
    (full_url, rev) = head.rsplit("@", 1)
0.436.175 by Jelmer Vernooij
Cache repo root for svn URLs.
37
    return (full_url.encode("utf-8"), int(rev), uuid.encode("utf-8"))
38
39
40
class SubversionBranchUrlFinder(object):
41
42
    def __init__(self):
43
        self._roots = defaultdict(set)
44
45
    def find_root(self, uuid, url):
46
        for root in self._roots[uuid]:
47
            if url.startswith(root):
48
                return root
49
        try:
50
            from subvertpy.ra import RemoteAccess
51
        except ImportError:
52
            return None
53
        c = RemoteAccess(url)
54
        root = c.get_repos_root()
55
        self._roots[uuid].add(root)
56
        return root
57
58
    def find_branch_path(self, uuid, url):
59
        root = self.find_root(uuid, url)
60
        if root is None:
61
            return None
62
        assert url.startswith(root)
63
        return url[len(root):].strip("/")
64
65
66
svn_branch_path_finder = SubversionBranchUrlFinder()
0.436.174 by Jelmer Vernooij
Support git-svn-id.
67
68
0.436.184 by Jelmer Vernooij
split up pseudonyms function.
69
def _extract_converted_from_revid(rev):
70
    if not "converted-from" in rev.properties:
71
        return
72
73
    for line in rev.properties.get("converted-from", "").splitlines():
74
        (kind, serialized_foreign_revid) = line.split(" ", 1)
75
        yield (kind, serialized_foreign_revid)
76
77
78
def _extract_cscvs(rev):
79
    """Older-style launchpad-cscvs import."""
80
    if not "cscvs-svn-branch-path" in rev.properties:
81
        return
82
    yield ("svn", "%s:%s:%s" % (
83
         rev.properties["cscvs-svn-repository-uuid"],
84
         rev.properties["cscvs-svn-revision-number"],
85
         urllib.quote(rev.properties["cscvs-svn-branch-path"].strip("/"))))
86
87
88
def _extract_git_svn_id(rev):
89
    if not "git-svn-id" in rev.properties:
90
        return
91
    (full_url, revnum, uuid) = parse_git_svn_id(rev.properties['git-svn-id'])
92
    branch_path = svn_branch_path_finder.find_branch_path(uuid, full_url)
93
    if branch_path is not None:
94
        yield ("svn", "%s:%d:%s" % (uuid, revnum, urllib.quote(branch_path)))
95
0.436.186 by Jelmer Vernooij
Add test for cscvs foreign revids
96
0.436.184 by Jelmer Vernooij
split up pseudonyms function.
97
def _extract_foreign_revision(rev):
0.436.169 by Jelmer Vernooij
Add 'pseudonyms' command.
98
    # Perhaps 'rev' is a foreign revision ?
99
    if getattr(rev, "foreign_revid", None) is not None:
0.436.184 by Jelmer Vernooij
split up pseudonyms function.
100
        yield ("svn", rev.mapping.vcs.serialize_foreign_revid(rev.foreign_revid))
101
102
103
def _extract_foreign_revid(rev):
0.436.169 by Jelmer Vernooij
Add 'pseudonyms' command.
104
    # Try parsing the revision id
105
    try:
106
        foreign_revid, mapping = \
107
            foreign.foreign_vcs_registry.parse_revision_id(rev.revision_id)
108
    except errors.InvalidRevisionId:
109
        pass
110
    else:
0.436.184 by Jelmer Vernooij
split up pseudonyms function.
111
        yield (mapping.vcs.abbreviation,
112
            mapping.vcs.serialize_foreign_revid(foreign_revid))
113
114
0.436.221 by Jelmer Vernooij
Add deb-md5 support in pseudonyms.
115
def _extract_debian_md5sum(rev):
116
    if 'deb-md5' in rev.properties:
117
        yield ("debian-md5sum", rev.properties["deb-md5"])
118
0.436.184 by Jelmer Vernooij
split up pseudonyms function.
119
120
_foreign_revid_extractors = [
121
    _extract_converted_from_revid,
122
    _extract_cscvs,
123
    _extract_git_svn_id,
124
    _extract_foreign_revision,
125
    _extract_foreign_revid,
0.436.221 by Jelmer Vernooij
Add deb-md5 support in pseudonyms.
126
    _extract_debian_md5sum,
0.436.184 by Jelmer Vernooij
split up pseudonyms function.
127
    ]
128
129
130
def extract_foreign_revids(rev):
131
    """Find ids of semi-equivalent revisions in foreign VCS'es.
132
133
    :param: Bazaar revision object
134
    :return: Set with semi-equivalent revisions.
135
    """
136
    ret = set()
137
    for extractor in _foreign_revid_extractors:
138
        ret.update(extractor(rev))
0.436.169 by Jelmer Vernooij
Add 'pseudonyms' command.
139
    return ret
140
141
142
def find_pseudonyms(repository, revids):
143
    """Find revisions that are pseudonyms of each other.
144
145
    :param repository: Repository object
146
    :param revids: Sequence of revision ids to check
147
    :return: Iterable over sets of pseudonyms
148
    """
149
    # Where have foreign revids ended up?
150
    conversions = defaultdict(set)
151
    # What are native revids conversions of?
152
    conversion_of = defaultdict(set)
153
    revs = repository.get_revisions(revids)
154
    pb = ui.ui_factory.nested_progress_bar()
155
    try:
156
        for i, rev in enumerate(revs):
157
            pb.update("finding pseudonyms", i, len(revs))
158
            for foreign_revid in extract_foreign_revids(rev):
159
                conversion_of[rev.revision_id].add(foreign_revid)
160
                conversions[foreign_revid].add(rev.revision_id)
161
    finally:
162
        pb.finished()
163
    done = set()
164
    for foreign_revid in conversions.keys():
165
        ret = set()
166
        check = set(conversions[foreign_revid])
167
        while check:
168
            x = check.pop()
169
            extra = set()
170
            for frevid in conversion_of[x]:
171
                extra.update(conversions[frevid])
172
                del conversions[frevid]
173
            del conversion_of[x]
174
            check.update(extra)
175
            ret.add(x)
176
        if len(ret) > 1:
177
            yield ret
0.436.170 by Jelmer Vernooij
Add convenience function for creating a pseudonym dictionary.
178
179
180
def pseudonyms_as_dict(l):
181
    """Convert an iterable over pseudonyms to a dictionary.
182
183
    :param l: Iterable over sets of pseudonyms
184
    :return: Dictionary with pseudonyms for each revid.
185
    """
186
    ret = {}
187
    for pns in l:
188
        for pn in pns:
189
            ret[pn] = pns - set([pn])
190
    return ret
0.436.172 by Jelmer Vernooij
Split up code for generating rebase map.
191
192
193
def generate_rebase_map_from_pseudonyms(pseudonym_dict, existing, desired):
194
    """Create a rebase map from pseudonyms and existing/desired ancestry.
195
0.436.189 by Jelmer Vernooij
Fix formatting.
196
    :param pseudonym_dict: Dictionary with pseudonym as returned by
197
        pseudonyms_as_dict()
0.436.172 by Jelmer Vernooij
Split up code for generating rebase map.
198
    :param existing: Existing ancestry, might need to be rebased
199
    :param desired: Desired ancestry
200
    :return: rebase map, as dictionary
201
    """
202
    rebase_map = {}
203
    for revid in existing:
204
        for pn in pseudonym_dict.get(revid, []):
205
            if pn in desired:
206
                rebase_map[revid] = pn
207
    return rebase_map