1
# Copyright (C) 2006 by Szilveszter Farkas (Phanatic) <szilveszter.farkas@gmail.com>
 
 
2
# Some parts of the code are:
 
 
3
# Copyright (C) 2005, 2006 by Canonical Ltd
 
 
5
# This program is free software; you can redistribute it and/or modify
 
 
6
# it under the terms of the GNU General Public License as published by
 
 
7
# the Free Software Foundation; either version 2 of the License, or
 
 
8
# (at your option) any later version.
 
 
10
# This program is distributed in the hope that it will be useful,
 
 
11
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
 
12
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
 
13
# GNU General Public License for more details.
 
 
15
# You should have received a copy of the GNU General Public License
 
 
16
# along with this program; if not, write to the Free Software
 
 
17
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
 
31
from bzrlib.missing import find_unmerged
 
 
33
def _repo_rel_url(repo_url, inner_url):
 
 
34
    """Return path with common prefix of repository path removed.
 
 
36
    If path is not part of the repository, the original path is returned.
 
 
37
    If path is equal to the repository, the current directory marker '.' is
 
 
39
    Otherwise, a relative path is returned, with trailing '/' stripped.
 
 
41
    inner_url = urlutils.normalize_url(inner_url)
 
 
42
    repo_url = urlutils.normalize_url(repo_url)
 
 
43
    if inner_url == repo_url:
 
 
45
    result = urlutils.relative_url(repo_url, inner_url)
 
 
46
    if result != inner_url:
 
 
47
        result = result.rstrip('/')
 
 
50
def get_location_info(repository, branch=None, working=None):
 
 
51
    """ Get known locations for working, branch and repository.
 
 
53
    :return: a dictionary containing the needed infos
 
 
56
    repository_path = repository.bzrdir.root_transport.base
 
 
57
    if working and branch:
 
 
58
        working_path = working.bzrdir.root_transport.base
 
 
59
        branch_path = branch.bzrdir.root_transport.base
 
 
60
        if working_path != branch_path:
 
 
61
            # lightweight checkout
 
 
62
            ret['lightcoroot'] = working_path
 
 
63
            if repository.is_shared():
 
 
64
                # lightweight checkout of branch in shared repository
 
 
65
                ret['sharedrepo'] = repository_path
 
 
66
                ret['repobranch'] = _repo_rel_url(repository_path, branch_path)
 
 
68
                # lightweight checkout of standalone branch
 
 
69
                ret['cobranch'] = branch_path
 
 
70
        elif repository.is_shared():
 
 
71
            # branch with tree inside shared repository
 
 
72
            ret['sharedrepo'] = repository_path
 
 
73
            ret['repoco'] = _repo_rel_url(repository_path, branch_path)
 
 
74
        elif branch.get_bound_location():
 
 
76
            ret['coroot'] = working_path
 
 
77
            ret['cobranch'] = branch.get_bound_location()
 
 
80
            ret['branchroot'] = working_path
 
 
82
        branch_path = branch.bzrdir.root_transport.base
 
 
83
        if repository.is_shared():
 
 
84
            # branch is part of shared repository
 
 
85
            ret['sharedrepo'] = repository_path
 
 
86
            ret['repobranch'] = _repo_rel_url(repository_path, branch_path)
 
 
89
            ret['branchroot'] = branch_path
 
 
92
        assert repository.is_shared()
 
 
93
        ret['sharedrepo'] = repository_path
 
 
97
def get_related_info(branch):
 
 
98
    """ Get parent and push location of branch.
 
 
100
    :return: a dictionary containing the needed infos
 
 
103
    if branch.get_parent() or branch.get_push_location():
 
 
104
        if branch.get_parent():
 
 
105
            ret['parentbranch'] = branch.get_parent()
 
 
106
        if branch.get_push_location():
 
 
107
            ret['publishbranch'] = branch.get_push_location()
 
 
112
def get_format_info(control=None, repository=None, branch=None, working=None):
 
 
113
    """ Get known formats for control, working, branch and repository.
 
 
115
    :return: a dictionary containing the needed infos
 
 
119
        ret['control'] = control._format.get_format_description()
 
 
121
        ret['workingtree'] = working._format.get_format_description()
 
 
123
        ret['branch'] = branch._format.get_format_description()
 
 
125
        ret['repository'] = repository._format.get_format_description()
 
 
130
def get_locking_info(repository, branch=None, working=None):
 
 
131
    """ Get locking status of working, branch and repository.
 
 
133
    :return: a dictionary containing the needed infos
 
 
136
    if (repository.get_physical_lock_status() or
 
 
137
        (branch and branch.get_physical_lock_status()) or
 
 
138
        (working and working.get_physical_lock_status())):
 
 
140
            if working.get_physical_lock_status():
 
 
144
            ret['workingtree'] = status
 
 
146
            if branch.get_physical_lock_status():
 
 
150
            ret['branch'] = status
 
 
152
            if repository.get_physical_lock_status():
 
 
156
            ret['repository'] = status
 
 
160
def get_missing_revisions_branch(branch):
 
 
161
    """ Get missing master revisions in branch.
 
 
163
    :return: a dictionary containing the needed infos
 
 
