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
32
from bzrlib.diff import show_diff_trees
33
from bzrlib.missing import find_unmerged
35
def _repo_rel_url(repo_url, inner_url):
36
"""Return path with common prefix of repository path removed.
38
If path is not part of the repository, the original path is returned.
39
If path is equal to the repository, the current directory marker '.' is
41
Otherwise, a relative path is returned, with trailing '/' stripped.
43
inner_url = urlutils.normalize_url(inner_url)
44
repo_url = urlutils.normalize_url(repo_url)
45
if inner_url == repo_url:
47
result = urlutils.relative_url(repo_url, inner_url)
48
if result != inner_url:
49
result = result.rstrip('/')
52
def get_location_info(repository, branch=None, working=None):
53
""" Get known locations for working, branch and repository.
55
:return: a dictionary containing the needed infos
58
repository_path = repository.bzrdir.root_transport.base
59
if working and branch:
60
working_path = working.bzrdir.root_transport.base
61
branch_path = branch.bzrdir.root_transport.base
62
if working_path != branch_path:
63
# lightweight checkout
64
ret['lightcoroot'] = working_path
65
if repository.is_shared():
66
# lightweight checkout of branch in shared repository
67
ret['sharedrepo'] = repository_path
68
ret['repobranch'] = _repo_rel_url(repository_path, branch_path)
70
# lightweight checkout of standalone branch
71
ret['cobranch'] = branch_path
72
elif repository.is_shared():
73
# branch with tree inside shared repository
74
ret['sharedrepo'] = repository_path
75
ret['repoco'] = _repo_rel_url(repository_path, branch_path)
76
elif branch.get_bound_location():
78
ret['coroot'] = working_path
79
ret['cobranch'] = branch.get_bound_location()
82
ret['branchroot'] = working_path
84
branch_path = branch.bzrdir.root_transport.base
85
if repository.is_shared():
86
# branch is part of shared repository
87
ret['sharedrepo'] = repository_path
88
ret['repobranch'] = _repo_rel_url(repository_path, branch_path)
91
ret['branchroot'] = branch_path
94
assert repository.is_shared()
95
ret['sharedrepo'] = repository_path
99
def get_related_info(branch):
100
""" Get parent and push location of branch.
102
:return: a dictionary containing the needed infos
105
if branch.get_parent() or branch.get_push_location():
106
if branch.get_parent():
107
ret['parentbranch'] = branch.get_parent()
108
if branch.get_push_location():
109
ret['publishbranch'] = branch.get_push_location()
114
def get_format_info(control=None, repository=None, branch=None, working=None):
115
""" Get known formats for control, working, branch and repository.
117
:return: a dictionary containing the needed infos
121
ret['control'] = control._format.get_format_description()
123
ret['workingtree'] = working._format.get_format_description()
125
ret['branch'] = branch._format.get_format_description()
127
ret['repository'] = repository._format.get_format_description()
132
def get_locking_info(repository, branch=None, working=None):
133
""" Get locking status of working, branch and repository.
135
:return: a dictionary containing the needed infos
138
if (repository.get_physical_lock_status() or
139
(branch and branch.get_physical_lock_status()) or
140
(working and working.get_physical_lock_status())):
142
if working.get_physical_lock_status():
146
ret['workingtree'] = status
148
if branch.get_physical_lock_status():
152
ret['branch'] = status
154
if repository.get_physical_lock_status():
158
ret['repository'] = status
162
def get_missing_revisions_branch(branch):
163
""" Get missing master revisions in branch.
165
:return: a dictionary containing the needed infos
168
# Try with inaccessible branch ?
169
master = branch.get_master_branch()
171
local_extra, remote_extra = find_unmerged(branch, master)
173
ret = len(remote_extra)
178
def get_missing_revisions_working(working):
179
""" Get missing revisions in working tree.
181
:return: a dictionary containing the needed infos
183
if (bzrlib.version_info[0] == 0) and (bzrlib.version_info[1] < 9):
184
# function deprecated after 0.9
185
from bzrlib.delta import compare_trees
188
branch = working.branch
189
basis = working.basis_tree()
191
if (bzrlib.version_info[0] == 0) and (bzrlib.version_info[1] < 9):
192
delta = compare_trees(basis, working, want_unchanged=True)
194
delta = working.changes_from(basis, want_unchanged=True)
196
history = branch.revision_history()
197
tree_last_id = working.last_revision()
199
if len(history) and tree_last_id != history[-1]:
200
tree_last_revno = branch.revision_id_to_revno(tree_last_id)
201
missing_count = len(history) - tree_last_revno
207
def get_working_stats(working):
208
""" Get statistics about a working tree.
210
:return: a dictionary containing the needed infos
212
if (bzrlib.version_info[0] == 0) and (bzrlib.version_info[1] < 9):
213
# function deprecated after 0.9
214
from bzrlib.delta import compare_trees
217
basis = working.basis_tree()
219
if (bzrlib.version_info[0] == 0) and (bzrlib.version_info[1] < 9):
220
delta = compare_trees(basis, working, want_unchanged=True)
222
delta = working.changes_from(basis, want_unchanged=True)
224
ret['unchanged'] = len(delta.unchanged)
225
ret['modified'] = len(delta.modified)
226
ret['added'] = len(delta.added)
227
ret['removed'] = len(delta.removed)
228
ret['renamed'] = len(delta.renamed)
230
ignore_cnt = unknown_cnt = 0
231
for path in working.extras():
232
if working.is_ignored(path):
236
ret['unknown'] = unknown_cnt
237
ret['ignored'] = ignore_cnt
240
for path, ie in working.iter_entries_by_dir():
241
if ie.kind == 'directory':
243
ret['subdirs'] = dir_cnt
247
def get_branch_stats(branch):
248
""" Get statistics about a branch.
250
:return: a dictionary containing the needed infos
253
repository = branch.repository
254
history = branch.revision_history()
260
committers[repository.get_revision(rev).committer] = True
261
ret['commiters'] = len(committers)
263
firstrev = repository.get_revision(history[0])
264
age = int((time.time() - firstrev.timestamp) / 3600 / 24)
265
ret['age'] = '%d days'%age
266
ret['firstrev'] = osutils.format_date(firstrev.timestamp,
269
lastrev = repository.get_revision(history[-1])
270
ret['lastrev'] = osutils.format_date(lastrev.timestamp,
275
def get_repository_stats(repository):
276
""" Get statistics about a repository.
278
:return: a dictionary containing the needed infos
281
if repository.bzrdir.root_transport.listable():
282
c, t = repository._revision_store.total_size(repository.get_transaction())
284
ret['size'] = '%d KiB'%t
288
def diff_helper(tree, specific_files, external_diff_options,
289
old_revision_spec=None, new_revision_spec=None,
290
old_label='a/', new_label='b/', output=None):
293
:param tree: a WorkingTree
295
:param specific_files: the specific files to compare, or None
297
:param external_diff_options: if non-None, run an external diff, and pass it these options
299
:param old_revision_spec: if None, use basis tree as old revision, otherwise use the tree for the specified revision.
301
:param new_revision_spec: if None, use working tree as new revision, otherwise use the tree for the specified revision.
307
if old_revision_spec is None:
308
old_tree = tree.basis_tree()
310
old_tree = spec_tree(old_revision_spec)
312
if new_revision_spec is None:
315
new_tree = spec_tree(new_revision_spec)
317
return show_diff_trees(old_tree, new_tree, output, specific_files,
318
external_diff_options,
319
old_label=old_label, new_label=new_label)
322
revision_id = spec.in_store(tree.branch).rev_id
323
return tree.branch.repository.revision_tree(revision_id)