19
import sys, os, time, os.path
22
23
from bzrlib.trace import mutter, note, log_error
23
24
from bzrlib.errors import bailout, BzrError, BzrCheckError, BzrCommandError
24
from bzrlib.osutils import quotefn
25
from bzrlib import Branch, Inventory, InventoryEntry, BZRDIR, \
25
from bzrlib.osutils import quotefn, pumpfile, isdir, isfile
26
from bzrlib.tree import RevisionTree, EmptyTree, WorkingTree, Tree
27
from bzrlib.revision import Revision
28
from bzrlib import Branch, Inventory, InventoryEntry, ScratchBranch, BZRDIR, \
34
37
assert cmd.startswith("cmd_")
35
38
return cmd[4:].replace('_','-')
37
def _parse_revision_str(revstr):
38
"""This handles a revision string -> revno.
40
There are several possibilities:
43
'234:345' -> [234, 345]
47
In the future we will also support:
48
'uuid:blah-blah-blah' -> ?
49
'hash:blahblahblah' -> ?
53
if revstr.find(':') != -1:
54
revs = revstr.split(':')
56
raise ValueError('More than 2 pieces not supported for --revision: %r' % revstr)
61
revs[0] = int(revs[0])
66
revs[1] = int(revs[1])
71
40
def get_all_cmds():
72
41
"""Return canonical name and class for all registered commands."""
73
42
for k, v in globals().iteritems():
221
189
class cmd_status(Command):
222
190
"""Display status summary.
224
This reports on versioned and unknown files, reporting them
225
grouped by state. Possible states are:
228
Versioned in the working copy but not in the previous revision.
231
Versioned in the previous revision but removed or deleted
235
Path of this file changed from the previous revision;
236
the text may also have changed. This includes files whose
237
parent directory was renamed.
240
Text has changed since the previous revision.
243
Nothing about this file has changed since the previous revision.
244
Only shown with --all.
247
Not versioned and not matching an ignore pattern.
249
To see ignored files use 'bzr ignored'. For details in the
250
changes to file texts, use 'bzr diff'.
252
If no arguments are specified, the status of the entire working
253
directory is shown. Otherwise, only the status of the specified
254
files or directories is reported. If a directory is given, status
255
is reported for everything inside that directory.
192
For each file there is a single line giving its file state and name.
193
The name is that in the current revision unless it is deleted or
194
missing, in which case the old name is shown.
257
196
takes_args = ['file*']
258
takes_options = ['all', 'show-ids']
197
takes_options = ['all']
259
198
aliases = ['st', 'stat']
261
def run(self, all=False, show_ids=False, file_list=None):
263
b = Branch(file_list[0])
264
file_list = [b.relpath(x) for x in file_list]
265
# special case: only one path was given and it's the root
267
if file_list == ['']:
272
status.show_status(b, show_unchanged=all, show_ids=show_ids,
273
specific_files=file_list)
200
def run(self, all=False, file_list=None):
201
b = Branch('.', lock_mode='r')
202
b.show_status(show_all=all, file_list=file_list)
276
205
class cmd_cat_revision(Command):
332
260
class cmd_inventory(Command):
333
261
"""Show inventory of the current working copy or a revision."""
334
takes_options = ['revision', 'show-ids']
262
takes_options = ['revision']
336
def run(self, revision=None, show_ids=False):
264
def run(self, revision=None):
338
266
if revision == None:
339
267
inv = b.read_working_inventory()
341
269
inv = b.get_revision_inventory(b.lookup_revision(revision))
343
for path, entry in inv.entries():
345
print '%-50s %s' % (path, entry.file_id)
271
for path, entry in inv.iter_entries():
272
print '%-50s %s' % (entry.file_id, path)
350
275
class cmd_move(Command):
407
332
class cmd_info(Command):
408
"""Show statistical information about a branch."""
409
takes_args = ['branch?']
411
def run(self, branch=None):
333
"""Show statistical information for this branch"""
414
from branch import find_branch
415
b = find_branch(branch)
336
info.show_info(Branch('.'))
419
339
class cmd_remove(Command):
527
446
takes_args = ['file*']
528
takes_options = ['revision', 'diff-options']
447
takes_options = ['revision']
531
def run(self, revision=None, file_list=None, diff_options=None):
450
def run(self, revision=None, file_list=None):
532
451
from bzrlib.diff import show_diff
533
from bzrlib import find_branch
536
b = find_branch(file_list[0])
537
file_list = [b.relpath(f) for f in file_list]
538
if file_list == ['']:
539
# just pointing to top-of-tree
544
show_diff(b, revision, specific_files=file_list,
545
external_diff_options=diff_options)
453
show_diff(Branch('.'), revision, file_list)
632
540
class cmd_log(Command):
633
541
"""Show log of this branch.
635
To request a range of logs, you can use the command -r begin:end
636
-r revision requests a specific revision, -r :end or -r begin: are
543
TODO: Option to limit range.
639
TODO: Make --revision support uuid: and hash: [future tag:] notation.
545
TODO: Perhaps show most-recent first with an option for last.
643
547
takes_args = ['filename?']
644
takes_options = ['forward', 'timezone', 'verbose', 'show-ids', 'revision']
646
def run(self, filename=None, timezone='original',
651
from bzrlib import show_log, find_branch
654
direction = (forward and 'forward') or 'reverse'
548
takes_options = ['timezone', 'verbose', 'show-ids']
549
def run(self, filename=None, timezone='original', verbose=False, show_ids=False):
550
from branch import find_branch
551
b = find_branch((filename or '.'), lock_mode='r')
657
b = find_branch(filename)
658
fp = b.relpath(filename)
660
file_id = b.read_working_inventory().path2id(fp)
662
file_id = None # points to branch root
668
revision = [None, None]
669
elif isinstance(revision, int):
670
revision = [revision, revision]
675
assert len(revision) == 2
677
mutter('encoding log as %r' % bzrlib.user_encoding)
678
outf = codecs.getwriter(bzrlib.user_encoding)(sys.stdout)
681
show_timezone=timezone,
686
start_revision=revision[0],
687
end_revision=revision[1])
553
filename = b.relpath(filename)
554
bzrlib.show_log(b, filename,
555
show_timezone=timezone,
691
561
class cmd_touching_revisions(Command):
692
"""Return revision-ids which affected a particular file.
694
A more user-friendly interface is "bzr log FILE"."""
562
"""Return revision-ids which affected a particular file."""
696
564
takes_args = ["filename"]
697
565
def run(self, filename):
566
b = Branch(filename, lock_mode='r')
699
567
inv = b.read_working_inventory()
700
568
file_id = inv.path2id(b.relpath(filename))
701
569
for revno, revision_id, what in bzrlib.log.find_touching_revisions(b, file_id):
760
628
def run(self, name_pattern):
761
629
from bzrlib.atomicfile import AtomicFile
765
633
ifn = b.abspath('.bzrignore')
635
# FIXME: probably doesn't handle non-ascii patterns
767
637
if os.path.exists(ifn):
770
igns = f.read().decode('utf-8')
638
f = b.controlfile(ifn, 'rt')
776
# TODO: If the file already uses crlf-style termination, maybe
777
# we should use that for the newly added lines?
779
644
if igns and igns[-1] != '\n':
781
646
igns += name_pattern + '\n'
784
f = AtomicFile(ifn, 'wt')
785
f.write(igns.encode('utf-8'))
648
f = AtomicFile(ifn, 'wt')
790
652
inv = b.working_tree().inventory
791
653
if inv.path2id('.bzrignore'):
868
730
class cmd_commit(Command):
869
731
"""Commit changes into a new revision.
871
If selected files are specified, only changes to those files are
872
committed. If a directory is specified then its contents are also
875
A selected-file commit may fail in some cases where the committed
876
tree would be invalid, such as trying to commit a file in a
877
newly-added directory that is not itself committed.
733
TODO: Commit only selected files.
879
735
TODO: Run hooks on tree to-be-committed, and after commit.
881
737
TODO: Strict commit that fails if there are unknown or deleted files.
883
takes_args = ['selected*']
884
739
takes_options = ['message', 'file', 'verbose']
885
740
aliases = ['ci', 'checkin']
887
def run(self, message=None, file=None, verbose=True, selected_list=None):
888
from bzrlib.commit import commit
742
def run(self, message=None, file=None, verbose=False):
890
743
## Warning: shadows builtin file()
891
744
if not message and not file:
892
745
raise BzrCommandError("please specify a commit message",
899
752
message = codecs.open(file, 'rt', bzrlib.user_encoding).read()
902
commit(b, message, verbose=verbose, specific_files=selected_list)
754
Branch('.').commit(message, verbose=verbose)
905
757
class cmd_check(Command):
933
785
failures, tests = 0, 0
935
import doctest, bzrlib.store
787
import doctest, bzrlib.store, bzrlib.tests
936
788
bzrlib.trace.verbose = False
938
790
for m in bzrlib.store, bzrlib.inventory, bzrlib.branch, bzrlib.osutils, \
939
bzrlib.tree, bzrlib.commands, bzrlib.add:
791
bzrlib.tree, bzrlib.tests, bzrlib.commands, bzrlib.add:
940
792
mf, mt = doctest.testmod(m)
978
828
print "it sure does!"
980
def parse_spec(spec):
982
parsed = spec.split('/@')
983
assert len(parsed) == 2
987
parsed[1] = int(parsed[1])
990
parsed = [spec, None]
993
class cmd_merge(Command):
994
"""Perform a three-way merge of trees."""
995
takes_args = ['other_spec', 'base_spec']
997
def run(self, other_spec, base_spec):
998
from bzrlib.merge import merge
999
merge(parse_spec(other_spec), parse_spec(base_spec))
1001
831
class cmd_assert_fail(Command):
1002
832
"""Test reporting of assertion failures"""