166
    # Try with inaccessible branch ?
 
 
167
    master = branch.get_master_branch()
 
 
169
        local_extra, remote_extra = find_unmerged(branch, master)
 
 
171
            ret = len(remote_extra)
 
 
176
def get_missing_revisions_working(working):
 
 
177
    """ Get missing revisions in working tree.
 
 
179
    :return: a dictionary containing the needed infos
 
 
181
    if (bzrlib.version_info[0] == 0) and (bzrlib.version_info[1] < 9):
 
 
182
        # function deprecated after 0.9
 
 
183
        from bzrlib.delta import compare_trees
 
 
186
    branch = working.branch
 
 
187
    basis = working.basis_tree()
 
 
189
    if (bzrlib.version_info[0] == 0) and (bzrlib.version_info[1] < 9):
 
 
190
        delta = compare_trees(basis, working, want_unchanged=True)
 
 
192
        delta = working.changes_from(basis, want_unchanged=True)
 
 
194
    history = branch.revision_history()
 
 
195
    tree_last_id = working.last_revision()
 
 
197
    if len(history) and tree_last_id != history[-1]:
 
 
198
        tree_last_revno = branch.revision_id_to_revno(tree_last_id)
 
 
199
        missing_count = len(history) - tree_last_revno
 
 
205
def get_working_stats(working):
 
 
206
    """ Get statistics about a working tree.
 
 
208
    :return: a dictionary containing the needed infos
 
 
210
    if (bzrlib.version_info[0] == 0) and (bzrlib.version_info[1] < 9):
 
 
211
        # function deprecated after 0.9
 
 
212
        from bzrlib.delta import compare_trees
 
 
215
    basis = working.basis_tree()
 
 
217
    if (bzrlib.version_info[0] == 0) and (bzrlib.version_info[1] < 9):
 
 
218
        delta = compare_trees(basis, working, want_unchanged=True)
 
 
220
        delta = working.changes_from(basis, want_unchanged=True)
 
 
222
    ret['unchanged'] = len(delta.unchanged)
 
 
223
    ret['modified'] = len(delta.modified)
 
 
224
    ret['added'] = len(delta.added)
 
 
225
    ret['removed'] = len(delta.removed)
 
 
226
    ret['renamed'] = len(delta.renamed)
 
 
228
    ignore_cnt = unknown_cnt = 0
 
 
229
    for path in working.extras():
 
 
230
        if working.is_ignored(path):
 
 
234
    ret['unknown'] = unknown_cnt
 
 
235
    ret['ignored'] = ignore_cnt
 
 
238
    for path, ie in working.iter_entries_by_dir():
 
 
239
        if ie.kind == 'directory':
 
 
241
    ret['subdirs'] = dir_cnt
 
 
245
def get_branch_stats(branch):
 
 
246
    """ Get statistics about a branch.
 
 
248
    :return: a dictionary containing the needed infos
 
 
251
    repository = branch.repository
 
 
252
    history = branch.revision_history()
 
 
258
        committers[repository.get_revision(rev).committer] = True
 
 
259
    ret['commiters'] = len(committers)
 
 
261
        firstrev = repository.get_revision(history[0])
 
 
262
        age = int((time.time() - firstrev.timestamp) / 3600 / 24)
 
 
264
        ret['firstrev'] = osutils.format_date(firstrev.timestamp,
 
 
267
        lastrev = repository.get_revision(history[-1])
 
 
268
        ret['lastrev'] = osutils.format_date(lastrev.timestamp,
 
 
273
def get_repository_stats(repository):
 
 
274
    """ Get statistics about a repository.
 
 
276
    :return: a dictionary containing the needed infos
 
 
279
    if repository.bzrdir.root_transport.listable():
 
 
280
        c, t = repository._revision_store.total_size(repository.get_transaction())
 
 
286
def diff_helper(tree, specific_files, external_diff_options, 
 
 
287
                    old_revision_spec=None, new_revision_spec=None,
 
 
288
                    old_label='a/', new_label='b/', output=None):
 
 
291
    :param tree: a WorkingTree
 
 
293
    :param specific_files: the specific files to compare, or None
 
 
295
    :param external_diff_options: if non-None, run an external diff, and pass it these options
 
 
297
    :param old_revision_spec: if None, use basis tree as old revision, otherwise use the tree for the specified revision. 
 
 
299
    :param new_revision_spec:  if None, use working tree as new revision, otherwise use the tree for the specified revision.
 
 
303
    from bzrlib.diff import show_diff_trees
 
 
309
        revision_id = spec.in_store(tree.branch).rev_id
 
 
310
        return tree.branch.repository.revision_tree(revision_id)
 
 
312
    if old_revision_spec is None:
 
 
313
        old_tree = tree.basis_tree()
 
 
315
        old_tree = spec_tree(old_revision_spec)
 
 
317
    if new_revision_spec is None:
 
 
320
        new_tree = spec_tree(new_revision_spec)
 
 
322
    return show_diff_trees(old_tree, new_tree, output, specific_files,
 
 
323
                           external_diff_options,
 
 
324
                           old_label=old_label, new_label=new_label)