32
34
from bzrlib.errors import (BzrError, BzrCheckError, BzrCommandError,
33
35
NotBranchError, DivergedBranches, NotConflicted,
34
36
NoSuchFile, NoWorkingTree, FileInWrongBranch,
35
NotVersionedError, BadBundle)
37
NotVersionedError, NotABundle)
36
38
from bzrlib.log import show_one_log
37
39
from bzrlib.merge import Merge3Merger
38
40
from bzrlib.option import Option
39
42
from bzrlib.progress import DummyProgress, ProgressPhase
40
43
from bzrlib.revision import common_ancestor
41
44
from bzrlib.revisionspec import RevisionSpec
43
46
from bzrlib.trace import mutter, note, log_error, warning, is_quiet
44
47
from bzrlib.transport.local import LocalTransport
49
import bzrlib.urlutils as urlutils
46
50
from bzrlib.workingtree import WorkingTree
152
156
takes_args = ['file*']
153
157
takes_options = ['all', 'show-ids', 'revision']
154
158
aliases = ['st', 'stat']
160
encoding_type = 'replace'
157
163
def run(self, all=False, show_ids=False, file_list=None, revision=None):
158
tree, file_list = tree_files(file_list)
160
164
from bzrlib.status import show_tree_status
166
tree, file_list = tree_files(file_list)
161
168
show_tree_status(tree, show_unchanged=all, show_ids=show_ids,
162
specific_files=file_list, revision=revision)
169
specific_files=file_list, revision=revision,
165
173
class cmd_cat_revision(Command):
173
181
takes_args = ['revision_id?']
174
182
takes_options = ['revision']
183
# cat-revision is more for frontends so should be exact
177
187
def run(self, revision_id=None, revision=None):
181
191
if revision_id is None and revision is None:
182
192
raise BzrCommandError('You must supply either --revision or a revision_id')
183
193
b = WorkingTree.open_containing(u'.')[0].branch
195
# TODO: jam 20060112 should cat-revision always output utf-8?
184
196
if revision_id is not None:
185
sys.stdout.write(b.repository.get_revision_xml(revision_id))
197
self.outf.write(b.repository.get_revision_xml(revision_id).decode('utf-8'))
186
198
elif revision is not None:
187
199
for rev in revision:
189
201
raise BzrCommandError('You cannot specify a NULL revision.')
190
202
revno, rev_id = rev.in_history(b)
191
sys.stdout.write(b.repository.get_revision_xml(rev_id))
203
self.outf.write(b.repository.get_revision_xml(rev_id).decode('utf-8'))
194
206
class cmd_revno(Command):
195
207
"""Show current revision number.
197
This is equal to the number of revisions on this branch."""
209
This is equal to the number of revisions on this branch.
198
212
takes_args = ['location?']
200
215
def run(self, location=u'.'):
201
print Branch.open_containing(location)[0].revno()
216
self.outf.write(str(Branch.open_containing(location)[0].revno()))
217
self.outf.write('\n')
204
220
class cmd_revision_info(Command):
258
275
takes_args = ['file*']
259
276
takes_options = ['no-recurse', 'dry-run', 'verbose']
277
encoding_type = 'replace'
261
279
def run(self, file_list, no_recurse=False, dry_run=False, verbose=False):
262
280
import bzrlib.add
266
# This is pointless, but I'd rather not raise an error
267
action = bzrlib.add.add_action_null
269
action = bzrlib.add.add_action_print
271
action = bzrlib.add.add_action_add
273
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()))
275
285
added, ignored = bzrlib.add.smart_add(file_list, not no_recurse,
277
287
if len(ignored) > 0:
279
289
for glob in sorted(ignored.keys()):
280
290
for path in ignored[glob]:
281
print "ignored %s matching \"%s\"" % (path, glob)
291
self.outf.write("ignored %s matching \"%s\"\n"
284
295
for glob, paths in ignored.items():
285
296
match_len += len(paths)
286
print "ignored %d file(s)." % match_len
287
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")
291
302
class cmd_mkdir(Command):
294
305
This is equivalent to creating the directory and then adding it.
296
308
takes_args = ['dir+']
309
encoding_type = 'replace'
298
311
def run(self, dir_list):
299
312
for d in dir_list:
301
314
wt, dd = WorkingTree.open_containing(d)
316
self.outf.write('added %s\n' % d)
306
319
class cmd_relpath(Command):
307
320
"""Show path of a file relative to root"""
308
322
takes_args = ['filename']
312
326
def run(self, filename):
327
# TODO: jam 20050106 Can relpath return a munged path if
328
# sys.stdout encoding cannot represent it?
313
329
tree, relpath = WorkingTree.open_containing(filename)
330
self.outf.write(relpath)
331
self.outf.write('\n')
317
334
class cmd_inventory(Command):
359
378
Files cannot be moved between branches.
361
381
takes_args = ['names*']
362
382
aliases = ['move', 'rename']
383
encoding_type = 'replace'
364
385
def run(self, names_list):
365
386
if len(names_list) < 2:
369
390
if os.path.isdir(names_list[-1]):
370
391
# move into existing directory
371
392
for pair in tree.move(rel_names[:-1], rel_names[-1]):
372
print "%s => %s" % pair
393
self.outf.write("%s => %s\n" % pair)
374
395
if len(names_list) != 2:
375
396
raise BzrCommandError('to mv multiple files the destination '
376
397
'must be a versioned directory')
377
398
tree.rename_one(rel_names[0], rel_names[1])
378
print "%s => %s" % (rel_names[0], rel_names[1])
399
self.outf.write("%s => %s\n" % (rel_names[0], rel_names[1]))
381
402
class cmd_pull(Command):
400
421
that, you can omit the location to use the default. To change the
401
422
default, use --remember.
403
425
takes_options = ['remember', 'overwrite', 'revision', 'verbose']
404
426
takes_args = ['location?']
427
encoding_type = 'replace'
406
429
def run(self, location=None, remember=False, overwrite=False, revision=None, verbose=False):
407
430
# FIXME: too much stuff is in the command class
410
433
branch_to = tree_to.branch
411
434
except NoWorkingTree:
413
branch_to = Branch.open_containing(u'.')[0]
436
branch_to = Branch.open_containing(u'.')[0]
414
437
stored_loc = branch_to.get_parent()
415
438
if location is None:
416
439
if stored_loc is None:
417
440
raise BzrCommandError("No pull location known or specified.")
419
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)
420
445
location = stored_loc
447
branch_from = Branch.open(location)
422
449
if branch_to.get_parent() is None or remember:
423
branch_to.set_parent(location)
425
branch_from = Branch.open(location)
450
branch_to.set_parent(branch_from.base)
427
452
if revision is None:
443
468
if old_rh != new_rh:
444
469
# Something changed
445
470
from bzrlib.log import show_changed_revisions
446
show_changed_revisions(branch_to, old_rh, new_rh)
471
show_changed_revisions(branch_to, old_rh, new_rh,
449
475
class cmd_push(Command):
470
496
After that, you can omit the location to use the default. To change the
471
497
default, use --remember.
473
takes_options = ['remember', 'overwrite',
500
takes_options = ['remember', 'overwrite', 'verbose',
474
501
Option('create-prefix',
475
502
help='Create the path leading up to the branch '
476
503
'if it does not already exist')]
477
504
takes_args = ['location?']
505
encoding_type = 'replace'
479
507
def run(self, location=None, remember=False, overwrite=False,
480
508
create_prefix=False, verbose=False):
488
516
if stored_loc is None:
489
517
raise BzrCommandError("No push location known or specified.")
491
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)
492
522
location = stored_loc
524
transport = get_transport(location)
525
location_url = transport.base
493
526
if br_from.get_push_location() is None or remember:
494
br_from.set_push_location(location)
527
br_from.set_push_location(location_url)
496
dir_to = bzrlib.bzrdir.BzrDir.open(location)
531
dir_to = bzrlib.bzrdir.BzrDir.open(location_url)
497
532
br_to = dir_to.open_branch()
498
533
except NotBranchError:
499
534
# create a branch.
500
transport = get_transport(location).clone('..')
535
transport = transport.clone('..')
501
536
if not create_prefix:
503
transport.mkdir(transport.relpath(location))
538
relurl = transport.relpath(location_url)
539
mutter('creating directory %s => %s', location_url, relurl)
540
transport.mkdir(relurl)
504
541
except NoSuchFile:
505
542
raise BzrCommandError("Parent directory of %s "
506
543
"does not exist." % location)
508
545
current = transport.base
509
needed = [(transport, transport.relpath(location))]
546
needed = [(transport, transport.relpath(location_url))]
512
549
transport, relpath = needed[-1]
519
556
if new_transport.base == transport.base:
520
557
raise BzrCommandError("Could not create "
522
dir_to = br_from.bzrdir.clone(location,
559
dir_to = br_from.bzrdir.clone(location_url,
523
560
revision_id=br_from.last_revision())
524
561
br_to = dir_to.open_branch()
525
562
count = len(br_to.revision_history())
546
583
if old_rh != new_rh:
547
584
# Something changed
548
585
from bzrlib.log import show_changed_revisions
549
show_changed_revisions(br_to, old_rh, new_rh)
586
show_changed_revisions(br_to, old_rh, new_rh,
552
590
class cmd_branch(Command):
567
605
aliases = ['get', 'clone']
569
607
def run(self, from_location, to_location=None, revision=None, basis=None):
608
from bzrlib.transport import get_transport
570
609
from bzrlib.osutils import rmtree
571
610
if revision is None:
572
611
revision = [None]
601
640
name = os.path.basename(to_location) + '\n'
642
to_transport = get_transport(to_location)
603
os.mkdir(to_location)
605
if e.errno == errno.EEXIST:
606
raise BzrCommandError('Target directory "%s" already'
607
' exists.' % to_location)
608
if e.errno == errno.ENOENT:
609
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.' %
614
652
# preserve whatever source format we have.
615
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)
616
655
branch = dir.open_branch()
617
656
except bzrlib.errors.NoSuchRevision:
657
to_transport.delete_tree('.')
619
658
msg = "The branch %s has no revision %s." % (from_location, revision[0])
620
659
raise BzrCommandError(msg)
621
660
except bzrlib.errors.UnlistableBranch:
725
763
renames = list(bzrlib.tree.find_renames(old_inv, new_inv))
727
765
for old_name, new_name in renames:
728
print "%s => %s" % (old_name, new_name)
766
self.outf.write("%s => %s\n" % (old_name, new_name))
731
769
class cmd_update(Command):
794
832
takes_args = ['file*']
795
833
takes_options = ['verbose', Option('new', help='remove newly-added files')]
835
encoding_type = 'replace'
798
837
def run(self, file_list, verbose=False, new=False):
799
838
tree, file_list = tree_files(file_list)
808
847
file_list = sorted([f[0] for f in added[0]], reverse=True)
809
848
if len(file_list) == 0:
810
849
raise BzrCommandError('No matching files.')
811
tree.remove(file_list, verbose=verbose)
850
tree.remove(file_list, verbose=verbose, to_file=self.outf)
814
853
class cmd_file_id(Command):
828
869
raise BzrError("%r is not a versioned file" % filename)
871
self.outf.write(i + '\n')
833
874
class cmd_file_path(Command):
834
875
"""Print path of file_ids to a file or directory.
836
877
This prints one line for each directory down to the target,
837
starting at the branch root."""
878
starting at the branch root.
839
882
takes_args = ['filename']
841
885
def run(self, filename):
842
886
tree, relpath = WorkingTree.open_containing(filename)
877
921
class cmd_revision_history(Command):
878
922
"""Display list of revision ids on this branch."""
882
927
branch = WorkingTree.open_containing(u'.')[0].branch
883
928
for patchid in branch.revision_history():
929
self.outf.write(patchid)
930
self.outf.write('\n')
887
933
class cmd_ancestry(Command):
888
934
"""List all revisions merged into this branch."""
892
939
tree = WorkingTree.open_containing(u'.')[0]
1027
1074
takes_args = ['file*']
1028
1075
takes_options = ['revision', 'diff-options', 'prefix']
1029
1076
aliases = ['di', 'dif']
1077
encoding_type = 'exact'
1031
1079
@display_command
1032
1080
def run(self, revision=None, file_list=None, diff_options=None,
1093
1141
# directories with readdir, rather than stating each one. Same
1094
1142
# level of effort but possibly much less IO. (Or possibly not,
1095
1143
# if the directories are very large...)
1144
takes_options = ['show-ids']
1096
1146
@display_command
1097
1147
def run(self, show_ids=False):
1098
1148
tree = WorkingTree.open_containing(u'.')[0]
1099
1149
old = tree.basis_tree()
1100
1150
for path, ie in old.inventory.iter_entries():
1101
1151
if not tree.has_id(ie.file_id):
1152
self.outf.write(path)
1103
print '%-50s %s' % (path, ie.file_id)
1154
self.outf.write(' ')
1155
self.outf.write(ie.file_id)
1156
self.outf.write('\n')
1108
1159
class cmd_modified(Command):
1116
1167
td = compare_trees(tree.basis_tree(), tree)
1118
1169
for path, id, kind, text_modified, meta_modified in td.modified:
1170
self.outf.write(path + '\n')
1123
1173
class cmd_added(Command):
1136
1186
path = inv.id2path(file_id)
1137
1187
if not os.access(bzrlib.osutils.abspath(path), os.F_OK):
1189
self.outf.write(path + '\n')
1143
1192
class cmd_root(Command):
1144
1193
"""Show the tree root directory.
1150
1199
def run(self, filename=None):
1151
1200
"""Print the branch root."""
1152
1201
tree = WorkingTree.open_containing(filename)[0]
1202
self.outf.write(tree.basedir + '\n')
1156
1205
class cmd_log(Command):
1198
1249
from bzrlib.log import log_formatter, show_log
1200
1250
assert message is None or isinstance(message, basestring), \
1201
1251
"invalid message argument %r" % message
1202
1252
direction = (forward and 'forward') or 'reverse'
1248
1298
if rev1 > rev2:
1249
1299
(rev2, rev1) = (rev1, rev2)
1251
mutter('encoding log as %r', bzrlib.user_encoding)
1253
# use 'replace' so that we don't abort if trying to write out
1254
# in e.g. the default C locale.
1255
outf = codecs.getwriter(bzrlib.user_encoding)(sys.stdout, errors='replace')
1257
1301
if (log_format == None):
1258
1302
default = bzrlib.config.BranchConfig(b).log_format()
1259
1303
log_format = get_log_format(long=long, short=short, line=line, default=default)
1261
1304
lf = log_formatter(log_format,
1262
1305
show_ids=show_ids,
1264
1307
show_timezone=timezone)
1287
1330
class cmd_touching_revisions(Command):
1288
1331
"""Return revision-ids which affected a particular file.
1290
A more user-friendly interface is "bzr log FILE"."""
1333
A more user-friendly interface is "bzr log FILE".
1292
1337
takes_args = ["filename"]
1293
1339
@display_command
1294
1340
def run(self, filename):
1295
1341
tree, relpath = WorkingTree.open_containing(filename)
1297
1343
inv = tree.read_working_inventory()
1298
1344
file_id = inv.path2id(relpath)
1299
1345
for revno, revision_id, what in bzrlib.log.find_touching_revisions(b, file_id):
1300
print "%6d %s" % (revno, what)
1346
self.outf.write("%6d %s\n" % (revno, what))
1303
1349
class cmd_ls(Command):
1336
1382
if revision is not None:
1337
1383
tree = tree.branch.repository.revision_tree(
1338
1384
revision[0].in_history(tree.branch).rev_id)
1339
1386
for fp, fc, kind, fid, entry in tree.list_files():
1340
1387
if fp.startswith(relpath):
1341
1388
fp = fp[len(relpath):]
1347
1394
kindch = entry.kind_character()
1348
print '%-8s %s%s' % (fc, fp, kindch)
1395
self.outf.write('%-8s %s%s\n' % (fc, fp, kindch))
1350
sys.stdout.write(fp)
1351
sys.stdout.write('\0')
1397
self.outf.write(fp + '\0')
1400
self.outf.write(fp + '\n')
1357
1403
class cmd_unknowns(Command):
1583
1629
from bzrlib.msgeditor import edit_commit_message, \
1584
1630
make_commit_message_template
1585
1631
from tempfile import TemporaryFile
1588
1633
# TODO: Need a blackbox test for invoking the external editor; may be
1589
1634
# slightly problematic to run this cross-platform.
2009
2053
if e.errno not in (errno.ENOENT, errno.EISDIR):
2014
2058
if reader is not None:
2015
2059
conflicts = merge_bundle(reader, tree, not force, merge_type,
2022
stored_loc = tree.branch.get_parent()
2024
if stored_loc is None:
2025
raise BzrCommandError("No merge branch known or specified.")
2027
print "Using saved branch: %s" % stored_loc
2030
if tree.branch.get_parent() is None or remember:
2031
tree.branch.set_parent(branch)
2066
branch = self._get_remembered_parent(tree, branch, 'Merging from')
2033
2068
if revision is None or len(revision) < 1:
2034
2069
base = [None, None]
2045
2080
if None in revision:
2046
2081
raise BzrCommandError(
2047
2082
"Merge doesn't permit that revision specifier.")
2048
b, path = Branch.open_containing(branch)
2050
base = [branch, revision[0].in_history(b).revno]
2051
other = [branch, revision[1].in_history(b).revno]
2083
other_branch, path = Branch.open_containing(branch)
2085
base = [branch, revision[0].in_history(other_branch).revno]
2086
other = [branch, revision[1].in_history(other_branch).revno]
2088
if tree.branch.get_parent() is None or remember:
2089
tree.branch.set_parent(other_branch.base)
2053
2092
interesting_files = [path]
2076
2115
"and (if you want) report this to the bzr developers\n")
2118
# TODO: move up to common parent; this isn't merge-specific anymore.
2119
def _get_remembered_parent(self, tree, supplied_location, verb_string):
2120
"""Use tree.branch's parent if none was supplied.
2122
Report if the remembered location was used.
2124
if supplied_location is not None:
2125
return supplied_location
2126
stored_location = tree.branch.get_parent()
2127
mutter("%s", stored_location)
2128
if stored_location is None:
2129
raise BzrCommandError("No location specified or remembered")
2130
display_url = urlutils.unescape_for_display(stored_location, self.outf.encoding)
2131
self.outf.write("%s remembered location %s\n" % (verb_string, display_url))
2132
return stored_location
2080
2135
class cmd_remerge(Command):
2081
2136
"""Redo a merge.