17
17
"""builtin bzr commands"""
23
from shutil import rmtree
25
27
import bzrlib.branch
26
28
from bzrlib.branch import Branch
27
29
import bzrlib.bzrdir as bzrdir
30
from bzrlib.bundle.read_bundle import BundleReader
31
from bzrlib.bundle.apply_bundle import merge_bundle
28
32
from bzrlib.commands import Command, display_command
29
33
import bzrlib.errors as errors
30
34
from bzrlib.errors import (BzrError, BzrCheckError, BzrCommandError,
31
35
NotBranchError, DivergedBranches, NotConflicted,
32
36
NoSuchFile, NoWorkingTree, FileInWrongBranch,
37
NotVersionedError, NotABundle)
34
38
from bzrlib.log import show_one_log
35
39
from bzrlib.merge import Merge3Merger
36
40
from bzrlib.option import Option
37
42
from bzrlib.progress import DummyProgress, ProgressPhase
38
43
from bzrlib.revision import common_ancestor
39
44
from bzrlib.revisionspec import RevisionSpec
41
46
from bzrlib.trace import mutter, note, log_error, warning, is_quiet
42
47
from bzrlib.transport.local import LocalTransport
49
import bzrlib.urlutils as urlutils
44
50
from bzrlib.workingtree import WorkingTree
150
156
takes_args = ['file*']
151
157
takes_options = ['all', 'show-ids', 'revision']
152
158
aliases = ['st', 'stat']
160
encoding_type = 'replace'
155
163
def run(self, all=False, show_ids=False, file_list=None, revision=None):
156
tree, file_list = tree_files(file_list)
158
164
from bzrlib.status import show_tree_status
166
tree, file_list = tree_files(file_list)
159
168
show_tree_status(tree, show_unchanged=all, show_ids=show_ids,
160
specific_files=file_list, revision=revision)
169
specific_files=file_list, revision=revision,
163
173
class cmd_cat_revision(Command):
171
181
takes_args = ['revision_id?']
172
182
takes_options = ['revision']
183
# cat-revision is more for frontends so should be exact
175
187
def run(self, revision_id=None, revision=None):
179
191
if revision_id is None and revision is None:
180
192
raise BzrCommandError('You must supply either --revision or a revision_id')
181
193
b = WorkingTree.open_containing(u'.')[0].branch
195
# TODO: jam 20060112 should cat-revision always output utf-8?
182
196
if revision_id is not None:
183
sys.stdout.write(b.repository.get_revision_xml(revision_id))
197
self.outf.write(b.repository.get_revision_xml(revision_id).decode('utf-8'))
184
198
elif revision is not None:
185
199
for rev in revision:
187
201
raise BzrCommandError('You cannot specify a NULL revision.')
188
202
revno, rev_id = rev.in_history(b)
189
sys.stdout.write(b.repository.get_revision_xml(rev_id))
203
self.outf.write(b.repository.get_revision_xml(rev_id).decode('utf-8'))
192
206
class cmd_revno(Command):
193
207
"""Show current revision number.
195
This is equal to the number of revisions on this branch."""
209
This is equal to the number of revisions on this branch.
196
212
takes_args = ['location?']
198
215
def run(self, location=u'.'):
199
print Branch.open_containing(location)[0].revno()
216
self.outf.write(str(Branch.open_containing(location)[0].revno()))
217
self.outf.write('\n')
202
220
class cmd_revision_info(Command):
256
275
takes_args = ['file*']
257
276
takes_options = ['no-recurse', 'dry-run', 'verbose']
277
encoding_type = 'replace'
259
279
def run(self, file_list, no_recurse=False, dry_run=False, verbose=False):
260
280
import bzrlib.add
264
# This is pointless, but I'd rather not raise an error
265
action = bzrlib.add.add_action_null
267
action = bzrlib.add.add_action_print
269
action = bzrlib.add.add_action_add
271
action = bzrlib.add.add_action_add_and_print
282
action = bzrlib.add.AddAction(to_file=self.outf,
283
should_add=(not dry_run), should_print=(not is_quiet()))
273
285
added, ignored = bzrlib.add.smart_add(file_list, not no_recurse,
275
287
if len(ignored) > 0:
277
289
for glob in sorted(ignored.keys()):
278
290
for path in ignored[glob]:
279
print "ignored %s matching \"%s\"" % (path, glob)
291
self.outf.write("ignored %s matching \"%s\"\n"
282
295
for glob, paths in ignored.items():
283
296
match_len += len(paths)
284
print "ignored %d file(s)." % match_len
285
print "If you wish to add some of these files, please add them"\
297
self.outf.write("ignored %d file(s).\n" % match_len)
298
self.outf.write("If you wish to add some of these files,"
299
" please add them by name.\n")
289
302
class cmd_mkdir(Command):
292
305
This is equivalent to creating the directory and then adding it.
294
308
takes_args = ['dir+']
309
encoding_type = 'replace'
296
311
def run(self, dir_list):
297
312
for d in dir_list:
299
314
wt, dd = WorkingTree.open_containing(d)
316
self.outf.write('added %s\n' % d)
304
319
class cmd_relpath(Command):
305
320
"""Show path of a file relative to root"""
306
322
takes_args = ['filename']
310
326
def run(self, filename):
327
# TODO: jam 20050106 Can relpath return a munged path if
328
# sys.stdout encoding cannot represent it?
311
329
tree, relpath = WorkingTree.open_containing(filename)
330
self.outf.write(relpath)
331
self.outf.write('\n')
315
334
class cmd_inventory(Command):
357
378
Files cannot be moved between branches.
359
381
takes_args = ['names*']
360
382
aliases = ['move', 'rename']
383
encoding_type = 'replace'
362
385
def run(self, names_list):
363
386
if len(names_list) < 2:
367
390
if os.path.isdir(names_list[-1]):
368
391
# move into existing directory
369
392
for pair in tree.move(rel_names[:-1], rel_names[-1]):
370
print "%s => %s" % pair
393
self.outf.write("%s => %s\n" % pair)
372
395
if len(names_list) != 2:
373
396
raise BzrCommandError('to mv multiple files the destination '
374
397
'must be a versioned directory')
375
398
tree.rename_one(rel_names[0], rel_names[1])
376
print "%s => %s" % (rel_names[0], rel_names[1])
399
self.outf.write("%s => %s\n" % (rel_names[0], rel_names[1]))
379
402
class cmd_pull(Command):
398
421
that, you can omit the location to use the default. To change the
399
422
default, use --remember.
401
425
takes_options = ['remember', 'overwrite', 'revision', 'verbose']
402
426
takes_args = ['location?']
427
encoding_type = 'replace'
404
429
def run(self, location=None, remember=False, overwrite=False, revision=None, verbose=False):
405
430
# FIXME: too much stuff is in the command class
408
433
branch_to = tree_to.branch
409
434
except NoWorkingTree:
411
branch_to = Branch.open_containing(u'.')[0]
436
branch_to = Branch.open_containing(u'.')[0]
412
437
stored_loc = branch_to.get_parent()
413
438
if location is None:
414
439
if stored_loc is None:
415
440
raise BzrCommandError("No pull location known or specified.")
417
print "Using saved location: %s" % stored_loc
442
display_url = urlutils.unescape_for_display(stored_loc,
444
self.outf.write("Using saved location: %s\n" % display_url)
418
445
location = stored_loc
447
branch_from = Branch.open(location)
420
449
if branch_to.get_parent() is None or remember:
421
branch_to.set_parent(location)
423
branch_from = Branch.open(location)
450
branch_to.set_parent(branch_from.base)
425
452
if revision is None:
441
468
if old_rh != new_rh:
442
469
# Something changed
443
470
from bzrlib.log import show_changed_revisions
444
show_changed_revisions(branch_to, old_rh, new_rh)
471
show_changed_revisions(branch_to, old_rh, new_rh,
447
475
class cmd_push(Command):
468
496
After that, you can omit the location to use the default. To change the
469
497
default, use --remember.
471
takes_options = ['remember', 'overwrite',
500
takes_options = ['remember', 'overwrite', 'verbose',
472
501
Option('create-prefix',
473
502
help='Create the path leading up to the branch '
474
503
'if it does not already exist')]
475
504
takes_args = ['location?']
505
encoding_type = 'replace'
477
507
def run(self, location=None, remember=False, overwrite=False,
478
508
create_prefix=False, verbose=False):
486
516
if stored_loc is None:
487
517
raise BzrCommandError("No push location known or specified.")
489
print "Using saved location: %s" % stored_loc
519
display_url = urlutils.unescape_for_display(stored_loc,
521
self.outf.write("Using saved location: %s" % display_url)
490
522
location = stored_loc
524
transport = get_transport(location)
525
location_url = transport.base
491
526
if br_from.get_push_location() is None or remember:
492
br_from.set_push_location(location)
527
br_from.set_push_location(location_url)
494
dir_to = bzrlib.bzrdir.BzrDir.open(location)
531
dir_to = bzrlib.bzrdir.BzrDir.open(location_url)
495
532
br_to = dir_to.open_branch()
496
533
except NotBranchError:
497
534
# create a branch.
498
transport = get_transport(location).clone('..')
535
transport = transport.clone('..')
499
536
if not create_prefix:
501
transport.mkdir(transport.relpath(location))
538
relurl = transport.relpath(location_url)
539
mutter('creating directory %s => %s', location_url, relurl)
540
transport.mkdir(relurl)
502
541
except NoSuchFile:
503
542
raise BzrCommandError("Parent directory of %s "
504
543
"does not exist." % location)
506
545
current = transport.base
507
needed = [(transport, transport.relpath(location))]
546
needed = [(transport, transport.relpath(location_url))]
510
549
transport, relpath = needed[-1]
517
556
if new_transport.base == transport.base:
518
557
raise BzrCommandError("Could not create "
520
dir_to = br_from.bzrdir.clone(location,
559
dir_to = br_from.bzrdir.clone(location_url,
521
560
revision_id=br_from.last_revision())
522
561
br_to = dir_to.open_branch()
523
562
count = len(br_to.revision_history())
544
583
if old_rh != new_rh:
545
584
# Something changed
546
585
from bzrlib.log import show_changed_revisions
547
show_changed_revisions(br_to, old_rh, new_rh)
586
show_changed_revisions(br_to, old_rh, new_rh,
550
590
class cmd_branch(Command):
565
605
aliases = ['get', 'clone']
567
607
def run(self, from_location, to_location=None, revision=None, basis=None):
608
from bzrlib.transport import get_transport
568
609
from bzrlib.osutils import rmtree
569
610
if revision is None:
570
611
revision = [None]
599
640
name = os.path.basename(to_location) + '\n'
642
to_transport = get_transport(to_location)
601
os.mkdir(to_location)
603
if e.errno == errno.EEXIST:
604
raise BzrCommandError('Target directory "%s" already'
605
' exists.' % to_location)
606
if e.errno == errno.ENOENT:
607
raise BzrCommandError('Parent of "%s" does not exist.' %
644
to_transport.mkdir('.')
645
except bzrlib.errors.FileExists:
646
raise BzrCommandError('Target directory "%s" already'
647
' exists.' % to_location)
648
except bzrlib.errors.NoSuchFile:
649
raise BzrCommandError('Parent of "%s" does not exist.' %
612
652
# preserve whatever source format we have.
613
dir = br_from.bzrdir.sprout(to_location, revision_id, basis_dir)
653
dir = br_from.bzrdir.sprout(to_transport.base,
654
revision_id, basis_dir)
614
655
branch = dir.open_branch()
615
656
except bzrlib.errors.NoSuchRevision:
657
to_transport.delete_tree('.')
617
658
msg = "The branch %s has no revision %s." % (from_location, revision[0])
618
659
raise BzrCommandError(msg)
619
660
except bzrlib.errors.UnlistableBranch:
733
773
renames = list(bzrlib.tree.find_renames(old_inv, new_inv))
735
775
for old_name, new_name in renames:
736
print "%s => %s" % (old_name, new_name)
776
self.outf.write("%s => %s\n" % (old_name, new_name))
739
779
class cmd_update(Command):
794
834
This makes bzr stop tracking changes to a versioned file. It does
795
835
not delete the working copy.
837
You can specify one or more files, and/or --new. If you specify --new,
838
only 'added' files will be removed. If you specify both, then new files
839
in the specified directories will be removed. If the directories are
840
also new, they will also be removed.
797
takes_args = ['file+']
798
takes_options = ['verbose']
842
takes_args = ['file*']
843
takes_options = ['verbose', Option('new', help='remove newly-added files')]
845
encoding_type = 'replace'
801
def run(self, file_list, verbose=False):
847
def run(self, file_list, verbose=False, new=False):
802
848
tree, file_list = tree_files(file_list)
803
tree.remove(file_list, verbose=verbose)
850
if file_list is None:
851
raise BzrCommandError('Specify one or more files to remove, or'
854
from bzrlib.delta import compare_trees
855
added = [compare_trees(tree.basis_tree(), tree,
856
specific_files=file_list).added]
857
file_list = sorted([f[0] for f in added[0]], reverse=True)
858
if len(file_list) == 0:
859
raise BzrCommandError('No matching files.')
860
tree.remove(file_list, verbose=verbose, to_file=self.outf)
806
863
class cmd_file_id(Command):
820
879
raise BzrError("%r is not a versioned file" % filename)
881
self.outf.write(i + '\n')
825
884
class cmd_file_path(Command):
826
885
"""Print path of file_ids to a file or directory.
828
887
This prints one line for each directory down to the target,
829
starting at the branch root."""
888
starting at the branch root.
831
892
takes_args = ['filename']
833
895
def run(self, filename):
834
896
tree, relpath = WorkingTree.open_containing(filename)
869
931
class cmd_revision_history(Command):
870
932
"""Display list of revision ids on this branch."""
874
937
branch = WorkingTree.open_containing(u'.')[0].branch
875
938
for patchid in branch.revision_history():
939
self.outf.write(patchid)
940
self.outf.write('\n')
879
943
class cmd_ancestry(Command):
880
944
"""List all revisions merged into this branch."""
884
949
tree = WorkingTree.open_containing(u'.')[0]
1019
1084
takes_args = ['file*']
1020
1085
takes_options = ['revision', 'diff-options', 'prefix']
1021
1086
aliases = ['di', 'dif']
1087
encoding_type = 'exact'
1023
1089
@display_command
1024
1090
def run(self, revision=None, file_list=None, diff_options=None,
1085
1151
# directories with readdir, rather than stating each one. Same
1086
1152
# level of effort but possibly much less IO. (Or possibly not,
1087
1153
# if the directories are very large...)
1154
takes_options = ['show-ids']
1088
1156
@display_command
1089
1157
def run(self, show_ids=False):
1090
1158
tree = WorkingTree.open_containing(u'.')[0]
1091
1159
old = tree.basis_tree()
1092
1160
for path, ie in old.inventory.iter_entries():
1093
1161
if not tree.has_id(ie.file_id):
1162
self.outf.write(path)
1095
print '%-50s %s' % (path, ie.file_id)
1164
self.outf.write(' ')
1165
self.outf.write(ie.file_id)
1166
self.outf.write('\n')
1100
1169
class cmd_modified(Command):
1108
1177
td = compare_trees(tree.basis_tree(), tree)
1110
1179
for path, id, kind, text_modified, meta_modified in td.modified:
1180
self.outf.write(path + '\n')
1115
1183
class cmd_added(Command):
1126
1194
path = inv.id2path(file_id)
1127
1195
if not os.access(bzrlib.osutils.abspath(path), os.F_OK):
1197
self.outf.write(path + '\n')
1133
1200
class cmd_root(Command):
1134
1201
"""Show the tree root directory.
1140
1207
def run(self, filename=None):
1141
1208
"""Print the branch root."""
1142
1209
tree = WorkingTree.open_containing(filename)[0]
1210
self.outf.write(tree.basedir + '\n')
1146
1213
class cmd_log(Command):
1188
1257
from bzrlib.log import log_formatter, show_log
1190
1258
assert message is None or isinstance(message, basestring), \
1191
1259
"invalid message argument %r" % message
1192
1260
direction = (forward and 'forward') or 'reverse'
1238
1306
if rev1 > rev2:
1239
1307
(rev2, rev1) = (rev1, rev2)
1241
mutter('encoding log as %r', bzrlib.user_encoding)
1243
# use 'replace' so that we don't abort if trying to write out
1244
# in e.g. the default C locale.
1245
outf = codecs.getwriter(bzrlib.user_encoding)(sys.stdout, errors='replace')
1247
1309
if (log_format == None):
1248
1310
default = bzrlib.config.BranchConfig(b).log_format()
1249
1311
log_format = get_log_format(long=long, short=short, line=line, default=default)
1251
1312
lf = log_formatter(log_format,
1252
1313
show_ids=show_ids,
1254
1315
show_timezone=timezone)
1277
1338
class cmd_touching_revisions(Command):
1278
1339
"""Return revision-ids which affected a particular file.
1280
A more user-friendly interface is "bzr log FILE"."""
1341
A more user-friendly interface is "bzr log FILE".
1282
1345
takes_args = ["filename"]
1283
1347
@display_command
1284
1348
def run(self, filename):
1285
1349
tree, relpath = WorkingTree.open_containing(filename)
1287
1351
inv = tree.read_working_inventory()
1288
1352
file_id = inv.path2id(relpath)
1289
1353
for revno, revision_id, what in bzrlib.log.find_touching_revisions(b, file_id):
1290
print "%6d %s" % (revno, what)
1354
self.outf.write("%6d %s\n" % (revno, what))
1293
1357
class cmd_ls(Command):
1326
1390
if revision is not None:
1327
1391
tree = tree.branch.repository.revision_tree(
1328
1392
revision[0].in_history(tree.branch).rev_id)
1329
1394
for fp, fc, kind, fid, entry in tree.list_files():
1330
1395
if fp.startswith(relpath):
1331
1396
fp = fp[len(relpath):]
1337
1402
kindch = entry.kind_character()
1338
print '%-8s %s%s' % (fc, fp, kindch)
1403
self.outf.write('%-8s %s%s\n' % (fc, fp, kindch))
1340
sys.stdout.write(fp)
1341
sys.stdout.write('\0')
1405
self.outf.write(fp + '\0')
1408
self.outf.write(fp + '\n')
1347
1411
class cmd_unknowns(Command):
1573
1637
from bzrlib.msgeditor import edit_commit_message, \
1574
1638
make_commit_message_template
1575
1639
from tempfile import TemporaryFile
1578
1641
# TODO: Need a blackbox test for invoking the external editor; may be
1579
1642
# slightly problematic to run this cross-platform.
1858
1920
print " nick: %s" % (branch.nick,)
1860
1922
print " revid: %s" % (rh[-1],)
1923
print "Using python interpreter:", sys.executable
1925
print "Using python standard library:", os.path.dirname(site.__file__)
1926
print "Using bzrlib:",
1927
if len(bzrlib.__path__) > 1:
1928
# print repr, which is a good enough way of making it clear it's
1929
# more than one element (eg ['/foo/bar', '/foo/bzr'])
1930
print repr(bzrlib.__path__)
1932
print bzrlib.__path__[0]
1861
1935
print bzrlib.__copyright__
1862
1936
print "http://bazaar-vcs.org/"
1977
2051
merge_type = Merge3Merger
1979
2053
tree = WorkingTree.open_containing(u'.')[0]
1980
stored_loc = tree.branch.get_parent()
1982
if stored_loc is None:
1983
raise BzrCommandError("No merge branch known or specified.")
1985
print "Using saved branch: %s" % stored_loc
1988
if tree.branch.get_parent() is None or remember:
1989
tree.branch.set_parent(branch)
2056
if branch is not None:
2057
reader = BundleReader(file(branch, 'rb'))
2061
if e.errno not in (errno.ENOENT, errno.EISDIR):
2066
if reader is not None:
2067
conflicts = merge_bundle(reader, tree, not force, merge_type,
2068
reprocess, show_base)
2074
branch = self._get_remembered_parent(tree, branch, 'Merging from')
1991
2076
if revision is None or len(revision) < 1:
1992
2077
base = [None, None]
2003
2088
if None in revision:
2004
2089
raise BzrCommandError(
2005
2090
"Merge doesn't permit that revision specifier.")
2006
b, path = Branch.open_containing(branch)
2008
base = [branch, revision[0].in_history(b).revno]
2009
other = [branch, revision[1].in_history(b).revno]
2091
other_branch, path = Branch.open_containing(branch)
2093
base = [branch, revision[0].in_history(other_branch).revno]
2094
other = [branch, revision[1].in_history(other_branch).revno]
2096
if tree.branch.get_parent() is None or remember:
2097
tree.branch.set_parent(other_branch.base)
2011
2100
interesting_files = [path]
2034
2123
"and (if you want) report this to the bzr developers\n")
2126
# TODO: move up to common parent; this isn't merge-specific anymore.
2127
def _get_remembered_parent(self, tree, supplied_location, verb_string):
2128
"""Use tree.branch's parent if none was supplied.
2130
Report if the remembered location was used.
2132
if supplied_location is not None:
2133
return supplied_location
2134
stored_location = tree.branch.get_parent()
2135
mutter("%s", stored_location)
2136
if stored_location is None:
2137
raise BzrCommandError("No location specified or remembered")
2138
display_url = urlutils.unescape_for_display(stored_location, self.outf.encoding)
2139
self.outf.write("%s remembered location %s\n" % (verb_string, display_url))
2140
return stored_location
2038
2143
class cmd_remerge(Command):
2039
2144
"""Redo a merge.
2457
2562
--dry-run will go through all the motions, but not actually
2458
2563
remove anything.
2460
In the future, uncommit will create a changeset, which can then
2565
In the future, uncommit will create a revision bundle, which can then
2617
2722
# aliases. ideally we would avoid loading the implementation until the
2618
2723
# details were needed.
2619
2724
from bzrlib.conflicts import cmd_resolve, cmd_conflicts, restore
2725
from bzrlib.bundle.commands import cmd_bundle_revisions
2620
2726
from bzrlib.sign_my_commits import cmd_sign_my_commits
2621
2727
from bzrlib.weave_commands import cmd_weave_list, cmd_weave_join, \
2622
2728
cmd_weave_plan_merge, cmd_weave_merge_text