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
20
import bzrlib.errors as errors
22
from bzrlib.branch import Branch
23
from bzrlib.workingtree import WorkingTree
25
from bzrlib.errors import (NotBranchError, PermissionDenied, BzrError)
27
class DifferentBranchesError(BzrError):
28
""" Occurs if the specified files are in different branches
35
class PrefixFormatError(BzrError):
36
""" Occurs if the prefix is badly formatted
43
class RevisionValueError(BzrError):
44
""" Invalid revision value provided
51
def diff(revision=None, file_list=None, diff_options=None, prefix=None):
52
""" Save the diff into a temporary file.
54
:param revision: a list of revision numbers (one or two elements)
56
:param file_list: list of files you want to diff
58
:param diff_options: external diff options
60
:param prefix: 0 - p0, 1 - p1, or specify prefixes in the form of old/:new/
62
:return: path to the temporary file which contains the diff output (the frontend has to remove it!)
64
from tempfile import mkstemp
66
from bzrlib.builtins import internal_tree_files
67
from bzrlib.diff import show_diff_trees
68
from bzrlib.revisionspec import RevisionSpec_int
69
from bzrlib.workingtree import WorkingTree
71
from info_helper import diff_helper
73
if (prefix is None) or (prefix == '0'):
82
raise PrefixFormatError
83
old_label, new_label = prefix.split(":")
86
tree1, file_list = internal_tree_files(file_list)
90
except errors.FileInWrongBranch:
91
if len(file_list) != 2:
92
raise DifferentBranchesError
94
tree1, file1 = WorkingTree.open_containing(file_list[0])
95
tree2, file2 = WorkingTree.open_containing(file_list[1])
97
if file1 != "" or file2 != "":
98
raise DifferentBranchesError
102
tmpfile = mkstemp(prefix='olive_')
103
tmpfp = open(tmpfile[1], 'w')
105
if revision is not None:
106
if tree2 is not None:
107
raise RevisionValueError
109
if len(revision) >= 1:
110
revision[0] = RevisionSpec_int(revision[0])
111
if len(revision) == 2:
112
revision[1] = RevisionSpec_int(revision[1])
114
if (len(revision) == 1) or (revision[1].spec is None):
115
ret = diff_helper(tree1, file_list, diff_options,
117
old_label=old_label, new_label=new_label,
119
elif len(revision) == 2:
120
ret = diff_helper(tree1, file_list, diff_options,
121
revision[0], revision[1],
122
old_label=old_label, new_label=new_label,
125
raise RevisionValueError
127
if tree2 is not None:
128
ret = show_diff_trees(tree1, tree2, tmpfp,
129
specific_files=file_list,
130
external_diff_options=diff_options,
131
old_label=old_label, new_label=new_label)
133
ret = diff_helper(tree1, file_list, diff_options,
134
old_label=old_label, new_label=new_label,
144
def get_push_location(location):
145
""" Get the stored push location of a branch.
147
:param location: the path to the branch
149
:return: the stored location
151
from bzrlib.branch import Branch
154
branch = Branch.open_containing(location)[0]
155
except errors.NotBranchError:
156
raise NotBranchError(location)
160
return branch.get_push_location()
163
""" Get info about branch, working tree, and repository
165
:param location: the location of the branch/working tree/repository
167
:return: the information in dictionary format
169
The following informations are delivered (if available):
170
ret['location']['lightcoroot']: Light checkout root
171
ret['location']['sharedrepo']: Shared repository
172
ret['location']['repobranch']: Repository branch
173
ret['location']['cobranch']: Checkout of branch
174
ret['location']['repoco']: Repository checkout
175
ret['location']['coroot']: Checkout root
176
ret['location']['branchroot']: Branch root
177
ret['related']['parentbranch']: Parent branch
178
ret['related']['publishbranch']: Publish to branch
179
ret['format']['control']: Control format
180
ret['format']['workingtree']: Working tree format
181
ret['format']['branch']: Branch format
182
ret['format']['repository']: Repository format
183
ret['locking']['workingtree']: Working tree lock status
184
ret['locking']['branch']: Branch lock status
185
ret['locking']['repository']: Repository lock status
186
ret['missing']['branch']: Missing revisions in branch
187
ret['missing']['workingtree']: Missing revisions in working tree
188
ret['wtstats']['unchanged']: Unchanged files
189
ret['wtstats']['modified']: Modified files
190
ret['wtstats']['added']: Added files
191
ret['wtstats']['removed']: Removed files
192
ret['wtstats']['renamed']: Renamed files
193
ret['wtstats']['unknown']: Unknown files
194
ret['wtstats']['ignored']: Ingnored files
195
ret['wtstats']['subdirs']: Versioned subdirectories
196
ret['brstats']['revno']: Revisions in branch
197
ret['brstats']['commiters']: Number of commiters
198
ret['brstats']['age']: Age of branch in days
199
ret['brstats']['firstrev']: Time of first revision
200
ret['brstats']['lastrev']: Time of last revision
201
ret['repstats']['revisions']: Revisions in repository
202
ret['repstats']['size']: Size of repository in bytes
204
import bzrlib.bzrdir as bzrdir
210
a_bzrdir = bzrdir.BzrDir.open_containing(location)[0]
211
except errors.NotBranchError:
212
raise NotBranchError(location)
215
working = a_bzrdir.open_workingtree()
218
branch = working.branch
219
repository = branch.repository
220
control = working.bzrdir
222
ret['location'] = info_helper.get_location_info(repository, branch, working)
223
ret['related'] = info_helper.get_related_info(branch)
224
ret['format'] = info_helper.get_format_info(control, repository, branch, working)
225
ret['locking'] = info_helper.get_locking_info(repository, branch, working)
227
ret['missing']['branch'] = info_helper.get_missing_revisions_branch(branch)
228
ret['missing']['workingtree'] = info_helper.get_missing_revisions_working(working)
229
ret['wtstats'] = info_helper.get_working_stats(working)
230
ret['brstats'] = info_helper.get_branch_stats(branch)
231
ret['repstats'] = info_helper.get_repository_stats(repository)
236
except (errors.NoWorkingTree, errors.NotLocalUrl):
240
branch = a_bzrdir.open_branch()
243
ret['location'] = info_helper.get_location_info(repository, branch)
244
ret['related'] = info_helper.get_related_info(branch)
245
ret['format'] = info_helper.get_format_info(control, repository, branch)
246
ret['locking'] = info_helper.get_locking_info(repository, branch)
247
ret['missing']['branch'] = info_helper.get_missing_revisions_branch(branch)
248
ret['brstats'] = info_helper.get_branch_stats(branch)
249
ret['repstats'] = info_helper.get_repository_stats(repository)
254
except errors.NotBranchError:
258
repository = a_bzrdir.open_repository()
259
repository.lock_read()
261
ret['location'] = info_helper.get_location_info(repository)
262
ret['format'] = info_helper.get_format_info(control, repository)
263
ret['locking'] = info_helper.get_locking_info(repository)
264
ret['repstats'] = info_helper.get_repository_stats(repository)
269
except errors.NoRepositoryPresent:
272
def is_branch(location):
273
""" Check if the location is a branch.
275
:param location: the location you want to check
277
:return: True or False respectively
280
branch = Branch.open_containing(location)[0]
281
except errors.NotBranchError:
283
except errors.PermissionDenied:
284
raise PermissionDenied(location)
289
def is_checkout(location):
290
""" Check if the location is a checkout.
292
:param location: the location you want to check
294
:return: True or False respectively
297
branch = Branch.open_containing(location)[0]
298
except errors.NotBranchError:
302
working = WorkingTree.open_containing(location)[0]
306
working_path = working.bzrdir.root_transport.base
307
branch_path = branch.bzrdir.root_transport.base
309
if working_path != branch_path:
310
# lightweight checkout
312
elif branch.get_bound_location():
318
def log(location, timezone='original', verbose=False, show_ids=False,
319
forward=False, revision=None, log_format=None, message=None,
320
long=False, short=False, line=False):
321
""" Print log into a temporary file.
323
:param location: location of local/remote branch or file
325
:param timzone: requested timezone
327
:param verbose: verbose output
331
:param forward: if True, start from the earliest entry
333
:param revision: revision range as a list ([from, to])
335
:param log_format: line, short, long
337
:param message: show revisions whose message matches this regexp
339
:param long: long log format
341
:param short: short log format
343
:param line: line log format
345
:return: full path to the temporary file containing the log (the frontend has to remove it!)
347
from tempfile import mkstemp
349
from bzrlib import bzrdir
350
from bzrlib.builtins import get_log_format
351
from bzrlib.log import log_formatter, show_log
352
from bzrlib.revisionspec import RevisionSpec_int
354
assert message is None or isinstance(message, basestring), \
355
"invalid message argument %r" % message
356
direction = (forward and 'forward') or 'reverse'
361
# find the file id to log:
362
dir, fp = bzrdir.BzrDir.open_containing(location)
363
b = dir.open_branch()
367
inv = dir.open_workingtree().inventory
368
except (errors.NotBranchError, errors.NotLocalUrl):
369
# either no tree, or is remote.
370
inv = b.basis_tree().inventory
371
file_id = inv.path2id(fp)
373
if revision is not None:
374
if len(revision) >= 1:
375
revision[0] = RevisionSpec_int(revision[0])
376
if len(revision) == 2:
377
revision[1] = RevisionSpec_int(revision[1])
382
elif len(revision) == 1:
383
rev1 = rev2 = revision[0].in_history(b).revno
384
elif len(revision) == 2:
385
if revision[0].spec is None:
386
# missing begin-range means first revision
389
rev1 = revision[0].in_history(b).revno
391
if revision[1].spec is None:
392
# missing end-range means last known revision
395
rev2 = revision[1].in_history(b).revno
397
raise RevisionValueError
399
# By this point, the revision numbers are converted to the +ve
400
# form if they were supplied in the -ve form, so we can do
401
# this comparison in relative safety
403
(rev2, rev1) = (rev1, rev2)
405
if (log_format == None):
406
default = b.get_config().log_format()
407
log_format = get_log_format(long=long, short=short, line=line,
410
tmpfile = mkstemp(prefix='olive_')
411
tmpfp = open(tmpfile[1], 'w')
413
lf = log_formatter(log_format,
416
show_timezone=timezone)
430
def nick(branch, nickname=None):
431
""" Get or set nickname.
433
:param branch: path to the branch
435
:param nickname: if specified, the nickname will be set
440
branch = Branch.open_containing(branch)[0]
441
except errors.NotBranchError:
444
if nickname is not None:
445
branch.nick = nickname
450
""" Get current revision number for specified branch
452
:param branch: path to the branch
454
:return: revision number
457
revno = Branch.open_containing(branch)[0].revno()
458
except errors.NotBranchError:
464
""" Get version information from bzr
466
:return: bzrlib version
468
return bzrlib.__version__
470
def whoami(branch=None, email=False):
471
""" Get user's data (name and email address)
473
:param branch: if specified, the user's data will be looked up in the branch's config
475
:param email: if True, only the email address will be returned
477
:return: user info (only email address if email is True)
479
from bzrlib.workingtree import WorkingTree
481
if branch is not None:
483
b = WorkingTree.open_containing(u'.')[0].branch
484
config = bzrlib.config.BranchConfig(b)
485
except NotBranchError:
486
config = bzrlib.config.GlobalConfig()
488
config = bzrlib.config.GlobalConfig()
491
return config.user_email()
493
return config.username()