~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/builtins.py

  • Committer: Aaron Bentley
  • Date: 2007-02-06 14:52:16 UTC
  • mfrom: (2266 +trunk)
  • mto: This revision was merged to the branch mainline in revision 2268.
  • Revision ID: abentley@panoramicfeedback.com-20070206145216-fcpi8o3ufvuzwbp9
Merge bzr.dev

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2004, 2005, 2006, 2007, 2008 Canonical Ltd
 
1
# Copyright (C) 2004, 2005, 2006 Canonical Ltd
2
2
#
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
17
17
"""builtin bzr commands"""
18
18
 
19
19
import os
20
 
from StringIO import StringIO
21
20
 
22
21
from bzrlib.lazy_import import lazy_import
23
22
lazy_import(globals(), """
24
23
import codecs
 
24
import errno
25
25
import sys
26
 
import time
 
26
import tempfile
27
27
 
28
28
import bzrlib
29
29
from bzrlib import (
30
 
    bugtracker,
 
30
    branch,
31
31
    bundle,
32
32
    bzrdir,
33
33
    delta,
34
34
    config,
35
35
    errors,
36
 
    globbing,
37
36
    ignores,
38
37
    log,
39
38
    merge as _mod_merge,
40
 
    merge_directive,
41
39
    osutils,
42
 
    reconfigure,
43
 
    revision as _mod_revision,
 
40
    repository,
44
41
    symbol_versioning,
45
42
    transport,
46
43
    tree as _mod_tree,
48
45
    urlutils,
49
46
    )
50
47
from bzrlib.branch import Branch
 
48
from bzrlib.bundle.apply_bundle import install_bundle, merge_bundle
51
49
from bzrlib.conflicts import ConflictList
 
50
from bzrlib.revision import common_ancestor
52
51
from bzrlib.revisionspec import RevisionSpec
53
 
from bzrlib.smtp_connection import SMTPConnection
54
52
from bzrlib.workingtree import WorkingTree
55
53
""")
56
54
 
57
55
from bzrlib.commands import Command, display_command
58
 
from bzrlib.option import ListOption, Option, RegistryOption, custom_help
59
 
from bzrlib.trace import mutter, note, warning, is_quiet, info
 
56
from bzrlib.option import Option, RegistryOption
 
57
from bzrlib.progress import DummyProgress, ProgressPhase
 
58
from bzrlib.trace import mutter, note, log_error, warning, is_quiet, info
60
59
 
61
60
 
62
61
def tree_files(file_list, default_branch=u'.'):
96
95
    return tree, new_list
97
96
 
98
97
 
 
98
@symbol_versioning.deprecated_function(symbol_versioning.zero_fifteen)
 
99
def get_format_type(typestring):
 
100
    """Parse and return a format specifier."""
 
101
    # Have to use BzrDirMetaFormat1 directly, so that
 
102
    # RepositoryFormat.set_default_format works
 
103
    if typestring == "default":
 
104
        return bzrdir.BzrDirMetaFormat1()
 
105
    try:
 
106
        return bzrdir.format_registry.make_bzrdir(typestring)
 
107
    except KeyError:
 
108
        msg = 'Unknown bzr format "%s". See "bzr help formats".' % typestring
 
109
        raise errors.BzrCommandError(msg)
 
110
 
 
111
 
99
112
# TODO: Make sure no commands unconditionally use the working directory as a
100
113
# branch.  If a filename argument is used, the first of them should be used to
101
114
# specify the branch.  (Perhaps this can be factored out into some kind of
108
121
    This reports on versioned and unknown files, reporting them
109
122
    grouped by state.  Possible states are:
110
123
 
111
 
    added
 
124
    added / A
112
125
        Versioned in the working copy but not in the previous revision.
113
126
 
114
 
    removed
 
127
    removed / D
115
128
        Versioned in the previous revision but removed or deleted
116
129
        in the working copy.
117
130
 
118
 
    renamed
 
131
    renamed / R
119
132
        Path of this file changed from the previous revision;
120
133
        the text may also have changed.  This includes files whose
121
134
        parent directory was renamed.
122
135
 
123
 
    modified
 
136
    modified / M
124
137
        Text has changed since the previous revision.
125
138
 
126
 
    kind changed
127
 
        File kind has been changed (e.g. from file to directory).
128
 
 
129
 
    unknown
 
139
    unknown / ?
130
140
        Not versioned and not matching an ignore pattern.
131
141
 
132
 
    To see ignored files use 'bzr ignored'.  For details on the
 
142
    To see ignored files use 'bzr ignored'.  For details in the
133
143
    changes to file texts, use 'bzr diff'.
134
144
    
135
 
    Note that --short or -S gives status flags for each item, similar
136
 
    to Subversion's status command. To get output similar to svn -q,
137
 
    use bzr status -SV.
 
145
    --short gives a one character status flag for each item, similar
 
146
    to the SVN's status command.
138
147
 
139
148
    If no arguments are specified, the status of the entire working
140
149
    directory is shown.  Otherwise, only the status of the specified
148
157
    # TODO: --no-recurse, --recurse options
149
158
    
150
159
    takes_args = ['file*']
151
 
    takes_options = ['show-ids', 'revision', 'change',
152
 
                     Option('short', help='Use short status indicators.',
153
 
                            short_name='S'),
154
 
                     Option('versioned', help='Only show versioned files.',
155
 
                            short_name='V'),
156
 
                     Option('no-pending', help='Don\'t show pending merges.',
157
 
                           ),
158
 
                     ]
 
160
    takes_options = ['show-ids', 'revision', 'short']
159
161
    aliases = ['st', 'stat']
160
162
 
161
163
    encoding_type = 'replace'
162
 
    _see_also = ['diff', 'revert', 'status-flags']
163
164
    
164
165
    @display_command
165
 
    def run(self, show_ids=False, file_list=None, revision=None, short=False,
166
 
            versioned=False, no_pending=False):
 
166
    def run(self, show_ids=False, file_list=None, revision=None, short=False):
167
167
        from bzrlib.status import show_tree_status
168
168
 
169
 
        if revision and len(revision) > 2:
170
 
            raise errors.BzrCommandError('bzr status --revision takes exactly'
171
 
                                         ' one or two revision specifiers')
172
 
 
173
169
        tree, file_list = tree_files(file_list)
174
170
            
175
171
        show_tree_status(tree, show_ids=show_ids,
176
172
                         specific_files=file_list, revision=revision,
177
 
                         to_file=self.outf, short=short, versioned=versioned,
178
 
                         show_pending=not no_pending)
 
173
                         to_file=self.outf,
 
174
                         short=short)
179
175
 
180
176
 
181
177
class cmd_cat_revision(Command):
193
189
    
194
190
    @display_command
195
191
    def run(self, revision_id=None, revision=None):
 
192
 
196
193
        if revision_id is not None and revision is not None:
197
194
            raise errors.BzrCommandError('You can only supply one of'
198
195
                                         ' revision_id or --revision')
203
200
 
204
201
        # TODO: jam 20060112 should cat-revision always output utf-8?
205
202
        if revision_id is not None:
206
 
            revision_id = osutils.safe_revision_id(revision_id, warn=False)
207
203
            self.outf.write(b.repository.get_revision_xml(revision_id).decode('utf-8'))
208
204
        elif revision is not None:
209
205
            for rev in revision:
210
206
                if rev is None:
211
207
                    raise errors.BzrCommandError('You cannot specify a NULL'
212
208
                                                 ' revision.')
213
 
                rev_id = rev.as_revision_id(b)
 
209
                revno, rev_id = rev.in_history(b)
214
210
                self.outf.write(b.repository.get_revision_xml(rev_id).decode('utf-8'))
215
211
    
216
212
 
219
215
 
220
216
    Since a lightweight checkout is little more than a working tree
221
217
    this will refuse to run against one.
222
 
 
223
 
    To re-create the working tree, use "bzr checkout".
224
218
    """
225
 
    _see_also = ['checkout', 'working-trees']
 
219
 
 
220
    hidden = True
226
221
 
227
222
    takes_args = ['location?']
228
223
 
252
247
    This is equal to the number of revisions on this branch.
253
248
    """
254
249
 
255
 
    _see_also = ['info']
256
250
    takes_args = ['location?']
257
251
 
258
252
    @display_command
277
271
        if revision_info_list is not None:
278
272
            for rev in revision_info_list:
279
273
                revs.append(RevisionSpec.from_string(rev))
280
 
 
281
 
        b = Branch.open_containing(u'.')[0]
282
 
 
283
274
        if len(revs) == 0:
284
 
            revs.append(RevisionSpec.from_string('-1'))
 
275
            raise errors.BzrCommandError('You must supply a revision identifier')
 
276
 
 
277
        b = WorkingTree.open_containing(u'.')[0].branch
285
278
 
286
279
        for rev in revs:
287
 
            revision_id = rev.as_revision_id(b)
288
 
            try:
289
 
                revno = '%4d' % (b.revision_id_to_revno(revision_id))
290
 
            except errors.NoSuchRevision:
291
 
                dotted_map = b.get_revision_id_to_revno_map()
292
 
                revno = '.'.join(str(i) for i in dotted_map[revision_id])
293
 
            print '%s %s' % (revno, revision_id)
 
280
            revinfo = rev.in_history(b)
 
281
            if revinfo.revno is None:
 
282
                print '     %s' % revinfo.rev_id
 
283
            else:
 
284
                print '%4d %s' % (revinfo.revno, revinfo.rev_id)
294
285
 
295
286
    
296
287
class cmd_add(Command):
321
312
 
322
313
    --file-ids-from will try to use the file ids from the supplied path.
323
314
    It looks up ids trying to find a matching parent directory with the
324
 
    same filename, and then by pure path. This option is rarely needed
325
 
    but can be useful when adding the same logical file into two
326
 
    branches that will be merged later (without showing the two different
327
 
    adds as a conflict). It is also useful when merging another project
328
 
    into a subdirectory of this one.
 
315
    same filename, and then by pure path.
329
316
    """
330
317
    takes_args = ['file*']
331
 
    takes_options = [
332
 
        Option('no-recurse',
333
 
               help="Don't recursively add the contents of directories."),
334
 
        Option('dry-run',
335
 
               help="Show what would be done, but don't actually do anything."),
336
 
        'verbose',
337
 
        Option('file-ids-from',
338
 
               type=unicode,
339
 
               help='Lookup file ids from this tree.'),
340
 
        ]
 
318
    takes_options = ['no-recurse', 'dry-run', 'verbose',
 
319
                     Option('file-ids-from', type=unicode,
 
320
                            help='Lookup file ids from here')]
341
321
    encoding_type = 'replace'
342
 
    _see_also = ['remove']
343
322
 
344
323
    def run(self, file_list, no_recurse=False, dry_run=False, verbose=False,
345
324
            file_ids_from=None):
346
325
        import bzrlib.add
347
326
 
348
 
        base_tree = None
349
327
        if file_ids_from is not None:
350
328
            try:
351
329
                base_tree, base_path = WorkingTree.open_containing(
361
339
            action = bzrlib.add.AddAction(to_file=self.outf,
362
340
                should_print=(not is_quiet()))
363
341
 
364
 
        if base_tree:
365
 
            base_tree.lock_read()
366
 
        try:
367
 
            file_list = self._maybe_expand_globs(file_list)
368
 
            if file_list:
369
 
                tree = WorkingTree.open_containing(file_list[0])[0]
370
 
            else:
371
 
                tree = WorkingTree.open_containing(u'.')[0]
372
 
            added, ignored = tree.smart_add(file_list, not
373
 
                no_recurse, action=action, save=not dry_run)
374
 
        finally:
375
 
            if base_tree is not None:
376
 
                base_tree.unlock()
 
342
        added, ignored = bzrlib.add.smart_add(file_list, not no_recurse,
 
343
                                              action=action, save=not dry_run)
377
344
        if len(ignored) > 0:
378
345
            if verbose:
379
346
                for glob in sorted(ignored.keys()):
431
398
    set. For example: bzr inventory --show-ids this/file
432
399
    """
433
400
 
434
 
    hidden = True
435
 
    _see_also = ['ls']
436
 
    takes_options = [
437
 
        'revision',
438
 
        'show-ids',
439
 
        Option('kind',
440
 
               help='List entries of a particular kind: file, directory, symlink.',
441
 
               type=unicode),
442
 
        ]
 
401
    takes_options = ['revision', 'show-ids', 'kind']
443
402
    takes_args = ['file*']
444
403
 
445
404
    @display_command
446
405
    def run(self, revision=None, show_ids=False, kind=None, file_list=None):
447
406
        if kind and kind not in ['file', 'directory', 'symlink']:
448
 
            raise errors.BzrCommandError('invalid kind %r specified' % (kind,))
 
407
            raise errors.BzrCommandError('invalid kind specified')
449
408
 
450
409
        work_tree, file_list = tree_files(file_list)
451
 
        work_tree.lock_read()
452
 
        try:
453
 
            if revision is not None:
454
 
                if len(revision) > 1:
455
 
                    raise errors.BzrCommandError(
456
 
                        'bzr inventory --revision takes exactly one revision'
457
 
                        ' identifier')
458
 
                revision_id = revision[0].as_revision_id(work_tree.branch)
459
 
                tree = work_tree.branch.repository.revision_tree(revision_id)
460
 
 
461
 
                extra_trees = [work_tree]
462
 
                tree.lock_read()
463
 
            else:
464
 
                tree = work_tree
465
 
                extra_trees = []
466
 
 
467
 
            if file_list is not None:
468
 
                file_ids = tree.paths2ids(file_list, trees=extra_trees,
469
 
                                          require_versioned=True)
470
 
                # find_ids_across_trees may include some paths that don't
471
 
                # exist in 'tree'.
472
 
                entries = sorted((tree.id2path(file_id), tree.inventory[file_id])
473
 
                                 for file_id in file_ids if file_id in tree)
474
 
            else:
475
 
                entries = tree.inventory.entries()
476
 
        finally:
477
 
            tree.unlock()
478
 
            if tree is not work_tree:
479
 
                work_tree.unlock()
 
410
 
 
411
        if revision is not None:
 
412
            if len(revision) > 1:
 
413
                raise errors.BzrCommandError('bzr inventory --revision takes'
 
414
                                             ' exactly one revision identifier')
 
415
            revision_id = revision[0].in_history(work_tree.branch).rev_id
 
416
            tree = work_tree.branch.repository.revision_tree(revision_id)
 
417
                        
 
418
            # We include work_tree as well as 'tree' here
 
419
            # So that doing '-r 10 path/foo' will lookup whatever file
 
420
            # exists now at 'path/foo' even if it has been renamed, as
 
421
            # well as whatever files existed in revision 10 at path/foo
 
422
            trees = [tree, work_tree]
 
423
        else:
 
424
            tree = work_tree
 
425
            trees = [tree]
 
426
 
 
427
        if file_list is not None:
 
428
            file_ids = _mod_tree.find_ids_across_trees(file_list, trees,
 
429
                                                      require_versioned=True)
 
430
            # find_ids_across_trees may include some paths that don't
 
431
            # exist in 'tree'.
 
432
            entries = sorted((tree.id2path(file_id), tree.inventory[file_id])
 
433
                             for file_id in file_ids if file_id in tree)
 
434
        else:
 
435
            entries = tree.inventory.entries()
480
436
 
481
437
        for path, entry in entries:
482
438
            if kind and kind != entry.kind:
491
447
class cmd_mv(Command):
492
448
    """Move or rename a file.
493
449
 
494
 
    :Usage:
 
450
    usage:
495
451
        bzr mv OLDNAME NEWNAME
496
 
 
497
452
        bzr mv SOURCE... DESTINATION
498
453
 
499
454
    If the last argument is a versioned directory, all the other names
510
465
    """
511
466
 
512
467
    takes_args = ['names*']
513
 
    takes_options = [Option("after", help="Move only the bzr identifier"
514
 
        " of the file, because the file has already been moved."),
515
 
        ]
 
468
    takes_options = [Option("after", help="move only the bzr identifier"
 
469
        " of the file (file has already been moved). Use this flag if"
 
470
        " bzr is not able to detect this itself.")]
516
471
    aliases = ['move', 'rename']
517
472
    encoding_type = 'replace'
518
473
 
523
478
        if len(names_list) < 2:
524
479
            raise errors.BzrCommandError("missing file argument")
525
480
        tree, rel_names = tree_files(names_list)
526
 
        tree.lock_write()
527
 
        try:
528
 
            self._run(tree, names_list, rel_names, after)
529
 
        finally:
530
 
            tree.unlock()
531
 
 
532
 
    def _run(self, tree, names_list, rel_names, after):
533
 
        into_existing = osutils.isdir(names_list[-1])
534
 
        if into_existing and len(names_list) == 2:
535
 
            # special cases:
536
 
            # a. case-insensitive filesystem and change case of dir
537
 
            # b. move directory after the fact (if the source used to be
538
 
            #    a directory, but now doesn't exist in the working tree
539
 
            #    and the target is an existing directory, just rename it)
540
 
            if (not tree.case_sensitive
541
 
                and rel_names[0].lower() == rel_names[1].lower()):
542
 
                into_existing = False
543
 
            else:
544
 
                inv = tree.inventory
545
 
                from_id = tree.path2id(rel_names[0])
546
 
                if (not osutils.lexists(names_list[0]) and
547
 
                    from_id and inv.get_file_kind(from_id) == "directory"):
548
 
                    into_existing = False
549
 
        # move/rename
550
 
        if into_existing:
 
481
        
 
482
        if os.path.isdir(names_list[-1]):
551
483
            # move into existing directory
552
484
            for pair in tree.move(rel_names[:-1], rel_names[-1], after=after):
553
485
                self.outf.write("%s => %s\n" % pair)
558
490
                                             ' directory')
559
491
            tree.rename_one(rel_names[0], rel_names[1], after=after)
560
492
            self.outf.write("%s => %s\n" % (rel_names[0], rel_names[1]))
561
 
 
562
 
 
 
493
            
 
494
    
563
495
class cmd_pull(Command):
564
496
    """Turn this branch into a mirror of another branch.
565
497
 
578
510
    that, you can omit the location to use the default.  To change the
579
511
    default, use --remember. The value will only be saved if the remote
580
512
    location can be accessed.
581
 
 
582
 
    Note: The location can be specified either in the form of a branch,
583
 
    or in the form of a path to a file containing a merge directive generated
584
 
    with bzr send.
585
513
    """
586
514
 
587
 
    _see_also = ['push', 'update', 'status-flags']
588
 
    takes_options = ['remember', 'overwrite', 'revision',
589
 
        custom_help('verbose',
590
 
            help='Show logs of pulled revisions.'),
591
 
        Option('directory',
592
 
            help='Branch to pull into, '
593
 
                 'rather than the one containing the working directory.',
594
 
            short_name='d',
595
 
            type=unicode,
596
 
            ),
597
 
        ]
 
515
    takes_options = ['remember', 'overwrite', 'revision', 'verbose']
598
516
    takes_args = ['location?']
599
517
    encoding_type = 'replace'
600
518
 
601
 
    def run(self, location=None, remember=False, overwrite=False,
602
 
            revision=None, verbose=False,
603
 
            directory=None):
 
519
    def run(self, location=None, remember=False, overwrite=False, revision=None, verbose=False):
604
520
        # FIXME: too much stuff is in the command class
605
 
        revision_id = None
606
 
        mergeable = None
607
 
        if directory is None:
608
 
            directory = u'.'
609
521
        try:
610
 
            tree_to = WorkingTree.open_containing(directory)[0]
 
522
            tree_to = WorkingTree.open_containing(u'.')[0]
611
523
            branch_to = tree_to.branch
612
524
        except errors.NoWorkingTree:
613
525
            tree_to = None
614
 
            branch_to = Branch.open_containing(directory)[0]
 
526
            branch_to = Branch.open_containing(u'.')[0]
615
527
 
616
 
        possible_transports = []
 
528
        reader = None
617
529
        if location is not None:
618
530
            try:
619
 
                mergeable = bundle.read_mergeable_from_url(location,
620
 
                    possible_transports=possible_transports)
 
531
                reader = bundle.read_bundle_from_url(location)
621
532
            except errors.NotABundle:
622
 
                mergeable = None
 
533
                pass # Continue on considering this url a Branch
623
534
 
624
535
        stored_loc = branch_to.get_parent()
625
536
        if location is None:
629
540
            else:
630
541
                display_url = urlutils.unescape_for_display(stored_loc,
631
542
                        self.outf.encoding)
632
 
                if not is_quiet():
633
 
                    self.outf.write("Using saved location: %s\n" % display_url)
 
543
                self.outf.write("Using saved location: %s\n" % display_url)
634
544
                location = stored_loc
635
545
 
636
 
        if mergeable is not None:
637
 
            if revision is not None:
638
 
                raise errors.BzrCommandError(
639
 
                    'Cannot use -r with merge directives or bundles')
640
 
            mergeable.install_revisions(branch_to.repository)
641
 
            base_revision_id, revision_id, verified = \
642
 
                mergeable.get_merge_request(branch_to.repository)
 
546
 
 
547
        if reader is not None:
 
548
            install_bundle(branch_to.repository, reader)
643
549
            branch_from = branch_to
644
550
        else:
645
 
            branch_from = Branch.open(location,
646
 
                possible_transports=possible_transports)
 
551
            branch_from = Branch.open(location)
647
552
 
648
553
            if branch_to.get_parent() is None or remember:
649
554
                branch_to.set_parent(branch_from.base)
650
555
 
651
 
        if revision is not None:
652
 
            if len(revision) == 1:
653
 
                revision_id = revision[0].as_revision_id(branch_from)
654
 
            else:
655
 
                raise errors.BzrCommandError(
656
 
                    'bzr pull --revision takes one value.')
657
 
 
658
 
        branch_to.lock_write()
659
 
        try:
660
 
            if tree_to is not None:
661
 
                change_reporter = delta._ChangeReporter(
662
 
                    unversioned_filter=tree_to.is_ignored)
663
 
                result = tree_to.pull(branch_from, overwrite, revision_id,
664
 
                                      change_reporter,
665
 
                                      possible_transports=possible_transports)
666
 
            else:
667
 
                result = branch_to.pull(branch_from, overwrite, revision_id)
668
 
 
669
 
            result.report(self.outf)
670
 
            if verbose and result.old_revid != result.new_revid:
671
 
                old_rh = list(
672
 
                    branch_to.repository.iter_reverse_revision_history(
673
 
                    result.old_revid))
674
 
                old_rh.reverse()
675
 
                new_rh = branch_to.revision_history()
676
 
                log.show_changed_revisions(branch_to, old_rh, new_rh,
677
 
                                           to_file=self.outf)
678
 
        finally:
679
 
            branch_to.unlock()
 
556
        rev_id = None
 
557
        if revision is None:
 
558
            if reader is not None:
 
559
                rev_id = reader.target
 
560
        elif len(revision) == 1:
 
561
            rev_id = revision[0].in_history(branch_from).rev_id
 
562
        else:
 
563
            raise errors.BzrCommandError('bzr pull --revision takes one value.')
 
564
 
 
565
        old_rh = branch_to.revision_history()
 
566
        if tree_to is not None:
 
567
            count = tree_to.pull(branch_from, overwrite, rev_id)
 
568
        else:
 
569
            count = branch_to.pull(branch_from, overwrite, rev_id)
 
570
        note('%d revision(s) pulled.' % (count,))
 
571
 
 
572
        if verbose:
 
573
            new_rh = branch_to.revision_history()
 
574
            if old_rh != new_rh:
 
575
                # Something changed
 
576
                from bzrlib.log import show_changed_revisions
 
577
                show_changed_revisions(branch_to, old_rh, new_rh,
 
578
                                       to_file=self.outf)
680
579
 
681
580
 
682
581
class cmd_push(Command):
705
604
    location can be accessed.
706
605
    """
707
606
 
708
 
    _see_also = ['pull', 'update', 'working-trees']
709
 
    takes_options = ['remember', 'overwrite', 'verbose', 'revision',
710
 
        Option('create-prefix',
711
 
               help='Create the path leading up to the branch '
712
 
                    'if it does not already exist.'),
713
 
        Option('directory',
714
 
            help='Branch to push from, '
715
 
                 'rather than the one containing the working directory.',
716
 
            short_name='d',
717
 
            type=unicode,
718
 
            ),
719
 
        Option('use-existing-dir',
720
 
               help='By default push will fail if the target'
721
 
                    ' directory exists, but does not already'
722
 
                    ' have a control directory.  This flag will'
723
 
                    ' allow push to proceed.'),
724
 
        Option('stacked',
725
 
            help='Create a stacked branch that references the public location '
726
 
                'of the parent branch.'),
727
 
        Option('stacked-on',
728
 
            help='Create a stacked branch that refers to another branch '
729
 
                'for the commit history. Only the work not present in the '
730
 
                'referenced branch is included in the branch created.',
731
 
            type=unicode),
732
 
        ]
 
607
    takes_options = ['remember', 'overwrite', 'verbose',
 
608
                     Option('create-prefix', 
 
609
                            help='Create the path leading up to the branch '
 
610
                                 'if it does not already exist')]
733
611
    takes_args = ['location?']
734
612
    encoding_type = 'replace'
735
613
 
736
614
    def run(self, location=None, remember=False, overwrite=False,
737
 
        create_prefix=False, verbose=False, revision=None,
738
 
        use_existing_dir=False, directory=None, stacked_on=None,
739
 
        stacked=False):
740
 
        from bzrlib.push import _show_push_branch
741
 
 
742
 
        # Get the source branch and revision_id
743
 
        if directory is None:
744
 
            directory = '.'
745
 
        br_from = Branch.open_containing(directory)[0]
746
 
        if revision is not None:
747
 
            if len(revision) == 1:
748
 
                revision_id = revision[0].in_history(br_from).rev_id
749
 
            else:
750
 
                raise errors.BzrCommandError(
751
 
                    'bzr push --revision takes one value.')
752
 
        else:
753
 
            revision_id = br_from.last_revision()
754
 
 
755
 
        # Get the stacked_on branch, if any
756
 
        if stacked_on is not None:
757
 
            stacked_on = urlutils.normalize_url(stacked_on)
758
 
        elif stacked:
759
 
            parent_url = br_from.get_parent()
760
 
            if parent_url:
761
 
                parent = Branch.open(parent_url)
762
 
                stacked_on = parent.get_public_branch()
763
 
                if not stacked_on:
764
 
                    # I considered excluding non-http url's here, thus forcing
765
 
                    # 'public' branches only, but that only works for some
766
 
                    # users, so it's best to just depend on the user spotting an
767
 
                    # error by the feedback given to them. RBC 20080227.
768
 
                    stacked_on = parent_url
769
 
            if not stacked_on:
770
 
                raise errors.BzrCommandError(
771
 
                    "Could not determine branch to refer to.")
772
 
 
773
 
        # Get the destination location
 
615
            create_prefix=False, verbose=False):
 
616
        # FIXME: Way too big!  Put this into a function called from the
 
617
        # command.
 
618
        
 
619
        br_from = Branch.open_containing('.')[0]
 
620
        stored_loc = br_from.get_push_location()
774
621
        if location is None:
775
 
            stored_loc = br_from.get_push_location()
776
622
            if stored_loc is None:
777
 
                raise errors.BzrCommandError(
778
 
                    "No push location known or specified.")
 
623
                raise errors.BzrCommandError("No push location known or specified.")
779
624
            else:
780
625
                display_url = urlutils.unescape_for_display(stored_loc,
781
626
                        self.outf.encoding)
782
627
                self.outf.write("Using saved location: %s\n" % display_url)
783
628
                location = stored_loc
784
629
 
785
 
        _show_push_branch(br_from, revision_id, location, self.outf,
786
 
            verbose=verbose, overwrite=overwrite, remember=remember,
787
 
            stacked_on=stacked_on, create_prefix=create_prefix,
788
 
            use_existing_dir=use_existing_dir)
 
630
        to_transport = transport.get_transport(location)
 
631
        location_url = to_transport.base
 
632
 
 
633
        old_rh = []
 
634
        try:
 
635
            dir_to = bzrdir.BzrDir.open(location_url)
 
636
            br_to = dir_to.open_branch()
 
637
        except errors.NotBranchError:
 
638
            # create a branch.
 
639
            to_transport = to_transport.clone('..')
 
640
            if not create_prefix:
 
641
                try:
 
642
                    relurl = to_transport.relpath(location_url)
 
643
                    mutter('creating directory %s => %s', location_url, relurl)
 
644
                    to_transport.mkdir(relurl)
 
645
                except errors.NoSuchFile:
 
646
                    raise errors.BzrCommandError("Parent directory of %s "
 
647
                                                 "does not exist." % location)
 
648
            else:
 
649
                current = to_transport.base
 
650
                needed = [(to_transport, to_transport.relpath(location_url))]
 
651
                while needed:
 
652
                    try:
 
653
                        to_transport, relpath = needed[-1]
 
654
                        to_transport.mkdir(relpath)
 
655
                        needed.pop()
 
656
                    except errors.NoSuchFile:
 
657
                        new_transport = to_transport.clone('..')
 
658
                        needed.append((new_transport,
 
659
                                       new_transport.relpath(to_transport.base)))
 
660
                        if new_transport.base == to_transport.base:
 
661
                            raise errors.BzrCommandError("Could not create "
 
662
                                                         "path prefix.")
 
663
            dir_to = br_from.bzrdir.clone(location_url,
 
664
                revision_id=br_from.last_revision())
 
665
            br_to = dir_to.open_branch()
 
666
            count = br_to.last_revision_info()[0]
 
667
            # We successfully created the target, remember it
 
668
            if br_from.get_push_location() is None or remember:
 
669
                br_from.set_push_location(br_to.base)
 
670
        else:
 
671
            # We were able to connect to the remote location, so remember it
 
672
            # we don't need to successfully push because of possible divergence.
 
673
            if br_from.get_push_location() is None or remember:
 
674
                br_from.set_push_location(br_to.base)
 
675
            old_rh = br_to.revision_history()
 
676
            try:
 
677
                try:
 
678
                    tree_to = dir_to.open_workingtree()
 
679
                except errors.NotLocalUrl:
 
680
                    warning('This transport does not update the working '
 
681
                            'tree of: %s' % (br_to.base,))
 
682
                    count = br_from.push(br_to, overwrite)
 
683
                except errors.NoWorkingTree:
 
684
                    count = br_from.push(br_to, overwrite)
 
685
                else:
 
686
                    tree_to.lock_write()
 
687
                    try:
 
688
                        count = br_from.push(tree_to.branch, overwrite)
 
689
                        tree_to.update()
 
690
                    finally:
 
691
                        tree_to.unlock()
 
692
            except errors.DivergedBranches:
 
693
                raise errors.BzrCommandError('These branches have diverged.'
 
694
                                        '  Try using "merge" and then "push".')
 
695
        note('%d revision(s) pushed.' % (count,))
 
696
 
 
697
        if verbose:
 
698
            new_rh = br_to.revision_history()
 
699
            if old_rh != new_rh:
 
700
                # Something changed
 
701
                from bzrlib.log import show_changed_revisions
 
702
                show_changed_revisions(br_to, old_rh, new_rh,
 
703
                                       to_file=self.outf)
789
704
 
790
705
 
791
706
class cmd_branch(Command):
793
708
 
794
709
    If the TO_LOCATION is omitted, the last component of the FROM_LOCATION will
795
710
    be used.  In other words, "branch ../foo/bar" will attempt to create ./bar.
796
 
    If the FROM_LOCATION has no / or path separator embedded, the TO_LOCATION
797
 
    is derived from the FROM_LOCATION by stripping a leading scheme or drive
798
 
    identifier, if any. For example, "branch lp:foo-bar" will attempt to
799
 
    create ./foo-bar.
800
711
 
801
712
    To retrieve the branch as of a particular revision, supply the --revision
802
713
    parameter, as in "branch foo/bar -r 5".
 
714
 
 
715
    --basis is to speed up branching from remote branches.  When specified, it
 
716
    copies all the file-contents, inventory and revision data from the basis
 
717
    branch before copying anything from the remote branch.
803
718
    """
804
 
 
805
 
    _see_also = ['checkout']
806
719
    takes_args = ['from_location', 'to_location?']
807
 
    takes_options = ['revision', Option('hardlink',
808
 
        help='Hard-link working tree files where possible.'),
809
 
        Option('stacked',
810
 
            help='Create a stacked branch referring to the source branch. '
811
 
                'The new branch will depend on the availability of the source '
812
 
                'branch for all operations.'),
813
 
        ]
 
720
    takes_options = ['revision', 'basis']
814
721
    aliases = ['get', 'clone']
815
722
 
816
 
    def run(self, from_location, to_location=None, revision=None,
817
 
            hardlink=False, stacked=False):
818
 
        from bzrlib.tag import _merge_tags_if_possible
 
723
    def run(self, from_location, to_location=None, revision=None, basis=None):
819
724
        if revision is None:
820
725
            revision = [None]
821
726
        elif len(revision) > 1:
822
727
            raise errors.BzrCommandError(
823
728
                'bzr branch --revision takes exactly 1 revision value')
824
 
 
825
 
        accelerator_tree, br_from = bzrdir.BzrDir.open_tree_or_branch(
826
 
            from_location)
 
729
        try:
 
730
            br_from = Branch.open(from_location)
 
731
        except OSError, e:
 
732
            if e.errno == errno.ENOENT:
 
733
                raise errors.BzrCommandError('Source location "%s" does not'
 
734
                                             ' exist.' % to_location)
 
735
            else:
 
736
                raise
827
737
        br_from.lock_read()
828
738
        try:
 
739
            if basis is not None:
 
740
                basis_dir = bzrdir.BzrDir.open_containing(basis)[0]
 
741
            else:
 
742
                basis_dir = None
829
743
            if len(revision) == 1 and revision[0] is not None:
830
 
                revision_id = revision[0].as_revision_id(br_from)
 
744
                revision_id = revision[0].in_history(br_from)[1]
831
745
            else:
832
746
                # FIXME - wt.last_revision, fallback to branch, fall back to
833
747
                # None or perhaps NULL_REVISION to mean copy nothing
834
748
                # RBC 20060209
835
749
                revision_id = br_from.last_revision()
836
750
            if to_location is None:
837
 
                to_location = urlutils.derive_to_location(from_location)
 
751
                to_location = os.path.basename(from_location.rstrip("/\\"))
 
752
                name = None
 
753
            else:
 
754
                name = os.path.basename(to_location) + '\n'
 
755
 
838
756
            to_transport = transport.get_transport(to_location)
839
757
            try:
840
758
                to_transport.mkdir('.')
846
764
                                             % to_location)
847
765
            try:
848
766
                # preserve whatever source format we have.
849
 
                dir = br_from.bzrdir.sprout(to_transport.base, revision_id,
850
 
                                            possible_transports=[to_transport],
851
 
                                            accelerator_tree=accelerator_tree,
852
 
                                            hardlink=hardlink, stacked=stacked)
 
767
                dir = br_from.bzrdir.sprout(to_transport.base,
 
768
                        revision_id, basis_dir)
853
769
                branch = dir.open_branch()
854
770
            except errors.NoSuchRevision:
855
771
                to_transport.delete_tree('.')
856
 
                msg = "The branch %s has no revision %s." % (from_location,
857
 
                    revision[0])
858
 
                raise errors.BzrCommandError(msg)
859
 
            _merge_tags_if_possible(br_from, branch)
860
 
            # If the source branch is stacked, the new branch may
861
 
            # be stacked whether we asked for that explicitly or not.
862
 
            # We therefore need a try/except here and not just 'if stacked:'
863
 
            try:
864
 
                note('Created new stacked branch referring to %s.' %
865
 
                    branch.get_stacked_on_url())
866
 
            except (errors.NotStacked, errors.UnstackableBranchFormat,
867
 
                errors.UnstackableRepositoryFormat), e:
868
 
                note('Branched %d revision(s).' % branch.revno())
 
772
                msg = "The branch %s has no revision %s." % (from_location, revision[0])
 
773
                raise errors.BzrCommandError(msg)
 
774
            except errors.UnlistableBranch:
 
775
                osutils.rmtree(to_location)
 
776
                msg = "The branch %s cannot be used as a --basis" % (basis,)
 
777
                raise errors.BzrCommandError(msg)
 
778
            if name:
 
779
                branch.control_files.put_utf8('branch-name', name)
 
780
            note('Branched %d revision(s).' % branch.revno())
869
781
        finally:
870
782
            br_from.unlock()
871
783
 
880
792
    
881
793
    If the TO_LOCATION is omitted, the last component of the BRANCH_LOCATION will
882
794
    be used.  In other words, "checkout ../foo/bar" will attempt to create ./bar.
883
 
    If the BRANCH_LOCATION has no / or path separator embedded, the TO_LOCATION
884
 
    is derived from the BRANCH_LOCATION by stripping a leading scheme or drive
885
 
    identifier, if any. For example, "checkout lp:foo-bar" will attempt to
886
 
    create ./foo-bar.
887
795
 
888
796
    To retrieve the branch as of a particular revision, supply the --revision
889
797
    parameter, as in "checkout foo/bar -r 5". Note that this will be immediately
890
798
    out of date [so you cannot commit] but it may be useful (i.e. to examine old
891
799
    code.)
 
800
 
 
801
    --basis is to speed up checking out from remote branches.  When specified, it
 
802
    uses the inventory and file contents from the basis branch in preference to the
 
803
    branch being checked out.
892
804
    """
893
 
 
894
 
    _see_also = ['checkouts', 'branch']
895
805
    takes_args = ['branch_location?', 'to_location?']
896
 
    takes_options = ['revision',
 
806
    takes_options = ['revision', # , 'basis']
897
807
                     Option('lightweight',
898
 
                            help="Perform a lightweight checkout.  Lightweight "
 
808
                            help="perform a lightweight checkout. Lightweight "
899
809
                                 "checkouts depend on access to the branch for "
900
 
                                 "every operation.  Normal checkouts can perform "
 
810
                                 "every operation. Normal checkouts can perform "
901
811
                                 "common operations like diff and status without "
902
812
                                 "such access, and also support local commits."
903
813
                            ),
904
 
                     Option('files-from', type=str,
905
 
                            help="Get file contents from this tree."),
906
 
                     Option('hardlink',
907
 
                            help='Hard-link working tree files where possible.'
908
 
                            ),
909
814
                     ]
910
815
    aliases = ['co']
911
816
 
912
 
    def run(self, branch_location=None, to_location=None, revision=None,
913
 
            lightweight=False, files_from=None, hardlink=False):
 
817
    def run(self, branch_location=None, to_location=None, revision=None, basis=None,
 
818
            lightweight=False):
914
819
        if revision is None:
915
820
            revision = [None]
916
821
        elif len(revision) > 1:
919
824
        if branch_location is None:
920
825
            branch_location = osutils.getcwd()
921
826
            to_location = branch_location
922
 
        accelerator_tree, source = bzrdir.BzrDir.open_tree_or_branch(
923
 
            branch_location)
924
 
        if files_from is not None:
925
 
            accelerator_tree = WorkingTree.open(files_from)
 
827
        source = Branch.open(branch_location)
926
828
        if len(revision) == 1 and revision[0] is not None:
927
 
            revision_id = revision[0].as_revision_id(source)
 
829
            revision_id = revision[0].in_history(source)[1]
928
830
        else:
929
831
            revision_id = None
930
832
        if to_location is None:
931
 
            to_location = urlutils.derive_to_location(branch_location)
 
833
            to_location = os.path.basename(branch_location.rstrip("/\\"))
932
834
        # if the source and to_location are the same, 
933
835
        # and there is no working tree,
934
836
        # then reconstitute a branch
937
839
            try:
938
840
                source.bzrdir.open_workingtree()
939
841
            except errors.NoWorkingTree:
940
 
                source.bzrdir.create_workingtree(revision_id)
 
842
                source.bzrdir.create_workingtree()
941
843
                return
942
 
        source.create_checkout(to_location, revision_id, lightweight,
943
 
                               accelerator_tree, hardlink)
 
844
        try:
 
845
            os.mkdir(to_location)
 
846
        except OSError, e:
 
847
            if e.errno == errno.EEXIST:
 
848
                raise errors.BzrCommandError('Target directory "%s" already'
 
849
                                             ' exists.' % to_location)
 
850
            if e.errno == errno.ENOENT:
 
851
                raise errors.BzrCommandError('Parent of "%s" does not exist.'
 
852
                                             % to_location)
 
853
            else:
 
854
                raise
 
855
        source.create_checkout(to_location, revision_id, lightweight)
944
856
 
945
857
 
946
858
class cmd_renames(Command):
949
861
    # TODO: Option to show renames between two historical versions.
950
862
 
951
863
    # TODO: Only show renames under dir, rather than in the whole branch.
952
 
    _see_also = ['status']
953
864
    takes_args = ['dir?']
954
865
 
955
866
    @display_command
956
867
    def run(self, dir=u'.'):
957
868
        tree = WorkingTree.open_containing(dir)[0]
958
 
        tree.lock_read()
959
 
        try:
960
 
            new_inv = tree.inventory
961
 
            old_tree = tree.basis_tree()
962
 
            old_tree.lock_read()
963
 
            try:
964
 
                old_inv = old_tree.inventory
965
 
                renames = list(_mod_tree.find_renames(old_inv, new_inv))
966
 
                renames.sort()
967
 
                for old_name, new_name in renames:
968
 
                    self.outf.write("%s => %s\n" % (old_name, new_name))
969
 
            finally:
970
 
                old_tree.unlock()
971
 
        finally:
972
 
            tree.unlock()
 
869
        old_inv = tree.basis_tree().inventory
 
870
        new_inv = tree.read_working_inventory()
 
871
        renames = list(_mod_tree.find_renames(old_inv, new_inv))
 
872
        renames.sort()
 
873
        for old_name, new_name in renames:
 
874
            self.outf.write("%s => %s\n" % (old_name, new_name))
973
875
 
974
876
 
975
877
class cmd_update(Command):
982
884
    If you want to discard your local changes, you can just do a 
983
885
    'bzr revert' instead of 'bzr commit' after the update.
984
886
    """
985
 
 
986
 
    _see_also = ['pull', 'working-trees', 'status-flags']
987
887
    takes_args = ['dir?']
988
888
    aliases = ['up']
989
889
 
990
890
    def run(self, dir='.'):
991
891
        tree = WorkingTree.open_containing(dir)[0]
992
 
        possible_transports = []
993
 
        master = tree.branch.get_master_branch(
994
 
            possible_transports=possible_transports)
 
892
        master = tree.branch.get_master_branch()
995
893
        if master is not None:
996
894
            tree.lock_write()
997
895
        else:
998
896
            tree.lock_tree_write()
999
897
        try:
1000
898
            existing_pending_merges = tree.get_parent_ids()[1:]
1001
 
            last_rev = _mod_revision.ensure_null(tree.last_revision())
1002
 
            if last_rev == _mod_revision.ensure_null(
1003
 
                tree.branch.last_revision()):
 
899
            last_rev = tree.last_revision()
 
900
            if last_rev == tree.branch.last_revision():
1004
901
                # may be up to date, check master too.
1005
 
                if master is None or last_rev == _mod_revision.ensure_null(
1006
 
                    master.last_revision()):
 
902
                master = tree.branch.get_master_branch()
 
903
                if master is None or last_rev == master.last_revision():
1007
904
                    revno = tree.branch.revision_id_to_revno(last_rev)
1008
905
                    note("Tree is up to date at revision %d." % (revno,))
1009
906
                    return 0
1010
 
            conflicts = tree.update(
1011
 
                delta._ChangeReporter(unversioned_filter=tree.is_ignored),
1012
 
                possible_transports=possible_transports)
1013
 
            revno = tree.branch.revision_id_to_revno(
1014
 
                _mod_revision.ensure_null(tree.last_revision()))
 
907
            conflicts = tree.update()
 
908
            revno = tree.branch.revision_id_to_revno(tree.last_revision())
1015
909
            note('Updated to revision %d.' % (revno,))
1016
910
            if tree.get_parent_ids()[1:] != existing_pending_merges:
1017
911
                note('Your local commits will now show as pending merges with '
1033
927
 
1034
928
    Branches and working trees will also report any missing revisions.
1035
929
    """
1036
 
    _see_also = ['revno', 'working-trees', 'repositories']
1037
930
    takes_args = ['location?']
1038
931
    takes_options = ['verbose']
1039
 
    encoding_type = 'replace'
1040
932
 
1041
933
    @display_command
1042
934
    def run(self, location=None, verbose=False):
1043
 
        if verbose:
1044
 
            noise_level = 2
1045
 
        else:
1046
 
            noise_level = 0
1047
935
        from bzrlib.info import show_bzrdir_info
1048
936
        show_bzrdir_info(bzrdir.BzrDir.open_containing(location)[0],
1049
 
                         verbose=noise_level, outfile=self.outf)
 
937
                         verbose=verbose)
1050
938
 
1051
939
 
1052
940
class cmd_remove(Command):
1053
 
    """Remove files or directories.
 
941
    """Make a file unversioned.
1054
942
 
1055
 
    This makes bzr stop tracking changes to the specified files and
1056
 
    delete them if they can easily be recovered using revert.
 
943
    This makes bzr stop tracking changes to a versioned file.  It does
 
944
    not delete the working copy.
1057
945
 
1058
946
    You can specify one or more files, and/or --new.  If you specify --new,
1059
947
    only 'added' files will be removed.  If you specify both, then new files
1061
949
    also new, they will also be removed.
1062
950
    """
1063
951
    takes_args = ['file*']
1064
 
    takes_options = ['verbose',
1065
 
        Option('new', help='Remove newly-added files.'),
1066
 
        RegistryOption.from_kwargs('file-deletion-strategy',
1067
 
            'The file deletion mode to be used.',
1068
 
            title='Deletion Strategy', value_switches=True, enum_switch=False,
1069
 
            safe='Only delete files if they can be'
1070
 
                 ' safely recovered (default).',
1071
 
            keep="Don't delete any files.",
1072
 
            force='Delete all the specified files, even if they can not be '
1073
 
                'recovered and even if they are non-empty directories.')]
 
952
    takes_options = ['verbose', Option('new', help='remove newly-added files')]
1074
953
    aliases = ['rm']
1075
954
    encoding_type = 'replace'
1076
 
 
1077
 
    def run(self, file_list, verbose=False, new=False,
1078
 
        file_deletion_strategy='safe'):
 
955
    
 
956
    def run(self, file_list, verbose=False, new=False):
1079
957
        tree, file_list = tree_files(file_list)
1080
 
 
1081
 
        if file_list is not None:
1082
 
            file_list = [f for f in file_list]
1083
 
        elif not new:
1084
 
            raise errors.BzrCommandError('Specify one or more files to'
1085
 
            ' remove, or use --new.')
1086
 
 
1087
 
        if new:
 
958
        if new is False:
 
959
            if file_list is None:
 
960
                raise errors.BzrCommandError('Specify one or more files to'
 
961
                                             ' remove, or use --new.')
 
962
        else:
1088
963
            added = tree.changes_from(tree.basis_tree(),
1089
964
                specific_files=file_list).added
1090
965
            file_list = sorted([f[0] for f in added], reverse=True)
1091
966
            if len(file_list) == 0:
1092
967
                raise errors.BzrCommandError('No matching files.')
1093
 
        tree.remove(file_list, verbose=verbose, to_file=self.outf,
1094
 
            keep_files=file_deletion_strategy=='keep',
1095
 
            force=file_deletion_strategy=='force')
 
968
        tree.remove(file_list, verbose=verbose, to_file=self.outf)
1096
969
 
1097
970
 
1098
971
class cmd_file_id(Command):
1104
977
    """
1105
978
 
1106
979
    hidden = True
1107
 
    _see_also = ['inventory', 'ls']
1108
980
    takes_args = ['filename']
1109
981
 
1110
982
    @display_command
1111
983
    def run(self, filename):
1112
984
        tree, relpath = WorkingTree.open_containing(filename)
1113
 
        i = tree.path2id(relpath)
 
985
        i = tree.inventory.path2id(relpath)
1114
986
        if i is None:
1115
987
            raise errors.NotVersionedError(filename)
1116
988
        else:
1130
1002
    @display_command
1131
1003
    def run(self, filename):
1132
1004
        tree, relpath = WorkingTree.open_containing(filename)
1133
 
        fid = tree.path2id(relpath)
 
1005
        inv = tree.inventory
 
1006
        fid = inv.path2id(relpath)
1134
1007
        if fid is None:
1135
1008
            raise errors.NotVersionedError(filename)
1136
 
        segments = osutils.splitpath(relpath)
1137
 
        for pos in range(1, len(segments) + 1):
1138
 
            path = osutils.joinpath(segments[:pos])
1139
 
            self.outf.write("%s\n" % tree.path2id(path))
 
1009
        for fip in inv.get_idpath(fid):
 
1010
            self.outf.write(fip + '\n')
1140
1011
 
1141
1012
 
1142
1013
class cmd_reconcile(Command):
1157
1028
 
1158
1029
    The branch *MUST* be on a listable system such as local disk or sftp.
1159
1030
    """
1160
 
 
1161
 
    _see_also = ['check']
1162
1031
    takes_args = ['branch?']
1163
1032
 
1164
1033
    def run(self, branch="."):
1169
1038
 
1170
1039
class cmd_revision_history(Command):
1171
1040
    """Display the list of revision ids on a branch."""
1172
 
 
1173
 
    _see_also = ['log']
1174
1041
    takes_args = ['location?']
1175
1042
 
1176
1043
    hidden = True
1185
1052
 
1186
1053
class cmd_ancestry(Command):
1187
1054
    """List all revisions merged into this branch."""
1188
 
 
1189
 
    _see_also = ['log', 'revision-history']
1190
1055
    takes_args = ['location?']
1191
1056
 
1192
1057
    hidden = True
1203
1068
            last_revision = wt.last_revision()
1204
1069
 
1205
1070
        revision_ids = b.repository.get_ancestry(last_revision)
 
1071
        assert revision_ids[0] is None
1206
1072
        revision_ids.pop(0)
1207
1073
        for revision_id in revision_ids:
1208
1074
            self.outf.write(revision_id + '\n')
1216
1082
 
1217
1083
    If there is a repository in a parent directory of the location, then 
1218
1084
    the history of the branch will be stored in the repository.  Otherwise
1219
 
    init creates a standalone branch which carries its own history
1220
 
    in the .bzr directory.
 
1085
    init creates a standalone branch which carries its own history in 
 
1086
    .bzr.
1221
1087
 
1222
1088
    If there is already a branch at the location but it has no working tree,
1223
1089
    the tree can be populated with 'bzr checkout'.
1224
1090
 
1225
 
    Recipe for importing a tree of files::
1226
 
 
 
1091
    Recipe for importing a tree of files:
1227
1092
        cd ~/project
1228
1093
        bzr init
1229
1094
        bzr add .
1230
1095
        bzr status
1231
 
        bzr commit -m "imported project"
 
1096
        bzr commit -m 'imported project'
1232
1097
    """
1233
 
 
1234
 
    _see_also = ['init-repository', 'branch', 'checkout']
1235
1098
    takes_args = ['location?']
1236
1099
    takes_options = [
1237
 
        Option('create-prefix',
1238
 
               help='Create the path leading up to the branch '
1239
 
                    'if it does not already exist.'),
1240
 
         RegistryOption('format',
1241
 
                help='Specify a format for this branch. '
1242
 
                'See "help formats".',
1243
 
                registry=bzrdir.format_registry,
1244
 
                converter=bzrdir.format_registry.make_bzrdir,
1245
 
                value_switches=True,
1246
 
                title="Branch Format",
1247
 
                ),
1248
 
         Option('append-revisions-only',
1249
 
                help='Never change revnos or the existing log.'
1250
 
                '  Append revisions to it only.')
1251
 
         ]
1252
 
    def run(self, location=None, format=None, append_revisions_only=False,
1253
 
            create_prefix=False):
 
1100
                     RegistryOption('format',
 
1101
                            help='Specify a format for this branch. Current'
 
1102
                                 ' formats are: default, knit, metaweave and'
 
1103
                                 ' weave. Default is knit; metaweave and'
 
1104
                                 ' weave are deprecated',
 
1105
                            converter=bzrdir.format_registry.make_bzrdir,
 
1106
                            registry=bzrdir.format_registry,
 
1107
                            value_switches=True),
 
1108
                     ]
 
1109
    def run(self, location=None, format=None):
1254
1110
        if format is None:
1255
1111
            format = bzrdir.format_registry.make_bzrdir('default')
1256
1112
        if location is None:
1263
1119
        # Just using os.mkdir, since I don't
1264
1120
        # believe that we want to create a bunch of
1265
1121
        # locations if the user supplies an extended path
1266
 
        try:
1267
 
            to_transport.ensure_base()
1268
 
        except errors.NoSuchFile:
1269
 
            if not create_prefix:
1270
 
                raise errors.BzrCommandError("Parent directory of %s"
1271
 
                    " does not exist."
1272
 
                    "\nYou may supply --create-prefix to create all"
1273
 
                    " leading parent directories."
1274
 
                    % location)
1275
 
            _create_prefix(to_transport)
1276
 
 
1277
 
        try:
1278
 
            existing_bzrdir = bzrdir.BzrDir.open_from_transport(to_transport)
 
1122
        # TODO: create-prefix
 
1123
        try:
 
1124
            to_transport.mkdir('.')
 
1125
        except errors.FileExists:
 
1126
            pass
 
1127
                    
 
1128
        try:
 
1129
            existing_bzrdir = bzrdir.BzrDir.open(location)
1279
1130
        except errors.NotBranchError:
1280
1131
            # really a NotBzrDir error...
1281
 
            create_branch = bzrdir.BzrDir.create_branch_convenience
1282
 
            branch = create_branch(to_transport.base, format=format,
1283
 
                                   possible_transports=[to_transport])
 
1132
            bzrdir.BzrDir.create_branch_convenience(location, format=format)
1284
1133
        else:
1285
1134
            from bzrlib.transport.local import LocalTransport
1286
1135
            if existing_bzrdir.has_branch():
1289
1138
                        raise errors.BranchExistsWithoutWorkingTree(location)
1290
1139
                raise errors.AlreadyBranchError(location)
1291
1140
            else:
1292
 
                branch = existing_bzrdir.create_branch()
 
1141
                existing_bzrdir.create_branch()
1293
1142
                existing_bzrdir.create_workingtree()
1294
 
        if append_revisions_only:
1295
 
            try:
1296
 
                branch.set_append_revisions_only(True)
1297
 
            except errors.UpgradeRequired:
1298
 
                raise errors.BzrCommandError('This branch format cannot be set'
1299
 
                    ' to append-revisions-only.  Try --experimental-branch6')
1300
1143
 
1301
1144
 
1302
1145
class cmd_init_repository(Command):
1303
1146
    """Create a shared repository to hold branches.
1304
1147
 
1305
 
    New branches created under the repository directory will store their
1306
 
    revisions in the repository, not in the branch directory.
1307
 
 
1308
 
    If the --no-trees option is used then the branches in the repository
1309
 
    will not have working trees by default.
1310
 
 
1311
 
    :Examples:
1312
 
        Create a shared repositories holding just branches::
1313
 
 
1314
 
            bzr init-repo --no-trees repo
1315
 
            bzr init repo/trunk
1316
 
 
1317
 
        Make a lightweight checkout elsewhere::
1318
 
 
1319
 
            bzr checkout --lightweight repo/trunk trunk-checkout
1320
 
            cd trunk-checkout
1321
 
            (add files here)
 
1148
    New branches created under the repository directory will store their revisions
 
1149
    in the repository, not in the branch directory, if the branch format supports
 
1150
    shared storage.
 
1151
 
 
1152
    example:
 
1153
        bzr init-repo repo
 
1154
        bzr init repo/trunk
 
1155
        bzr checkout --lightweight repo/trunk trunk-checkout
 
1156
        cd trunk-checkout
 
1157
        (add files here)
1322
1158
    """
1323
 
 
1324
 
    _see_also = ['init', 'branch', 'checkout', 'repositories']
1325
 
    takes_args = ["location"]
 
1159
    takes_args = ["location"] 
1326
1160
    takes_options = [RegistryOption('format',
1327
 
                            help='Specify a format for this repository. See'
1328
 
                                 ' "bzr help formats" for details.',
 
1161
                            help='Specify a format for this repository.'
 
1162
                                 ' Current formats are: default, knit,'
 
1163
                                 ' metaweave and weave. Default is knit;'
 
1164
                                 ' metaweave and weave are deprecated',
1329
1165
                            registry=bzrdir.format_registry,
1330
1166
                            converter=bzrdir.format_registry.make_bzrdir,
1331
 
                            value_switches=True, title='Repository format'),
1332
 
                     Option('no-trees',
1333
 
                             help='Branches in the repository will default to'
1334
 
                                  ' not having a working tree.'),
1335
 
                    ]
 
1167
                            value_switches=True),
 
1168
                     Option('trees',
 
1169
                             help='Allows branches in repository to have'
 
1170
                             ' a working tree')]
1336
1171
    aliases = ["init-repo"]
1337
 
 
1338
 
    def run(self, location, format=None, no_trees=False):
 
1172
    def run(self, location, format=None, trees=False):
1339
1173
        if format is None:
1340
1174
            format = bzrdir.format_registry.make_bzrdir('default')
1341
1175
 
1343
1177
            location = '.'
1344
1178
 
1345
1179
        to_transport = transport.get_transport(location)
1346
 
        to_transport.ensure_base()
 
1180
        try:
 
1181
            to_transport.mkdir('.')
 
1182
        except errors.FileExists:
 
1183
            pass
1347
1184
 
1348
1185
        newdir = format.initialize_on_transport(to_transport)
1349
1186
        repo = newdir.create_repository(shared=True)
1350
 
        repo.set_make_working_trees(not no_trees)
 
1187
        repo.set_make_working_trees(trees)
1351
1188
 
1352
1189
 
1353
1190
class cmd_diff(Command):
1354
 
    """Show differences in the working tree, between revisions or branches.
 
1191
    """Show differences in the working tree or between revisions.
1355
1192
    
1356
 
    If no arguments are given, all changes for the current tree are listed.
1357
 
    If files are given, only the changes in those files are listed.
1358
 
    Remote and multiple branches can be compared by using the --old and
1359
 
    --new options. If not provided, the default for both is derived from
1360
 
    the first argument, if any, or the current tree if no arguments are
1361
 
    given.
 
1193
    If files are listed, only the changes in those files are listed.
 
1194
    Otherwise, all changes for the tree are listed.
1362
1195
 
1363
1196
    "bzr diff -p1" is equivalent to "bzr diff --prefix old/:new/", and
1364
1197
    produces patches suitable for "patch -p1".
1365
1198
 
1366
 
    :Exit values:
1367
 
        1 - changed
1368
 
        2 - unrepresentable changes
1369
 
        3 - error
1370
 
        0 - no change
1371
 
 
1372
 
    :Examples:
1373
 
        Shows the difference in the working tree versus the last commit::
1374
 
 
1375
 
            bzr diff
1376
 
 
1377
 
        Difference between the working tree and revision 1::
1378
 
 
1379
 
            bzr diff -r1
1380
 
 
1381
 
        Difference between revision 2 and revision 1::
1382
 
 
1383
 
            bzr diff -r1..2
1384
 
 
1385
 
        Difference between revision 2 and revision 1 for branch xxx::
1386
 
 
1387
 
            bzr diff -r1..2 xxx
1388
 
 
1389
 
        Show just the differences for file NEWS::
1390
 
 
1391
 
            bzr diff NEWS
1392
 
 
1393
 
        Show the differences in working tree xxx for file NEWS::
1394
 
 
1395
 
            bzr diff xxx/NEWS
1396
 
 
1397
 
        Show the differences from branch xxx to this working tree:
1398
 
 
1399
 
            bzr diff --old xxx
1400
 
 
1401
 
        Show the differences between two branches for file NEWS::
1402
 
 
1403
 
            bzr diff --old xxx --new yyy NEWS
1404
 
 
1405
 
        Same as 'bzr diff' but prefix paths with old/ and new/::
1406
 
 
1407
 
            bzr diff --prefix old/:new/
 
1199
    examples:
 
1200
        bzr diff
 
1201
            Shows the difference in the working tree versus the last commit
 
1202
        bzr diff -r1
 
1203
            Difference between the working tree and revision 1
 
1204
        bzr diff -r1..2
 
1205
            Difference between revision 2 and revision 1
 
1206
        bzr diff --diff-prefix old/:new/
 
1207
            Same as 'bzr diff' but prefix paths with old/ and new/
 
1208
        bzr diff bzr.mine bzr.dev
 
1209
            Show the differences between the two working trees
 
1210
        bzr diff foo.c
 
1211
            Show just the differences for 'foo.c'
1408
1212
    """
1409
 
    _see_also = ['status']
 
1213
    # TODO: Option to use external diff command; could be GNU diff, wdiff,
 
1214
    #       or a graphical diff.
 
1215
 
 
1216
    # TODO: Python difflib is not exactly the same as unidiff; should
 
1217
    #       either fix it up or prefer to use an external diff.
 
1218
 
 
1219
    # TODO: Selected-file diff is inefficient and doesn't show you
 
1220
    #       deleted files.
 
1221
 
 
1222
    # TODO: This probably handles non-Unix newlines poorly.
 
1223
 
1410
1224
    takes_args = ['file*']
1411
 
    takes_options = [
1412
 
        Option('diff-options', type=str,
1413
 
               help='Pass these options to the external diff program.'),
 
1225
    takes_options = ['revision', 'diff-options',
1414
1226
        Option('prefix', type=str,
1415
1227
               short_name='p',
1416
 
               help='Set prefixes added to old and new filenames, as '
1417
 
                    'two values separated by a colon. (eg "old/:new/").'),
1418
 
        Option('old',
1419
 
            help='Branch/tree to compare from.',
1420
 
            type=unicode,
1421
 
            ),
1422
 
        Option('new',
1423
 
            help='Branch/tree to compare to.',
1424
 
            type=unicode,
1425
 
            ),
1426
 
        'revision',
1427
 
        'change',
1428
 
        Option('using',
1429
 
            help='Use this command to compare files.',
1430
 
            type=unicode,
1431
 
            ),
 
1228
               help='Set prefixes to added to old and new filenames, as '
 
1229
                    'two values separated by a colon.'),
1432
1230
        ]
1433
1231
    aliases = ['di', 'dif']
1434
1232
    encoding_type = 'exact'
1435
1233
 
1436
1234
    @display_command
1437
1235
    def run(self, revision=None, file_list=None, diff_options=None,
1438
 
            prefix=None, old=None, new=None, using=None):
1439
 
        from bzrlib.diff import _get_trees_to_diff, show_diff_trees
 
1236
            prefix=None):
 
1237
        from bzrlib.diff import diff_cmd_helper, show_diff_trees
1440
1238
 
1441
1239
        if (prefix is None) or (prefix == '0'):
1442
1240
            # diff -p0 format
1448
1246
        elif ':' in prefix:
1449
1247
            old_label, new_label = prefix.split(":")
1450
1248
        else:
1451
 
            raise errors.BzrCommandError(
1452
 
                '--prefix expects two values separated by a colon'
1453
 
                ' (eg "old/:new/")')
 
1249
            raise BzrCommandError(
 
1250
                "--prefix expects two values separated by a colon")
1454
1251
 
1455
1252
        if revision and len(revision) > 2:
1456
1253
            raise errors.BzrCommandError('bzr diff --revision takes exactly'
1457
1254
                                         ' one or two revision specifiers')
1458
 
 
1459
 
        old_tree, new_tree, specific_files, extra_trees = \
1460
 
                _get_trees_to_diff(file_list, revision, old, new)
1461
 
        return show_diff_trees(old_tree, new_tree, sys.stdout, 
1462
 
                               specific_files=specific_files,
1463
 
                               external_diff_options=diff_options,
1464
 
                               old_label=old_label, new_label=new_label,
1465
 
                               extra_trees=extra_trees, using=using)
 
1255
        
 
1256
        try:
 
1257
            tree1, file_list = internal_tree_files(file_list)
 
1258
            tree2 = None
 
1259
            b = None
 
1260
            b2 = None
 
1261
        except errors.FileInWrongBranch:
 
1262
            if len(file_list) != 2:
 
1263
                raise errors.BzrCommandError("Files are in different branches")
 
1264
 
 
1265
            tree1, file1 = WorkingTree.open_containing(file_list[0])
 
1266
            tree2, file2 = WorkingTree.open_containing(file_list[1])
 
1267
            if file1 != "" or file2 != "":
 
1268
                # FIXME diff those two files. rbc 20051123
 
1269
                raise errors.BzrCommandError("Files are in different branches")
 
1270
            file_list = None
 
1271
        except errors.NotBranchError:
 
1272
            if (revision is not None and len(revision) == 2
 
1273
                and not revision[0].needs_branch()
 
1274
                and not revision[1].needs_branch()):
 
1275
                # If both revision specs include a branch, we can
 
1276
                # diff them without needing a local working tree
 
1277
                tree1, tree2 = None, None
 
1278
            else:
 
1279
                raise
 
1280
 
 
1281
        if tree2 is not None:
 
1282
            if revision is not None:
 
1283
                # FIXME: but there should be a clean way to diff between
 
1284
                # non-default versions of two trees, it's not hard to do
 
1285
                # internally...
 
1286
                raise errors.BzrCommandError(
 
1287
                        "Sorry, diffing arbitrary revisions across branches "
 
1288
                        "is not implemented yet")
 
1289
            return show_diff_trees(tree1, tree2, sys.stdout, 
 
1290
                                   specific_files=file_list,
 
1291
                                   external_diff_options=diff_options,
 
1292
                                   old_label=old_label, new_label=new_label)
 
1293
 
 
1294
        return diff_cmd_helper(tree1, file_list, diff_options,
 
1295
                               revision_specs=revision,
 
1296
                               old_label=old_label, new_label=new_label)
1466
1297
 
1467
1298
 
1468
1299
class cmd_deleted(Command):
1474
1305
    # directories with readdir, rather than stating each one.  Same
1475
1306
    # level of effort but possibly much less IO.  (Or possibly not,
1476
1307
    # if the directories are very large...)
1477
 
    _see_also = ['status', 'ls']
1478
1308
    takes_options = ['show-ids']
1479
1309
 
1480
1310
    @display_command
1481
1311
    def run(self, show_ids=False):
1482
1312
        tree = WorkingTree.open_containing(u'.')[0]
1483
 
        tree.lock_read()
1484
 
        try:
1485
 
            old = tree.basis_tree()
1486
 
            old.lock_read()
1487
 
            try:
1488
 
                for path, ie in old.inventory.iter_entries():
1489
 
                    if not tree.has_id(ie.file_id):
1490
 
                        self.outf.write(path)
1491
 
                        if show_ids:
1492
 
                            self.outf.write(' ')
1493
 
                            self.outf.write(ie.file_id)
1494
 
                        self.outf.write('\n')
1495
 
            finally:
1496
 
                old.unlock()
1497
 
        finally:
1498
 
            tree.unlock()
 
1313
        old = tree.basis_tree()
 
1314
        for path, ie in old.inventory.iter_entries():
 
1315
            if not tree.has_id(ie.file_id):
 
1316
                self.outf.write(path)
 
1317
                if show_ids:
 
1318
                    self.outf.write(' ')
 
1319
                    self.outf.write(ie.file_id)
 
1320
                self.outf.write('\n')
1499
1321
 
1500
1322
 
1501
1323
class cmd_modified(Command):
1502
 
    """List files modified in working tree.
1503
 
    """
1504
 
 
 
1324
    """List files modified in working tree."""
1505
1325
    hidden = True
1506
 
    _see_also = ['status', 'ls']
1507
 
    takes_options = [
1508
 
            Option('null',
1509
 
                   help='Write an ascii NUL (\\0) separator '
1510
 
                   'between files rather than a newline.')
1511
 
            ]
1512
 
 
1513
1326
    @display_command
1514
 
    def run(self, null=False):
 
1327
    def run(self):
1515
1328
        tree = WorkingTree.open_containing(u'.')[0]
1516
1329
        td = tree.changes_from(tree.basis_tree())
1517
1330
        for path, id, kind, text_modified, meta_modified in td.modified:
1518
 
            if null:
1519
 
                self.outf.write(path + '\0')
1520
 
            else:
1521
 
                self.outf.write(osutils.quotefn(path) + '\n')
 
1331
            self.outf.write(path + '\n')
1522
1332
 
1523
1333
 
1524
1334
class cmd_added(Command):
1525
 
    """List files added in working tree.
1526
 
    """
1527
 
 
 
1335
    """List files added in working tree."""
1528
1336
    hidden = True
1529
 
    _see_also = ['status', 'ls']
1530
 
    takes_options = [
1531
 
            Option('null',
1532
 
                   help='Write an ascii NUL (\\0) separator '
1533
 
                   'between files rather than a newline.')
1534
 
            ]
1535
 
 
1536
1337
    @display_command
1537
 
    def run(self, null=False):
 
1338
    def run(self):
1538
1339
        wt = WorkingTree.open_containing(u'.')[0]
1539
 
        wt.lock_read()
1540
 
        try:
1541
 
            basis = wt.basis_tree()
1542
 
            basis.lock_read()
1543
 
            try:
1544
 
                basis_inv = basis.inventory
1545
 
                inv = wt.inventory
1546
 
                for file_id in inv:
1547
 
                    if file_id in basis_inv:
1548
 
                        continue
1549
 
                    if inv.is_root(file_id) and len(basis_inv) == 0:
1550
 
                        continue
1551
 
                    path = inv.id2path(file_id)
1552
 
                    if not os.access(osutils.abspath(path), os.F_OK):
1553
 
                        continue
1554
 
                    if null:
1555
 
                        self.outf.write(path + '\0')
1556
 
                    else:
1557
 
                        self.outf.write(osutils.quotefn(path) + '\n')
1558
 
            finally:
1559
 
                basis.unlock()
1560
 
        finally:
1561
 
            wt.unlock()
 
1340
        basis_inv = wt.basis_tree().inventory
 
1341
        inv = wt.inventory
 
1342
        for file_id in inv:
 
1343
            if file_id in basis_inv:
 
1344
                continue
 
1345
            if inv.is_root(file_id) and len(basis_inv) == 0:
 
1346
                continue
 
1347
            path = inv.id2path(file_id)
 
1348
            if not os.access(osutils.abspath(path), os.F_OK):
 
1349
                continue
 
1350
            self.outf.write(path + '\n')
1562
1351
 
1563
1352
 
1564
1353
class cmd_root(Command):
1566
1355
 
1567
1356
    The root is the nearest enclosing directory with a .bzr control
1568
1357
    directory."""
1569
 
 
1570
1358
    takes_args = ['filename?']
1571
1359
    @display_command
1572
1360
    def run(self, filename=None):
1575
1363
        self.outf.write(tree.basedir + '\n')
1576
1364
 
1577
1365
 
1578
 
def _parse_limit(limitstring):
1579
 
    try:
1580
 
        return int(limitstring)
1581
 
    except ValueError:
1582
 
        msg = "The limit argument must be an integer."
1583
 
        raise errors.BzrCommandError(msg)
1584
 
 
1585
 
 
1586
1366
class cmd_log(Command):
1587
1367
    """Show log of a branch, file, or directory.
1588
1368
 
1592
1372
    -r revision requests a specific revision, -r ..end or -r begin.. are
1593
1373
    also valid.
1594
1374
 
1595
 
    :Examples:
1596
 
        Log the current branch::
1597
 
 
1598
 
            bzr log
1599
 
 
1600
 
        Log a file::
1601
 
 
1602
 
            bzr log foo.c
1603
 
 
1604
 
        Log the last 10 revisions of a branch::
1605
 
 
1606
 
            bzr log -r -10.. http://server/branch
 
1375
    examples:
 
1376
        bzr log
 
1377
        bzr log foo.c
 
1378
        bzr log -r -10.. http://server/branch
1607
1379
    """
1608
1380
 
1609
1381
    # TODO: Make --revision support uuid: and hash: [future tag:] notation.
1610
1382
 
1611
1383
    takes_args = ['location?']
1612
 
    takes_options = [
1613
 
            Option('forward',
1614
 
                   help='Show from oldest to newest.'),
1615
 
            Option('timezone',
1616
 
                   type=str,
1617
 
                   help='Display timezone as local, original, or utc.'),
1618
 
            custom_help('verbose',
1619
 
                   help='Show files changed in each revision.'),
1620
 
            'show-ids',
1621
 
            'revision',
1622
 
            'log-format',
1623
 
            Option('message',
1624
 
                   short_name='m',
1625
 
                   help='Show revisions whose message matches this '
1626
 
                        'regular expression.',
1627
 
                   type=str),
1628
 
            Option('limit',
1629
 
                   short_name='l',
1630
 
                   help='Limit the output to the first N revisions.',
1631
 
                   argname='N',
1632
 
                   type=_parse_limit),
1633
 
            ]
 
1384
    takes_options = [Option('forward', 
 
1385
                            help='show from oldest to newest'),
 
1386
                     'timezone', 
 
1387
                     Option('verbose', 
 
1388
                             short_name='v',
 
1389
                             help='show files changed in each revision'),
 
1390
                     'show-ids', 'revision',
 
1391
                     'log-format',
 
1392
                     'line', 'long', 
 
1393
                     Option('message',
 
1394
                            short_name='m',
 
1395
                            help='show revisions whose message matches this regexp',
 
1396
                            type=str),
 
1397
                     'short',
 
1398
                     ]
1634
1399
    encoding_type = 'replace'
1635
1400
 
1636
1401
    @display_command
1641
1406
            revision=None,
1642
1407
            log_format=None,
1643
1408
            message=None,
1644
 
            limit=None):
1645
 
        from bzrlib.log import show_log
 
1409
            long=False,
 
1410
            short=False,
 
1411
            line=False):
 
1412
        from bzrlib.log import log_formatter, show_log
 
1413
        assert message is None or isinstance(message, basestring), \
 
1414
            "invalid message argument %r" % message
1646
1415
        direction = (forward and 'forward') or 'reverse'
1647
1416
        
1648
1417
        # log everything
1650
1419
        if location:
1651
1420
            # find the file id to log:
1652
1421
 
1653
 
            tree, b, fp = bzrdir.BzrDir.open_containing_tree_or_branch(
1654
 
                location)
 
1422
            dir, fp = bzrdir.BzrDir.open_containing(location)
 
1423
            b = dir.open_branch()
1655
1424
            if fp != '':
1656
 
                if tree is None:
1657
 
                    tree = b.basis_tree()
1658
 
                file_id = tree.path2id(fp)
 
1425
                try:
 
1426
                    # might be a tree:
 
1427
                    inv = dir.open_workingtree().inventory
 
1428
                except (errors.NotBranchError, errors.NotLocalUrl):
 
1429
                    # either no tree, or is remote.
 
1430
                    inv = b.basis_tree().inventory
 
1431
                file_id = inv.path2id(fp)
1659
1432
                if file_id is None:
1660
1433
                    raise errors.BzrCommandError(
1661
1434
                        "Path does not have any revision history: %s" %
1671
1444
            dir, relpath = bzrdir.BzrDir.open_containing(location)
1672
1445
            b = dir.open_branch()
1673
1446
 
1674
 
        b.lock_read()
1675
 
        try:
1676
 
            if revision is None:
1677
 
                rev1 = None
1678
 
                rev2 = None
1679
 
            elif len(revision) == 1:
1680
 
                rev1 = rev2 = revision[0].in_history(b)
1681
 
            elif len(revision) == 2:
1682
 
                if revision[1].get_branch() != revision[0].get_branch():
1683
 
                    # b is taken from revision[0].get_branch(), and
1684
 
                    # show_log will use its revision_history. Having
1685
 
                    # different branches will lead to weird behaviors.
1686
 
                    raise errors.BzrCommandError(
1687
 
                        "Log doesn't accept two revisions in different"
1688
 
                        " branches.")
1689
 
                rev1 = revision[0].in_history(b)
1690
 
                rev2 = revision[1].in_history(b)
1691
 
            else:
 
1447
        if revision is None:
 
1448
            rev1 = None
 
1449
            rev2 = None
 
1450
        elif len(revision) == 1:
 
1451
            rev1 = rev2 = revision[0].in_history(b).revno
 
1452
        elif len(revision) == 2:
 
1453
            if revision[1].get_branch() != revision[0].get_branch():
 
1454
                # b is taken from revision[0].get_branch(), and
 
1455
                # show_log will use its revision_history. Having
 
1456
                # different branches will lead to weird behaviors.
1692
1457
                raise errors.BzrCommandError(
1693
 
                    'bzr log --revision takes one or two values.')
1694
 
 
1695
 
            if log_format is None:
1696
 
                log_format = log.log_formatter_registry.get_default(b)
1697
 
 
1698
 
            lf = log_format(show_ids=show_ids, to_file=self.outf,
1699
 
                            show_timezone=timezone)
1700
 
 
1701
 
            show_log(b,
1702
 
                     lf,
1703
 
                     file_id,
1704
 
                     verbose=verbose,
1705
 
                     direction=direction,
1706
 
                     start_revision=rev1,
1707
 
                     end_revision=rev2,
1708
 
                     search=message,
1709
 
                     limit=limit)
1710
 
        finally:
1711
 
            b.unlock()
 
1458
                    "Log doesn't accept two revisions in different branches.")
 
1459
            if revision[0].spec is None:
 
1460
                # missing begin-range means first revision
 
1461
                rev1 = 1
 
1462
            else:
 
1463
                rev1 = revision[0].in_history(b).revno
 
1464
 
 
1465
            if revision[1].spec is None:
 
1466
                # missing end-range means last known revision
 
1467
                rev2 = b.revno()
 
1468
            else:
 
1469
                rev2 = revision[1].in_history(b).revno
 
1470
        else:
 
1471
            raise errors.BzrCommandError('bzr log --revision takes one or two values.')
 
1472
 
 
1473
        # By this point, the revision numbers are converted to the +ve
 
1474
        # form if they were supplied in the -ve form, so we can do
 
1475
        # this comparison in relative safety
 
1476
        if rev1 > rev2:
 
1477
            (rev2, rev1) = (rev1, rev2)
 
1478
 
 
1479
        if (log_format is None):
 
1480
            default = b.get_config().log_format()
 
1481
            log_format = get_log_format(long=long, short=short, line=line, 
 
1482
                                        default=default)
 
1483
        lf = log_formatter(log_format,
 
1484
                           show_ids=show_ids,
 
1485
                           to_file=self.outf,
 
1486
                           show_timezone=timezone)
 
1487
 
 
1488
        show_log(b,
 
1489
                 lf,
 
1490
                 file_id,
 
1491
                 verbose=verbose,
 
1492
                 direction=direction,
 
1493
                 start_revision=rev1,
 
1494
                 end_revision=rev2,
 
1495
                 search=message)
1712
1496
 
1713
1497
 
1714
1498
def get_log_format(long=False, short=False, line=False, default='long'):
1735
1519
    def run(self, filename):
1736
1520
        tree, relpath = WorkingTree.open_containing(filename)
1737
1521
        b = tree.branch
1738
 
        file_id = tree.path2id(relpath)
 
1522
        inv = tree.read_working_inventory()
 
1523
        file_id = inv.path2id(relpath)
1739
1524
        for revno, revision_id, what in log.find_touching_revisions(b, file_id):
1740
1525
            self.outf.write("%6d %s\n" % (revno, what))
1741
1526
 
1744
1529
    """List files in a tree.
1745
1530
    """
1746
1531
 
1747
 
    _see_also = ['status', 'cat']
1748
1532
    takes_args = ['path?']
1749
1533
    # TODO: Take a revision or remote path and list that tree instead.
1750
 
    takes_options = [
1751
 
            'verbose',
1752
 
            'revision',
1753
 
            Option('non-recursive',
1754
 
                   help='Don\'t recurse into subdirectories.'),
1755
 
            Option('from-root',
1756
 
                   help='Print paths relative to the root of the branch.'),
1757
 
            Option('unknown', help='Print unknown files.'),
1758
 
            Option('versioned', help='Print versioned files.',
1759
 
                   short_name='V'),
1760
 
            Option('ignored', help='Print ignored files.'),
1761
 
            Option('null',
1762
 
                   help='Write an ascii NUL (\\0) separator '
1763
 
                   'between files rather than a newline.'),
1764
 
            Option('kind',
1765
 
                   help='List entries of a particular kind: file, directory, symlink.',
1766
 
                   type=unicode),
1767
 
            'show-ids',
1768
 
            ]
 
1534
    takes_options = ['verbose', 'revision',
 
1535
                     Option('non-recursive',
 
1536
                            help='don\'t recurse into sub-directories'),
 
1537
                     Option('from-root',
 
1538
                            help='Print all paths from the root of the branch.'),
 
1539
                     Option('unknown', help='Print unknown files'),
 
1540
                     Option('versioned', help='Print versioned files'),
 
1541
                     Option('ignored', help='Print ignored files'),
 
1542
 
 
1543
                     Option('null', help='Null separate the files'),
 
1544
                     'kind', 'show-ids'
 
1545
                    ]
1769
1546
    @display_command
1770
 
    def run(self, revision=None, verbose=False,
 
1547
    def run(self, revision=None, verbose=False, 
1771
1548
            non_recursive=False, from_root=False,
1772
1549
            unknown=False, versioned=False, ignored=False,
1773
1550
            null=False, kind=None, show_ids=False, path=None):
1798
1575
            relpath += '/'
1799
1576
        if revision is not None:
1800
1577
            tree = branch.repository.revision_tree(
1801
 
                revision[0].as_revision_id(branch))
 
1578
                revision[0].in_history(branch).rev_id)
1802
1579
        elif tree is None:
1803
1580
            tree = branch.basis_tree()
1804
1581
 
1805
 
        tree.lock_read()
1806
 
        try:
1807
 
            for fp, fc, fkind, fid, entry in tree.list_files(include_root=False):
1808
 
                if fp.startswith(relpath):
1809
 
                    fp = osutils.pathjoin(prefix, fp[len(relpath):])
1810
 
                    if non_recursive and '/' in fp:
1811
 
                        continue
1812
 
                    if not all and not selection[fc]:
1813
 
                        continue
1814
 
                    if kind is not None and fkind != kind:
1815
 
                        continue
1816
 
                    if verbose:
1817
 
                        kindch = entry.kind_character()
1818
 
                        outstring = '%-8s %s%s' % (fc, fp, kindch)
1819
 
                        if show_ids and fid is not None:
1820
 
                            outstring = "%-50s %s" % (outstring, fid)
1821
 
                        self.outf.write(outstring + '\n')
1822
 
                    elif null:
1823
 
                        self.outf.write(fp + '\0')
1824
 
                        if show_ids:
1825
 
                            if fid is not None:
1826
 
                                self.outf.write(fid)
1827
 
                            self.outf.write('\0')
1828
 
                        self.outf.flush()
1829
 
                    else:
 
1582
        for fp, fc, fkind, fid, entry in tree.list_files(include_root=False):
 
1583
            if fp.startswith(relpath):
 
1584
                fp = osutils.pathjoin(prefix, fp[len(relpath):])
 
1585
                if non_recursive and '/' in fp:
 
1586
                    continue
 
1587
                if not all and not selection[fc]:
 
1588
                    continue
 
1589
                if kind is not None and fkind != kind:
 
1590
                    continue
 
1591
                if verbose:
 
1592
                    kindch = entry.kind_character()
 
1593
                    outstring = '%-8s %s%s' % (fc, fp, kindch)
 
1594
                    if show_ids and fid is not None:
 
1595
                        outstring = "%-50s %s" % (outstring, fid)
 
1596
                    self.outf.write(outstring + '\n')
 
1597
                elif null:
 
1598
                    self.outf.write(fp + '\0')
 
1599
                    if show_ids:
1830
1600
                        if fid is not None:
1831
 
                            my_id = fid
1832
 
                        else:
1833
 
                            my_id = ''
1834
 
                        if show_ids:
1835
 
                            self.outf.write('%-50s %s\n' % (fp, my_id))
1836
 
                        else:
1837
 
                            self.outf.write(fp + '\n')
1838
 
        finally:
1839
 
            tree.unlock()
 
1601
                            self.outf.write(fid)
 
1602
                        self.outf.write('\0')
 
1603
                    self.outf.flush()
 
1604
                else:
 
1605
                    if fid is not None:
 
1606
                        my_id = fid
 
1607
                    else:
 
1608
                        my_id = ''
 
1609
                    if show_ids:
 
1610
                        self.outf.write('%-50s %s\n' % (fp, my_id))
 
1611
                    else:
 
1612
                        self.outf.write(fp + '\n')
1840
1613
 
1841
1614
 
1842
1615
class cmd_unknowns(Command):
1843
 
    """List unknown files.
1844
 
    """
1845
 
 
1846
 
    hidden = True
1847
 
    _see_also = ['ls']
1848
 
 
 
1616
    """List unknown files."""
1849
1617
    @display_command
1850
1618
    def run(self):
1851
1619
        for f in WorkingTree.open_containing(u'.')[0].unknowns():
1855
1623
class cmd_ignore(Command):
1856
1624
    """Ignore specified files or patterns.
1857
1625
 
1858
 
    See ``bzr help patterns`` for details on the syntax of patterns.
1859
 
 
1860
1626
    To remove patterns from the ignore list, edit the .bzrignore file.
1861
 
    After adding, editing or deleting that file either indirectly by
1862
 
    using this command or directly by using an editor, be sure to commit
1863
 
    it.
 
1627
 
 
1628
    Trailing slashes on patterns are ignored. 
 
1629
    If the pattern contains a slash or is a regular expression, it is compared 
 
1630
    to the whole path from the branch root.  Otherwise, it is compared to only
 
1631
    the last component of the path.  To match a file only in the root 
 
1632
    directory, prepend './'.
 
1633
 
 
1634
    Ignore patterns specifying absolute paths are not allowed.
 
1635
 
 
1636
    Ignore patterns may include globbing wildcards such as:
 
1637
      ? - Matches any single character except '/'
 
1638
      * - Matches 0 or more characters except '/'
 
1639
      /**/ - Matches 0 or more directories in a path
 
1640
      [a-z] - Matches a single character from within a group of characters
 
1641
 
 
1642
    Ignore patterns may also be Python regular expressions.  
 
1643
    Regular expression ignore patterns are identified by a 'RE:' prefix 
 
1644
    followed by the regular expression.  Regular expression ignore patterns
 
1645
    may not include named or numbered groups.
1864
1646
 
1865
1647
    Note: ignore patterns containing shell wildcards must be quoted from 
1866
1648
    the shell on Unix.
1867
1649
 
1868
 
    :Examples:
1869
 
        Ignore the top level Makefile::
1870
 
 
1871
 
            bzr ignore ./Makefile
1872
 
 
1873
 
        Ignore class files in all directories::
1874
 
 
1875
 
            bzr ignore "*.class"
1876
 
 
1877
 
        Ignore .o files under the lib directory::
1878
 
 
1879
 
            bzr ignore "lib/**/*.o"
1880
 
 
1881
 
        Ignore .o files under the lib directory::
1882
 
 
1883
 
            bzr ignore "RE:lib/.*\.o"
1884
 
 
1885
 
        Ignore everything but the "debian" toplevel directory::
1886
 
 
1887
 
            bzr ignore "RE:(?!debian/).*"
 
1650
    examples:
 
1651
        bzr ignore ./Makefile
 
1652
        bzr ignore '*.class'
 
1653
        bzr ignore 'lib/**/*.o'
 
1654
        bzr ignore 'RE:lib/.*\.o'
1888
1655
    """
1889
 
 
1890
 
    _see_also = ['status', 'ignored', 'patterns']
1891
1656
    takes_args = ['name_pattern*']
1892
1657
    takes_options = [
1893
 
        Option('old-default-rules',
1894
 
               help='Write out the ignore rules bzr < 0.9 always used.')
1895
 
        ]
 
1658
                     Option('old-default-rules',
 
1659
                            help='Out the ignore rules bzr < 0.9 always used.')
 
1660
                     ]
1896
1661
    
1897
1662
    def run(self, name_pattern_list=None, old_default_rules=None):
1898
 
        from bzrlib import ignores
 
1663
        from bzrlib.atomicfile import AtomicFile
1899
1664
        if old_default_rules is not None:
1900
1665
            # dump the rules and exit
1901
1666
            for pattern in ignores.OLD_DEFAULTS:
1904
1669
        if not name_pattern_list:
1905
1670
            raise errors.BzrCommandError("ignore requires at least one "
1906
1671
                                  "NAME_PATTERN or --old-default-rules")
1907
 
        name_pattern_list = [globbing.normalize_pattern(p) 
1908
 
                             for p in name_pattern_list]
1909
1672
        for name_pattern in name_pattern_list:
1910
 
            if (name_pattern[0] == '/' or 
1911
 
                (len(name_pattern) > 1 and name_pattern[1] == ':')):
 
1673
            if name_pattern[0] == '/':
1912
1674
                raise errors.BzrCommandError(
1913
1675
                    "NAME_PATTERN should not be an absolute path")
1914
1676
        tree, relpath = WorkingTree.open_containing(u'.')
1915
 
        ignores.tree_ignores_add_patterns(tree, name_pattern_list)
1916
 
        ignored = globbing.Globster(name_pattern_list)
1917
 
        matches = []
1918
 
        tree.lock_read()
1919
 
        for entry in tree.list_files():
1920
 
            id = entry[3]
1921
 
            if id is not None:
1922
 
                filename = entry[0]
1923
 
                if ignored.match(filename):
1924
 
                    matches.append(filename.encode('utf-8'))
1925
 
        tree.unlock()
1926
 
        if len(matches) > 0:
1927
 
            print "Warning: the following files are version controlled and" \
1928
 
                  " match your ignore pattern:\n%s" % ("\n".join(matches),)
 
1677
        ifn = tree.abspath('.bzrignore')
 
1678
        if os.path.exists(ifn):
 
1679
            f = open(ifn, 'rt')
 
1680
            try:
 
1681
                igns = f.read().decode('utf-8')
 
1682
            finally:
 
1683
                f.close()
 
1684
        else:
 
1685
            igns = ''
 
1686
 
 
1687
        # TODO: If the file already uses crlf-style termination, maybe
 
1688
        # we should use that for the newly added lines?
 
1689
 
 
1690
        if igns and igns[-1] != '\n':
 
1691
            igns += '\n'
 
1692
        for name_pattern in name_pattern_list:
 
1693
            igns += name_pattern.rstrip('/') + '\n'
 
1694
 
 
1695
        f = AtomicFile(ifn, 'wb')
 
1696
        try:
 
1697
            f.write(igns.encode('utf-8'))
 
1698
            f.commit()
 
1699
        finally:
 
1700
            f.close()
 
1701
 
 
1702
        inv = tree.inventory
 
1703
        if inv.path2id('.bzrignore'):
 
1704
            mutter('.bzrignore is already versioned')
 
1705
        else:
 
1706
            mutter('need to make new .bzrignore file versioned')
 
1707
            tree.add(['.bzrignore'])
 
1708
 
1929
1709
 
1930
1710
class cmd_ignored(Command):
1931
1711
    """List ignored files and the patterns that matched them.
1932
 
    """
1933
 
 
1934
 
    encoding_type = 'replace'
1935
 
    _see_also = ['ignore']
1936
 
 
 
1712
 
 
1713
    See also: bzr ignore"""
1937
1714
    @display_command
1938
1715
    def run(self):
1939
1716
        tree = WorkingTree.open_containing(u'.')[0]
1940
 
        tree.lock_read()
1941
 
        try:
1942
 
            for path, file_class, kind, file_id, entry in tree.list_files():
1943
 
                if file_class != 'I':
1944
 
                    continue
1945
 
                ## XXX: Slightly inefficient since this was already calculated
1946
 
                pat = tree.is_ignored(path)
1947
 
                self.outf.write('%-50s %s\n' % (path, pat))
1948
 
        finally:
1949
 
            tree.unlock()
 
1717
        for path, file_class, kind, file_id, entry in tree.list_files():
 
1718
            if file_class != 'I':
 
1719
                continue
 
1720
            ## XXX: Slightly inefficient since this was already calculated
 
1721
            pat = tree.is_ignored(path)
 
1722
            print '%-50s %s' % (path, pat)
1950
1723
 
1951
1724
 
1952
1725
class cmd_lookup_revision(Command):
1953
1726
    """Lookup the revision-id from a revision-number
1954
1727
 
1955
 
    :Examples:
 
1728
    example:
1956
1729
        bzr lookup-revision 33
1957
1730
    """
1958
1731
    hidden = True
1969
1742
 
1970
1743
 
1971
1744
class cmd_export(Command):
1972
 
    """Export current or past revision to a destination directory or archive.
 
1745
    """Export past revision to destination directory.
1973
1746
 
1974
1747
    If no revision is specified this exports the last committed revision.
1975
1748
 
1977
1750
    given, try to find the format with the extension. If no extension
1978
1751
    is found exports to a directory (equivalent to --format=dir).
1979
1752
 
1980
 
    If root is supplied, it will be used as the root directory inside
1981
 
    container formats (tar, zip, etc). If it is not supplied it will default
1982
 
    to the exported filename. The root option has no effect for 'dir' format.
1983
 
 
1984
 
    If branch is omitted then the branch containing the current working
1985
 
    directory will be used.
1986
 
 
1987
 
    Note: Export of tree with non-ASCII filenames to zip is not supported.
1988
 
 
1989
 
      =================       =========================
1990
 
      Supported formats       Autodetected by extension
1991
 
      =================       =========================
1992
 
         dir                         (none)
 
1753
    Root may be the top directory for tar, tgz and tbz2 formats. If none
 
1754
    is given, the top directory will be the root name of the file.
 
1755
 
 
1756
    If branch is omitted then the branch containing the CWD will be used.
 
1757
 
 
1758
    Note: export of tree with non-ascii filenames to zip is not supported.
 
1759
 
 
1760
     Supported formats       Autodetected by extension
 
1761
     -----------------       -------------------------
 
1762
         dir                            -
1993
1763
         tar                          .tar
1994
1764
         tbz2                    .tar.bz2, .tbz2
1995
1765
         tgz                      .tar.gz, .tgz
1996
1766
         zip                          .zip
1997
 
      =================       =========================
1998
1767
    """
1999
1768
    takes_args = ['dest', 'branch?']
2000
 
    takes_options = [
2001
 
        Option('format',
2002
 
               help="Type of file to export to.",
2003
 
               type=unicode),
2004
 
        'revision',
2005
 
        Option('root',
2006
 
               type=str,
2007
 
               help="Name of the root directory inside the exported file."),
2008
 
        ]
 
1769
    takes_options = ['revision', 'format', 'root']
2009
1770
    def run(self, dest, branch=None, revision=None, format=None, root=None):
2010
1771
        from bzrlib.export import export
2011
1772
 
2021
1782
        else:
2022
1783
            if len(revision) != 1:
2023
1784
                raise errors.BzrCommandError('bzr export --revision takes exactly 1 argument')
2024
 
            rev_id = revision[0].as_revision_id(b)
 
1785
            rev_id = revision[0].in_history(b).rev_id
2025
1786
        t = b.repository.revision_tree(rev_id)
2026
1787
        try:
2027
1788
            export(t, dest, format, root)
2030
1791
 
2031
1792
 
2032
1793
class cmd_cat(Command):
2033
 
    """Write the contents of a file as of a given revision to standard output.
2034
 
 
2035
 
    If no revision is nominated, the last revision is used.
2036
 
 
2037
 
    Note: Take care to redirect standard output when using this command on a
2038
 
    binary file. 
2039
 
    """
2040
 
 
2041
 
    _see_also = ['ls']
2042
 
    takes_options = [
2043
 
        Option('name-from-revision', help='The path name in the old tree.'),
2044
 
        'revision',
2045
 
        ]
 
1794
    """Write a file's text from a previous revision."""
 
1795
 
 
1796
    takes_options = ['revision', 'name-from-revision']
2046
1797
    takes_args = ['filename']
2047
1798
    encoding_type = 'exact'
2048
1799
 
2050
1801
    def run(self, filename, revision=None, name_from_revision=False):
2051
1802
        if revision is not None and len(revision) != 1:
2052
1803
            raise errors.BzrCommandError("bzr cat --revision takes exactly"
2053
 
                                         " one revision specifier")
2054
 
        tree, branch, relpath = \
2055
 
            bzrdir.BzrDir.open_containing_tree_or_branch(filename)
2056
 
        branch.lock_read()
 
1804
                                        " one number")
 
1805
 
 
1806
        tree = None
2057
1807
        try:
2058
 
            return self._run(tree, branch, relpath, filename, revision,
2059
 
                             name_from_revision)
2060
 
        finally:
2061
 
            branch.unlock()
 
1808
            tree, relpath = WorkingTree.open_containing(filename)
 
1809
            b = tree.branch
 
1810
        except (errors.NotBranchError, errors.NotLocalUrl):
 
1811
            pass
2062
1812
 
2063
 
    def _run(self, tree, b, relpath, filename, revision, name_from_revision):
 
1813
        if revision is not None and revision[0].get_branch() is not None:
 
1814
            b = Branch.open(revision[0].get_branch())
2064
1815
        if tree is None:
 
1816
            b, relpath = Branch.open_containing(filename)
2065
1817
            tree = b.basis_tree()
2066
1818
        if revision is None:
2067
1819
            revision_id = b.last_revision()
2068
1820
        else:
2069
 
            revision_id = revision[0].as_revision_id(b)
 
1821
            revision_id = revision[0].in_history(b).rev_id
2070
1822
 
2071
1823
        cur_file_id = tree.path2id(relpath)
2072
1824
        rev_tree = b.repository.revision_tree(revision_id)
2077
1829
                raise errors.BzrCommandError("%r is not present in revision %s"
2078
1830
                                                % (filename, revision_id))
2079
1831
            else:
2080
 
                content = rev_tree.get_file_text(old_file_id)
 
1832
                rev_tree.print_file(old_file_id)
2081
1833
        elif cur_file_id is not None:
2082
 
            content = rev_tree.get_file_text(cur_file_id)
 
1834
            rev_tree.print_file(cur_file_id)
2083
1835
        elif old_file_id is not None:
2084
 
            content = rev_tree.get_file_text(old_file_id)
 
1836
            rev_tree.print_file(old_file_id)
2085
1837
        else:
2086
1838
            raise errors.BzrCommandError("%r is not present in revision %s" %
2087
1839
                                         (filename, revision_id))
2088
 
        self.outf.write(content)
2089
1840
 
2090
1841
 
2091
1842
class cmd_local_time_offset(Command):
2106
1857
    committed.  If a directory is specified then the directory and everything 
2107
1858
    within it is committed.
2108
1859
 
2109
 
    If author of the change is not the same person as the committer, you can
2110
 
    specify the author's name using the --author option. The name should be
2111
 
    in the same format as a committer-id, e.g. "John Doe <jdoe@example.com>".
2112
 
 
2113
1860
    A selected-file commit may fail in some cases where the committed
2114
 
    tree would be invalid. Consider::
2115
 
 
2116
 
      bzr init foo
2117
 
      mkdir foo/bar
2118
 
      bzr add foo/bar
2119
 
      bzr commit foo -m "committing foo"
2120
 
      bzr mv foo/bar foo/baz
2121
 
      mkdir foo/bar
2122
 
      bzr add foo/bar
2123
 
      bzr commit foo/bar -m "committing bar but not baz"
2124
 
 
2125
 
    In the example above, the last commit will fail by design. This gives
2126
 
    the user the opportunity to decide whether they want to commit the
2127
 
    rename at the same time, separately first, or not at all. (As a general
2128
 
    rule, when in doubt, Bazaar has a policy of Doing the Safe Thing.)
2129
 
 
2130
 
    Note: A selected-file commit after a merge is not yet supported.
 
1861
    tree would be invalid, such as trying to commit a file in a
 
1862
    newly-added directory that is not itself committed.
2131
1863
    """
2132
1864
    # TODO: Run hooks on tree to-be-committed, and after commit.
2133
1865
 
2138
1870
 
2139
1871
    # XXX: verbose currently does nothing
2140
1872
 
2141
 
    _see_also = ['bugs', 'uncommit']
2142
1873
    takes_args = ['selected*']
2143
 
    takes_options = [
2144
 
            Option('message', type=unicode,
2145
 
                   short_name='m',
2146
 
                   help="Description of the new revision."),
2147
 
            'verbose',
2148
 
             Option('unchanged',
2149
 
                    help='Commit even if nothing has changed.'),
2150
 
             Option('file', type=str,
2151
 
                    short_name='F',
2152
 
                    argname='msgfile',
2153
 
                    help='Take commit message from this file.'),
2154
 
             Option('strict',
2155
 
                    help="Refuse to commit if there are unknown "
2156
 
                    "files in the working tree."),
2157
 
             ListOption('fixes', type=str,
2158
 
                    help="Mark a bug as being fixed by this revision."),
2159
 
             Option('author', type=unicode,
2160
 
                    help="Set the author's name, if it's different "
2161
 
                         "from the committer."),
2162
 
             Option('local',
2163
 
                    help="Perform a local commit in a bound "
2164
 
                         "branch.  Local commits are not pushed to "
2165
 
                         "the master branch until a normal commit "
2166
 
                         "is performed."
2167
 
                    ),
2168
 
              Option('show-diff',
2169
 
                     help='When no message is supplied, show the diff along'
2170
 
                     ' with the status summary in the message editor.'),
2171
 
             ]
 
1874
    takes_options = ['message', 'verbose', 
 
1875
                     Option('unchanged',
 
1876
                            help='commit even if nothing has changed'),
 
1877
                     Option('file', type=str, 
 
1878
                            short_name='F',
 
1879
                            argname='msgfile',
 
1880
                            help='file containing commit message'),
 
1881
                     Option('strict',
 
1882
                            help="refuse to commit if there are unknown "
 
1883
                            "files in the working tree."),
 
1884
                     Option('local',
 
1885
                            help="perform a local only commit in a bound "
 
1886
                                 "branch. Such commits are not pushed to "
 
1887
                                 "the master branch until a normal commit "
 
1888
                                 "is performed."
 
1889
                            ),
 
1890
                     ]
2172
1891
    aliases = ['ci', 'checkin']
2173
1892
 
2174
 
    def _get_bug_fix_properties(self, fixes, branch):
2175
 
        properties = []
2176
 
        # Configure the properties for bug fixing attributes.
2177
 
        for fixed_bug in fixes:
2178
 
            tokens = fixed_bug.split(':')
2179
 
            if len(tokens) != 2:
2180
 
                raise errors.BzrCommandError(
2181
 
                    "Invalid bug %s. Must be in the form of 'tag:id'. "
2182
 
                    "Commit refused." % fixed_bug)
2183
 
            tag, bug_id = tokens
2184
 
            try:
2185
 
                bug_url = bugtracker.get_bug_url(tag, branch, bug_id)
2186
 
            except errors.UnknownBugTrackerAbbreviation:
2187
 
                raise errors.BzrCommandError(
2188
 
                    'Unrecognized bug %s. Commit refused.' % fixed_bug)
2189
 
            except errors.MalformedBugIdentifier:
2190
 
                raise errors.BzrCommandError(
2191
 
                    "Invalid bug identifier for %s. Commit refused."
2192
 
                    % fixed_bug)
2193
 
            properties.append('%s fixed' % bug_url)
2194
 
        return '\n'.join(properties)
2195
 
 
2196
 
    def run(self, message=None, file=None, verbose=False, selected_list=None,
2197
 
            unchanged=False, strict=False, local=False, fixes=None,
2198
 
            author=None, show_diff=False):
2199
 
        from bzrlib.errors import (
2200
 
            PointlessCommit,
2201
 
            ConflictsInTree,
2202
 
            StrictCommitFailed
2203
 
        )
2204
 
        from bzrlib.msgeditor import (
2205
 
            edit_commit_message_encoded,
2206
 
            make_commit_message_template_encoded
2207
 
        )
 
1893
    def run(self, message=None, file=None, verbose=True, selected_list=None,
 
1894
            unchanged=False, strict=False, local=False):
 
1895
        from bzrlib.commit import (NullCommitReporter, ReportCommitToLog)
 
1896
        from bzrlib.errors import (PointlessCommit, ConflictsInTree,
 
1897
                StrictCommitFailed)
 
1898
        from bzrlib.msgeditor import edit_commit_message, \
 
1899
                make_commit_message_template
2208
1900
 
2209
1901
        # TODO: Need a blackbox test for invoking the external editor; may be
2210
1902
        # slightly problematic to run this cross-platform.
2211
1903
 
2212
1904
        # TODO: do more checks that the commit will succeed before 
2213
1905
        # spending the user's valuable time typing a commit message.
2214
 
 
2215
 
        properties = {}
2216
 
 
2217
1906
        tree, selected_list = tree_files(selected_list)
2218
1907
        if selected_list == ['']:
2219
1908
            # workaround - commit of root of tree should be exactly the same
2221
1910
            # selected-file merge commit is not done yet
2222
1911
            selected_list = []
2223
1912
 
2224
 
        if fixes is None:
2225
 
            fixes = []
2226
 
        bug_property = self._get_bug_fix_properties(fixes, tree.branch)
2227
 
        if bug_property:
2228
 
            properties['bugs'] = bug_property
2229
 
 
2230
1913
        if local and not tree.branch.get_bound_location():
2231
1914
            raise errors.LocalRequiresBoundBranch()
2232
1915
 
2234
1917
            """Callback to get commit message"""
2235
1918
            my_message = message
2236
1919
            if my_message is None and not file:
2237
 
                t = make_commit_message_template_encoded(tree,
2238
 
                        selected_list, diff=show_diff,
2239
 
                        output_encoding=bzrlib.user_encoding)
2240
 
                my_message = edit_commit_message_encoded(t)
 
1920
                template = make_commit_message_template(tree, selected_list)
 
1921
                my_message = edit_commit_message(template)
2241
1922
                if my_message is None:
2242
1923
                    raise errors.BzrCommandError("please specify a commit"
2243
1924
                        " message with either --message or --file")
2250
1931
            if my_message == "":
2251
1932
                raise errors.BzrCommandError("empty commit message specified")
2252
1933
            return my_message
 
1934
        
 
1935
        if verbose:
 
1936
            reporter = ReportCommitToLog()
 
1937
        else:
 
1938
            reporter = NullCommitReporter()
2253
1939
 
2254
1940
        try:
2255
1941
            tree.commit(message_callback=get_message,
2256
1942
                        specific_files=selected_list,
2257
1943
                        allow_pointless=unchanged, strict=strict, local=local,
2258
 
                        reporter=None, verbose=verbose, revprops=properties,
2259
 
                        author=author)
 
1944
                        reporter=reporter)
2260
1945
        except PointlessCommit:
2261
1946
            # FIXME: This should really happen before the file is read in;
2262
1947
            # perhaps prepare the commit; get the message; then actually commit
2277
1962
 
2278
1963
 
2279
1964
class cmd_check(Command):
2280
 
    """Validate working tree structure, branch consistency and repository history.
2281
 
 
2282
 
    This command checks various invariants about branch and repository storage
2283
 
    to detect data corruption or bzr bugs.
2284
 
 
2285
 
    The working tree and branch checks will only give output if a problem is
2286
 
    detected. The output fields of the repository check are:
2287
 
 
2288
 
        revisions: This is just the number of revisions checked.  It doesn't
2289
 
            indicate a problem.
2290
 
        versionedfiles: This is just the number of versionedfiles checked.  It
2291
 
            doesn't indicate a problem.
2292
 
        unreferenced ancestors: Texts that are ancestors of other texts, but
2293
 
            are not properly referenced by the revision ancestry.  This is a
2294
 
            subtle problem that Bazaar can work around.
2295
 
        unique file texts: This is the total number of unique file contents
2296
 
            seen in the checked revisions.  It does not indicate a problem.
2297
 
        repeated file texts: This is the total number of repeated texts seen
2298
 
            in the checked revisions.  Texts can be repeated when their file
2299
 
            entries are modified, but the file contents are not.  It does not
2300
 
            indicate a problem.
2301
 
 
2302
 
    If no restrictions are specified, all Bazaar data that is found at the given
2303
 
    location will be checked.
2304
 
 
2305
 
    :Examples:
2306
 
 
2307
 
        Check the tree and branch at 'foo'::
2308
 
 
2309
 
            bzr check --tree --branch foo
2310
 
 
2311
 
        Check only the repository at 'bar'::
2312
 
 
2313
 
            bzr check --repo bar
2314
 
 
2315
 
        Check everything at 'baz'::
2316
 
 
2317
 
            bzr check baz
 
1965
    """Validate consistency of branch history.
 
1966
 
 
1967
    This command checks various invariants about the branch storage to
 
1968
    detect data corruption or bzr bugs.
2318
1969
    """
2319
 
 
2320
 
    _see_also = ['reconcile']
2321
 
    takes_args = ['path?']
2322
 
    takes_options = ['verbose',
2323
 
                     Option('branch', help="Check the branch related to the"
2324
 
                                           " current directory."),
2325
 
                     Option('repo', help="Check the repository related to the"
2326
 
                                         " current directory."),
2327
 
                     Option('tree', help="Check the working tree related to"
2328
 
                                         " the current directory.")]
2329
 
 
2330
 
    def run(self, path=None, verbose=False, branch=False, repo=False,
2331
 
            tree=False):
2332
 
        from bzrlib.check import check_dwim
2333
 
        if path is None:
2334
 
            path = '.'
2335
 
        if not branch and not repo and not tree:
2336
 
            branch = repo = tree = True
2337
 
        check_dwim(path, verbose, do_branch=branch, do_repo=repo, do_tree=tree)
 
1970
    takes_args = ['branch?']
 
1971
    takes_options = ['verbose']
 
1972
 
 
1973
    def run(self, branch=None, verbose=False):
 
1974
        from bzrlib.check import check
 
1975
        if branch is None:
 
1976
            tree = WorkingTree.open_containing()[0]
 
1977
            branch = tree.branch
 
1978
        else:
 
1979
            branch = Branch.open(branch)
 
1980
        check(branch, verbose)
2338
1981
 
2339
1982
 
2340
1983
class cmd_upgrade(Command):
2344
1987
    this command. When the default format has changed you may also be warned
2345
1988
    during other operations to upgrade.
2346
1989
    """
2347
 
 
2348
 
    _see_also = ['check']
2349
1990
    takes_args = ['url?']
2350
1991
    takes_options = [
2351
1992
                    RegistryOption('format',
2352
 
                        help='Upgrade to a specific format.  See "bzr help'
2353
 
                             ' formats" for details.',
 
1993
                        help='Upgrade to a specific format. Current formats'
 
1994
                             ' are: default, knit, metaweave and weave.'
 
1995
                             ' Default is knit; metaweave and weave are'
 
1996
                             ' deprecated',
2354
1997
                        registry=bzrdir.format_registry,
2355
1998
                        converter=bzrdir.format_registry.make_bzrdir,
2356
 
                        value_switches=True, title='Branch format'),
 
1999
                        value_switches=True),
2357
2000
                    ]
2358
2001
 
 
2002
 
2359
2003
    def run(self, url='.', format=None):
2360
2004
        from bzrlib.upgrade import upgrade
2361
2005
        if format is None:
2366
2010
class cmd_whoami(Command):
2367
2011
    """Show or set bzr user id.
2368
2012
    
2369
 
    :Examples:
2370
 
        Show the email of the current user::
2371
 
 
2372
 
            bzr whoami --email
2373
 
 
2374
 
        Set the current user::
2375
 
 
2376
 
            bzr whoami "Frank Chu <fchu@example.com>"
 
2013
    examples:
 
2014
        bzr whoami --email
 
2015
        bzr whoami 'Frank Chu <fchu@example.com>'
2377
2016
    """
2378
2017
    takes_options = [ Option('email',
2379
 
                             help='Display email address only.'),
 
2018
                             help='display email address only'),
2380
2019
                      Option('branch',
2381
 
                             help='Set identity for the current branch instead of '
2382
 
                                  'globally.'),
 
2020
                             help='set identity for the current branch instead of '
 
2021
                                  'globally'),
2383
2022
                    ]
2384
2023
    takes_args = ['name?']
2385
2024
    encoding_type = 'replace'
2419
2058
    If unset, the tree root directory name is used as the nickname
2420
2059
    To print the current nickname, execute with no argument.  
2421
2060
    """
2422
 
 
2423
 
    _see_also = ['info']
2424
2061
    takes_args = ['nickname?']
2425
2062
    def run(self, nickname=None):
2426
2063
        branch = Branch.open_containing(u'.')[0]
2431
2068
 
2432
2069
    @display_command
2433
2070
    def printme(self, branch):
2434
 
        print branch.nick
2435
 
 
2436
 
 
2437
 
class cmd_alias(Command):
2438
 
    """Set/unset and display aliases.
2439
 
 
2440
 
    :Examples:
2441
 
        Show the current aliases::
2442
 
 
2443
 
            bzr alias
2444
 
 
2445
 
        Show the alias specified for 'll'::
2446
 
 
2447
 
            bzr alias ll
2448
 
 
2449
 
        Set an alias for 'll'::
2450
 
 
2451
 
            bzr alias ll="log --line -r-10..-1"
2452
 
 
2453
 
        To remove an alias for 'll'::
2454
 
 
2455
 
            bzr alias --remove ll
2456
 
 
2457
 
    """
2458
 
    takes_args = ['name?']
2459
 
    takes_options = [
2460
 
        Option('remove', help='Remove the alias.'),
2461
 
        ]
2462
 
 
2463
 
    def run(self, name=None, remove=False):
2464
 
        if remove:
2465
 
            self.remove_alias(name)
2466
 
        elif name is None:
2467
 
            self.print_aliases()
2468
 
        else:
2469
 
            equal_pos = name.find('=')
2470
 
            if equal_pos == -1:
2471
 
                self.print_alias(name)
2472
 
            else:
2473
 
                self.set_alias(name[:equal_pos], name[equal_pos+1:])
2474
 
 
2475
 
    def remove_alias(self, alias_name):
2476
 
        if alias_name is None:
2477
 
            raise errors.BzrCommandError(
2478
 
                'bzr alias --remove expects an alias to remove.')
2479
 
        # If alias is not found, print something like:
2480
 
        # unalias: foo: not found
2481
 
        c = config.GlobalConfig()
2482
 
        c.unset_alias(alias_name)
2483
 
 
2484
 
    @display_command
2485
 
    def print_aliases(self):
2486
 
        """Print out the defined aliases in a similar format to bash."""
2487
 
        aliases = config.GlobalConfig().get_aliases()
2488
 
        for key, value in sorted(aliases.iteritems()):
2489
 
            self.outf.write('bzr alias %s="%s"\n' % (key, value))
2490
 
 
2491
 
    @display_command
2492
 
    def print_alias(self, alias_name):
2493
 
        from bzrlib.commands import get_alias
2494
 
        alias = get_alias(alias_name)
2495
 
        if alias is None:
2496
 
            self.outf.write("bzr alias: %s: not found\n" % alias_name)
2497
 
        else:
2498
 
            self.outf.write(
2499
 
                'bzr alias %s="%s"\n' % (alias_name, ' '.join(alias)))
2500
 
 
2501
 
    def set_alias(self, alias_name, alias_command):
2502
 
        """Save the alias in the global config."""
2503
 
        c = config.GlobalConfig()
2504
 
        c.set_alias(alias_name, alias_command)
 
2071
        print branch.nick 
2505
2072
 
2506
2073
 
2507
2074
class cmd_selftest(Command):
2508
2075
    """Run internal test suite.
2509
2076
    
 
2077
    This creates temporary test directories in the working directory, but not
 
2078
    existing data is affected.  These directories are deleted if the tests
 
2079
    pass, or left behind to help in debugging if they fail and --keep-output
 
2080
    is specified.
 
2081
    
2510
2082
    If arguments are given, they are regular expressions that say which tests
2511
2083
    should run.  Tests matching any expression are run, and other tests are
2512
2084
    not run.
2515
2087
    all other tests are run.  This is useful if you have been working in a
2516
2088
    particular area, but want to make sure nothing else was broken.
2517
2089
 
2518
 
    If --exclude is given, tests that match that regular expression are
2519
 
    excluded, regardless of whether they match --first or not.
2520
 
 
2521
 
    To help catch accidential dependencies between tests, the --randomize
2522
 
    option is useful. In most cases, the argument used is the word 'now'.
2523
 
    Note that the seed used for the random number generator is displayed
2524
 
    when this option is used. The seed can be explicitly passed as the
2525
 
    argument to this option if required. This enables reproduction of the
2526
 
    actual ordering used if and when an order sensitive problem is encountered.
2527
 
 
2528
 
    If --list-only is given, the tests that would be run are listed. This is
2529
 
    useful when combined with --first, --exclude and/or --randomize to
2530
 
    understand their impact. The test harness reports "Listed nn tests in ..."
2531
 
    instead of "Ran nn tests in ..." when list mode is enabled.
2532
 
 
2533
2090
    If the global option '--no-plugins' is given, plugins are not loaded
2534
2091
    before running the selftests.  This has two effects: features provided or
2535
2092
    modified by plugins will not be tested, and tests provided by plugins will
2536
2093
    not be run.
2537
2094
 
2538
 
    Tests that need working space on disk use a common temporary directory, 
2539
 
    typically inside $TMPDIR or /tmp.
2540
 
 
2541
 
    :Examples:
2542
 
        Run only tests relating to 'ignore'::
2543
 
 
2544
 
            bzr selftest ignore
2545
 
 
2546
 
        Disable plugins and list tests as they're run::
2547
 
 
2548
 
            bzr --no-plugins selftest -v
 
2095
    examples::
 
2096
        bzr selftest ignore
 
2097
            run only tests relating to 'ignore'
 
2098
        bzr --no-plugins selftest -v
 
2099
            disable plugins and list tests as they're run
2549
2100
    """
 
2101
    # TODO: --list should give a list of all available tests
 
2102
 
2550
2103
    # NB: this is used from the class without creating an instance, which is
2551
2104
    # why it does not have a self parameter.
2552
2105
    def get_transport_type(typestring):
2567
2120
    hidden = True
2568
2121
    takes_args = ['testspecs*']
2569
2122
    takes_options = ['verbose',
2570
 
                     Option('one',
2571
 
                             help='Stop when one test fails.',
2572
 
                             short_name='1',
2573
 
                             ),
2574
 
                     Option('transport',
 
2123
                     Option('one', help='stop when one test fails'),
 
2124
                     Option('keep-output', 
 
2125
                            help='keep output directories when tests fail'),
 
2126
                     Option('transport', 
2575
2127
                            help='Use a different transport by default '
2576
2128
                                 'throughout the test suite.',
2577
2129
                            type=get_transport_type),
2578
 
                     Option('benchmark',
2579
 
                            help='Run the benchmarks rather than selftests.'),
 
2130
                     Option('benchmark', help='run the bzr bencharks.'),
2580
2131
                     Option('lsprof-timed',
2581
 
                            help='Generate lsprof output for benchmarked'
 
2132
                            help='generate lsprof output for benchmarked'
2582
2133
                                 ' sections of code.'),
2583
2134
                     Option('cache-dir', type=str,
2584
 
                            help='Cache intermediate benchmark output in this '
2585
 
                                 'directory.'),
 
2135
                            help='a directory to cache intermediate'
 
2136
                                 ' benchmark steps'),
 
2137
                     Option('clean-output',
 
2138
                            help='clean temporary tests directories'
 
2139
                                 ' without running tests'),
2586
2140
                     Option('first',
2587
 
                            help='Run all tests, but run specified tests first.',
2588
 
                            short_name='f',
2589
 
                            ),
2590
 
                     Option('list-only',
2591
 
                            help='List the tests instead of running them.'),
2592
 
                     Option('randomize', type=str, argname="SEED",
2593
 
                            help='Randomize the order of tests using the given'
2594
 
                                 ' seed or "now" for the current time.'),
2595
 
                     Option('exclude', type=str, argname="PATTERN",
2596
 
                            short_name='x',
2597
 
                            help='Exclude tests that match this regular'
2598
 
                                 ' expression.'),
2599
 
                     Option('strict', help='Fail on missing dependencies or '
2600
 
                            'known failures.'),
2601
 
                     Option('load-list', type=str, argname='TESTLISTFILE',
2602
 
                            help='Load a test id list from a text file.'),
2603
 
                     ListOption('debugflag', type=str, short_name='E',
2604
 
                                help='Turn on a selftest debug flag.'),
2605
 
                     Option('starting-with', type=str, argname='TESTID',
2606
 
                            short_name='s',
2607
 
                            help='Load only the tests starting with TESTID.'),
 
2141
                            help='run all tests, but run specified tests first',
 
2142
                            )
2608
2143
                     ]
2609
2144
    encoding_type = 'replace'
2610
2145
 
2611
 
    def run(self, testspecs_list=None, verbose=False, one=False,
2612
 
            transport=None, benchmark=None,
2613
 
            lsprof_timed=None, cache_dir=None,
2614
 
            first=False, list_only=False,
2615
 
            randomize=None, exclude=None, strict=False,
2616
 
            load_list=None, debugflag=None, starting_with=None):
 
2146
    def run(self, testspecs_list=None, verbose=None, one=False,
 
2147
            keep_output=False, transport=None, benchmark=None,
 
2148
            lsprof_timed=None, cache_dir=None, clean_output=False,
 
2149
            first=False):
2617
2150
        import bzrlib.ui
2618
2151
        from bzrlib.tests import selftest
2619
2152
        import bzrlib.benchmarks as benchmarks
2620
2153
        from bzrlib.benchmarks import tree_creator
2621
2154
 
2622
 
        # Make deprecation warnings visible, unless -Werror is set
2623
 
        symbol_versioning.activate_deprecation_warnings(override=False)
 
2155
        if clean_output:
 
2156
            from bzrlib.tests import clean_selftest_output
 
2157
            clean_selftest_output()
 
2158
            return 0
2624
2159
 
2625
2160
        if cache_dir is not None:
2626
2161
            tree_creator.TreeCreator.CACHE_ROOT = osutils.abspath(cache_dir)
2627
 
        if not list_only:
2628
 
            print 'testing: %s' % (osutils.realpath(sys.argv[0]),)
2629
 
            print '   %s (%s python%s)' % (
2630
 
                    bzrlib.__path__[0],
2631
 
                    bzrlib.version_string,
2632
 
                    bzrlib._format_version_tuple(sys.version_info),
2633
 
                    )
 
2162
        print '%10s: %s' % ('bzr', osutils.realpath(sys.argv[0]))
 
2163
        print '%10s: %s' % ('bzrlib', bzrlib.__path__[0])
2634
2164
        print
2635
2165
        if testspecs_list is not None:
2636
2166
            pattern = '|'.join(testspecs_list)
2638
2168
            pattern = ".*"
2639
2169
        if benchmark:
2640
2170
            test_suite_factory = benchmarks.test_suite
2641
 
            # Unless user explicitly asks for quiet, be verbose in benchmarks
2642
 
            verbose = not is_quiet()
 
2171
            if verbose is None:
 
2172
                verbose = True
2643
2173
            # TODO: should possibly lock the history file...
2644
2174
            benchfile = open(".perf_history", "at", buffering=1)
2645
2175
        else:
2646
2176
            test_suite_factory = None
 
2177
            if verbose is None:
 
2178
                verbose = False
2647
2179
            benchfile = None
2648
2180
        try:
2649
 
            result = selftest(verbose=verbose,
 
2181
            result = selftest(verbose=verbose, 
2650
2182
                              pattern=pattern,
2651
 
                              stop_on_failure=one,
 
2183
                              stop_on_failure=one, 
 
2184
                              keep_output=keep_output,
2652
2185
                              transport=transport,
2653
2186
                              test_suite_factory=test_suite_factory,
2654
2187
                              lsprof_timed=lsprof_timed,
2655
2188
                              bench_history=benchfile,
2656
2189
                              matching_tests_first=first,
2657
 
                              list_only=list_only,
2658
 
                              random_seed=randomize,
2659
 
                              exclude_pattern=exclude,
2660
 
                              strict=strict,
2661
 
                              load_list=load_list,
2662
 
                              debug_flags=debugflag,
2663
 
                              starting_with=starting_with,
2664
2190
                              )
2665
2191
        finally:
2666
2192
            if benchfile is not None:
2667
2193
                benchfile.close()
2668
2194
        if result:
2669
 
            note('tests passed')
 
2195
            info('tests passed')
2670
2196
        else:
2671
 
            note('tests failed')
 
2197
            info('tests failed')
2672
2198
        return int(not result)
2673
2199
 
2674
2200
 
2675
2201
class cmd_version(Command):
2676
2202
    """Show version of bzr."""
2677
2203
 
2678
 
    encoding_type = 'replace'
2679
 
    takes_options = [
2680
 
        Option("short", help="Print just the version number."),
2681
 
        ]
2682
 
 
2683
2204
    @display_command
2684
 
    def run(self, short=False):
 
2205
    def run(self):
2685
2206
        from bzrlib.version import show_version
2686
 
        if short:
2687
 
            self.outf.write(bzrlib.version_string + '\n')
2688
 
        else:
2689
 
            show_version(to_file=self.outf)
 
2207
        show_version()
2690
2208
 
2691
2209
 
2692
2210
class cmd_rocks(Command):
2696
2214
 
2697
2215
    @display_command
2698
2216
    def run(self):
2699
 
        print "It sure does!"
 
2217
        print "it sure does!"
2700
2218
 
2701
2219
 
2702
2220
class cmd_find_merge_base(Command):
2708
2226
    
2709
2227
    @display_command
2710
2228
    def run(self, branch, other):
2711
 
        from bzrlib.revision import ensure_null
 
2229
        from bzrlib.revision import MultipleRevisionSources
2712
2230
        
2713
2231
        branch1 = Branch.open_containing(branch)[0]
2714
2232
        branch2 = Branch.open_containing(other)[0]
2715
 
        branch1.lock_read()
2716
 
        try:
2717
 
            branch2.lock_read()
2718
 
            try:
2719
 
                last1 = ensure_null(branch1.last_revision())
2720
 
                last2 = ensure_null(branch2.last_revision())
2721
 
 
2722
 
                graph = branch1.repository.get_graph(branch2.repository)
2723
 
                base_rev_id = graph.find_unique_lca(last1, last2)
2724
 
 
2725
 
                print 'merge base is revision %s' % base_rev_id
2726
 
            finally:
2727
 
                branch2.unlock()
2728
 
        finally:
2729
 
            branch1.unlock()
 
2233
 
 
2234
        last1 = branch1.last_revision()
 
2235
        last2 = branch2.last_revision()
 
2236
 
 
2237
        source = MultipleRevisionSources(branch1.repository, 
 
2238
                                         branch2.repository)
 
2239
        
 
2240
        base_rev_id = common_ancestor(last1, last2, source)
 
2241
 
 
2242
        print 'merge base is revision %s' % base_rev_id
2730
2243
 
2731
2244
 
2732
2245
class cmd_merge(Command):
2733
2246
    """Perform a three-way merge.
2734
2247
    
2735
 
    The source of the merge can be specified either in the form of a branch,
2736
 
    or in the form of a path to a file containing a merge directive generated
2737
 
    with bzr send. If neither is specified, the default is the upstream branch
2738
 
    or the branch most recently merged using --remember.
2739
 
 
2740
 
    When merging a branch, by default the tip will be merged. To pick a different
2741
 
    revision, pass --revision. If you specify two values, the first will be used as
2742
 
    BASE and the second one as OTHER. Merging individual revisions, or a subset of
2743
 
    available revisions, like this is commonly referred to as "cherrypicking".
2744
 
 
2745
 
    Revision numbers are always relative to the branch being merged.
 
2248
    The branch is the branch you will merge from.  By default, it will merge
 
2249
    the latest revision.  If you specify a revision, that revision will be
 
2250
    merged.  If you specify two revisions, the first will be used as a BASE,
 
2251
    and the second one as OTHER.  Revision numbers are always relative to the
 
2252
    specified branch.
2746
2253
 
2747
2254
    By default, bzr will try to merge in all new work from the other
2748
2255
    branch, automatically determining an appropriate base.  If this
2760
2267
    default, use --remember. The value will only be saved if the remote
2761
2268
    location can be accessed.
2762
2269
 
2763
 
    The results of the merge are placed into the destination working
2764
 
    directory, where they can be reviewed (with bzr diff), tested, and then
2765
 
    committed to record the result of the merge.
 
2270
    Examples:
 
2271
 
 
2272
    To merge the latest revision from bzr.dev
 
2273
    bzr merge ../bzr.dev
 
2274
 
 
2275
    To merge changes up to and including revision 82 from bzr.dev
 
2276
    bzr merge -r 82 ../bzr.dev
 
2277
 
 
2278
    To merge the changes introduced by 82, without previous changes:
 
2279
    bzr merge -r 81..82 ../bzr.dev
2766
2280
    
2767
2281
    merge refuses to run if there are any uncommitted changes, unless
2768
2282
    --force is given.
2769
2283
 
2770
 
    :Examples:
2771
 
        To merge the latest revision from bzr.dev::
2772
 
 
2773
 
            bzr merge ../bzr.dev
2774
 
 
2775
 
        To merge changes up to and including revision 82 from bzr.dev::
2776
 
 
2777
 
            bzr merge -r 82 ../bzr.dev
2778
 
 
2779
 
        To merge the changes introduced by 82, without previous changes::
2780
 
 
2781
 
            bzr merge -r 81..82 ../bzr.dev
2782
 
 
2783
 
        To apply a merge directive contained in in /tmp/merge:
2784
 
 
2785
 
            bzr merge /tmp/merge
 
2284
    The following merge types are available:
2786
2285
    """
2787
 
 
2788
 
    encoding_type = 'exact'
2789
 
    _see_also = ['update', 'remerge', 'status-flags']
2790
 
    takes_args = ['location?']
2791
 
    takes_options = [
2792
 
        'change',
2793
 
        'revision',
2794
 
        Option('force',
2795
 
               help='Merge even if the destination tree has uncommitted changes.'),
2796
 
        'merge-type',
2797
 
        'reprocess',
2798
 
        'remember',
2799
 
        Option('show-base', help="Show base revision text in "
2800
 
               "conflicts."),
2801
 
        Option('uncommitted', help='Apply uncommitted changes'
2802
 
               ' from a working copy, instead of branch changes.'),
2803
 
        Option('pull', help='If the destination is already'
2804
 
                ' completely merged into the source, pull from the'
2805
 
                ' source rather than merging.  When this happens,'
2806
 
                ' you do not need to commit the result.'),
2807
 
        Option('directory',
2808
 
               help='Branch to merge into, '
2809
 
                    'rather than the one containing the working directory.',
2810
 
               short_name='d',
2811
 
               type=unicode,
2812
 
               ),
2813
 
        Option('preview', help='Instead of merging, show a diff of the merge.')
2814
 
    ]
2815
 
 
2816
 
    def run(self, location=None, revision=None, force=False,
2817
 
            merge_type=None, show_base=False, reprocess=False, remember=False,
2818
 
            uncommitted=False, pull=False,
2819
 
            directory=None,
2820
 
            preview=False,
2821
 
            ):
 
2286
    takes_args = ['branch?']
 
2287
    takes_options = ['revision', 'force', 'merge-type', 'reprocess', 'remember',
 
2288
                     Option('show-base', help="Show base revision text in "
 
2289
                            "conflicts"),
 
2290
                     Option('uncommitted', help='Apply uncommitted changes'
 
2291
                            ' from a working copy, instead of branch changes'),
 
2292
                     Option('pull', help='If the destination is already'
 
2293
                             ' completely merged into the source, pull from the'
 
2294
                             ' source rather than merging. When this happens,'
 
2295
                             ' you do not need to commit the result.'),
 
2296
                     ]
 
2297
 
 
2298
    def help(self):
 
2299
        from inspect import getdoc
 
2300
        return getdoc(self) + '\n' + _mod_merge.merge_type_help()
 
2301
 
 
2302
    def run(self, branch=None, revision=None, force=False, merge_type=None,
 
2303
            show_base=False, reprocess=False, remember=False, 
 
2304
            uncommitted=False, pull=False):
2822
2305
        if merge_type is None:
2823
2306
            merge_type = _mod_merge.Merge3Merger
2824
2307
 
2825
 
        if directory is None: directory = u'.'
2826
 
        possible_transports = []
2827
 
        merger = None
2828
 
        allow_pending = True
2829
 
        verified = 'inapplicable'
2830
 
        tree = WorkingTree.open_containing(directory)[0]
2831
 
        change_reporter = delta._ChangeReporter(
2832
 
            unversioned_filter=tree.is_ignored)
2833
 
        cleanups = []
2834
 
        try:
2835
 
            pb = ui.ui_factory.nested_progress_bar()
2836
 
            cleanups.append(pb.finished)
2837
 
            tree.lock_write()
2838
 
            cleanups.append(tree.unlock)
2839
 
            if location is not None:
2840
 
                try:
2841
 
                    mergeable = bundle.read_mergeable_from_url(location,
2842
 
                        possible_transports=possible_transports)
2843
 
                except errors.NotABundle:
2844
 
                    mergeable = None
 
2308
        tree = WorkingTree.open_containing(u'.')[0]
 
2309
 
 
2310
        if branch is not None:
 
2311
            try:
 
2312
                reader = bundle.read_bundle_from_url(branch)
 
2313
            except errors.NotABundle:
 
2314
                pass # Continue on considering this url a Branch
 
2315
            else:
 
2316
                conflicts = merge_bundle(reader, tree, not force, merge_type,
 
2317
                                            reprocess, show_base)
 
2318
                if conflicts == 0:
 
2319
                    return 0
2845
2320
                else:
2846
 
                    if uncommitted:
2847
 
                        raise errors.BzrCommandError('Cannot use --uncommitted'
2848
 
                            ' with bundles or merge directives.')
2849
 
 
2850
 
                    if revision is not None:
2851
 
                        raise errors.BzrCommandError(
2852
 
                            'Cannot use -r with merge directives or bundles')
2853
 
                    merger, verified = _mod_merge.Merger.from_mergeable(tree,
2854
 
                       mergeable, pb)
2855
 
 
2856
 
            if merger is None and uncommitted:
2857
 
                if revision is not None and len(revision) > 0:
2858
 
                    raise errors.BzrCommandError('Cannot use --uncommitted and'
2859
 
                        ' --revision at the same time.')
2860
 
                location = self._select_branch_location(tree, location)[0]
2861
 
                other_tree, other_path = WorkingTree.open_containing(location)
2862
 
                merger = _mod_merge.Merger.from_uncommitted(tree, other_tree,
2863
 
                    pb)
2864
 
                allow_pending = False
2865
 
                if other_path != '':
2866
 
                    merger.interesting_files = [other_path]
2867
 
 
2868
 
            if merger is None:
2869
 
                merger, allow_pending = self._get_merger_from_branch(tree,
2870
 
                    location, revision, remember, possible_transports, pb)
2871
 
 
2872
 
            merger.merge_type = merge_type
2873
 
            merger.reprocess = reprocess
2874
 
            merger.show_base = show_base
2875
 
            self.sanity_check_merger(merger)
2876
 
            if (merger.base_rev_id == merger.other_rev_id and
2877
 
                merger.other_rev_id is not None):
2878
 
                note('Nothing to do.')
 
2321
                    return 1
 
2322
 
 
2323
        if revision is None \
 
2324
                or len(revision) < 1 or revision[0].needs_branch():
 
2325
            branch = self._get_remembered_parent(tree, branch, 'Merging from')
 
2326
 
 
2327
        if revision is None or len(revision) < 1:
 
2328
            if uncommitted:
 
2329
                base = [branch, -1]
 
2330
                other = [branch, None]
 
2331
            else:
 
2332
                base = [None, None]
 
2333
                other = [branch, -1]
 
2334
            other_branch, path = Branch.open_containing(branch)
 
2335
        else:
 
2336
            if uncommitted:
 
2337
                raise errors.BzrCommandError('Cannot use --uncommitted and'
 
2338
                                             ' --revision at the same time.')
 
2339
            branch = revision[0].get_branch() or branch
 
2340
            if len(revision) == 1:
 
2341
                base = [None, None]
 
2342
                other_branch, path = Branch.open_containing(branch)
 
2343
                revno = revision[0].in_history(other_branch).revno
 
2344
                other = [branch, revno]
 
2345
            else:
 
2346
                assert len(revision) == 2
 
2347
                if None in revision:
 
2348
                    raise errors.BzrCommandError(
 
2349
                        "Merge doesn't permit empty revision specifier.")
 
2350
                base_branch, path = Branch.open_containing(branch)
 
2351
                branch1 = revision[1].get_branch() or branch
 
2352
                other_branch, path1 = Branch.open_containing(branch1)
 
2353
                if revision[0].get_branch() is not None:
 
2354
                    # then path was obtained from it, and is None.
 
2355
                    path = path1
 
2356
 
 
2357
                base = [branch, revision[0].in_history(base_branch).revno]
 
2358
                other = [branch1, revision[1].in_history(other_branch).revno]
 
2359
 
 
2360
        if tree.branch.get_parent() is None or remember:
 
2361
            tree.branch.set_parent(other_branch.base)
 
2362
 
 
2363
        if path != "":
 
2364
            interesting_files = [path]
 
2365
        else:
 
2366
            interesting_files = None
 
2367
        pb = ui.ui_factory.nested_progress_bar()
 
2368
        try:
 
2369
            try:
 
2370
                conflict_count = _merge_helper(
 
2371
                    other, base, check_clean=(not force),
 
2372
                    merge_type=merge_type,
 
2373
                    reprocess=reprocess,
 
2374
                    show_base=show_base,
 
2375
                    pull=pull,
 
2376
                    pb=pb, file_list=interesting_files)
 
2377
            finally:
 
2378
                pb.finished()
 
2379
            if conflict_count != 0:
 
2380
                return 1
 
2381
            else:
2879
2382
                return 0
2880
 
            if pull:
2881
 
                if merger.interesting_files is not None:
2882
 
                    raise errors.BzrCommandError('Cannot pull individual files')
2883
 
                if (merger.base_rev_id == tree.last_revision()):
2884
 
                    result = tree.pull(merger.other_branch, False,
2885
 
                                       merger.other_rev_id)
2886
 
                    result.report(self.outf)
2887
 
                    return 0
2888
 
            merger.check_basis(not force)
2889
 
            if preview:
2890
 
                return self._do_preview(merger)
2891
 
            else:
2892
 
                return self._do_merge(merger, change_reporter, allow_pending,
2893
 
                                      verified)
2894
 
        finally:
2895
 
            for cleanup in reversed(cleanups):
2896
 
                cleanup()
2897
 
 
2898
 
    def _do_preview(self, merger):
2899
 
        from bzrlib.diff import show_diff_trees
2900
 
        tree_merger = merger.make_merger()
2901
 
        tt = tree_merger.make_preview_transform()
2902
 
        try:
2903
 
            result_tree = tt.get_preview_tree()
2904
 
            show_diff_trees(merger.this_tree, result_tree, self.outf,
2905
 
                            old_label='', new_label='')
2906
 
        finally:
2907
 
            tt.finalize()
2908
 
 
2909
 
    def _do_merge(self, merger, change_reporter, allow_pending, verified):
2910
 
        merger.change_reporter = change_reporter
2911
 
        conflict_count = merger.do_merge()
2912
 
        if allow_pending:
2913
 
            merger.set_pending()
2914
 
        if verified == 'failed':
2915
 
            warning('Preview patch does not match changes')
2916
 
        if conflict_count != 0:
2917
 
            return 1
2918
 
        else:
2919
 
            return 0
2920
 
 
2921
 
    def sanity_check_merger(self, merger):
2922
 
        if (merger.show_base and
2923
 
            not merger.merge_type is _mod_merge.Merge3Merger):
2924
 
            raise errors.BzrCommandError("Show-base is not supported for this"
2925
 
                                         " merge type. %s" % merger.merge_type)
2926
 
        if merger.reprocess and not merger.merge_type.supports_reprocess:
2927
 
            raise errors.BzrCommandError("Conflict reduction is not supported"
2928
 
                                         " for merge type %s." %
2929
 
                                         merger.merge_type)
2930
 
        if merger.reprocess and merger.show_base:
2931
 
            raise errors.BzrCommandError("Cannot do conflict reduction and"
2932
 
                                         " show base.")
2933
 
 
2934
 
    def _get_merger_from_branch(self, tree, location, revision, remember,
2935
 
                                possible_transports, pb):
2936
 
        """Produce a merger from a location, assuming it refers to a branch."""
2937
 
        from bzrlib.tag import _merge_tags_if_possible
2938
 
        # find the branch locations
2939
 
        other_loc, user_location = self._select_branch_location(tree, location,
2940
 
            revision, -1)
2941
 
        if revision is not None and len(revision) == 2:
2942
 
            base_loc, _unused = self._select_branch_location(tree,
2943
 
                location, revision, 0)
2944
 
        else:
2945
 
            base_loc = other_loc
2946
 
        # Open the branches
2947
 
        other_branch, other_path = Branch.open_containing(other_loc,
2948
 
            possible_transports)
2949
 
        if base_loc == other_loc:
2950
 
            base_branch = other_branch
2951
 
        else:
2952
 
            base_branch, base_path = Branch.open_containing(base_loc,
2953
 
                possible_transports)
2954
 
        # Find the revision ids
2955
 
        if revision is None or len(revision) < 1 or revision[-1] is None:
2956
 
            other_revision_id = _mod_revision.ensure_null(
2957
 
                other_branch.last_revision())
2958
 
        else:
2959
 
            other_revision_id = revision[-1].as_revision_id(other_branch)
2960
 
        if (revision is not None and len(revision) == 2
2961
 
            and revision[0] is not None):
2962
 
            base_revision_id = revision[0].as_revision_id(base_branch)
2963
 
        else:
2964
 
            base_revision_id = None
2965
 
        # Remember where we merge from
2966
 
        if ((remember or tree.branch.get_submit_branch() is None) and
2967
 
             user_location is not None):
2968
 
            tree.branch.set_submit_branch(other_branch.base)
2969
 
        _merge_tags_if_possible(other_branch, tree.branch)
2970
 
        merger = _mod_merge.Merger.from_revision_ids(pb, tree,
2971
 
            other_revision_id, base_revision_id, other_branch, base_branch)
2972
 
        if other_path != '':
2973
 
            allow_pending = False
2974
 
            merger.interesting_files = [other_path]
2975
 
        else:
2976
 
            allow_pending = True
2977
 
        return merger, allow_pending
2978
 
 
2979
 
    def _select_branch_location(self, tree, user_location, revision=None,
2980
 
                                index=None):
2981
 
        """Select a branch location, according to possible inputs.
2982
 
 
2983
 
        If provided, branches from ``revision`` are preferred.  (Both
2984
 
        ``revision`` and ``index`` must be supplied.)
2985
 
 
2986
 
        Otherwise, the ``location`` parameter is used.  If it is None, then the
2987
 
        ``submit`` or ``parent`` location is used, and a note is printed.
2988
 
 
2989
 
        :param tree: The working tree to select a branch for merging into
2990
 
        :param location: The location entered by the user
2991
 
        :param revision: The revision parameter to the command
2992
 
        :param index: The index to use for the revision parameter.  Negative
2993
 
            indices are permitted.
2994
 
        :return: (selected_location, user_location).  The default location
2995
 
            will be the user-entered location.
2996
 
        """
2997
 
        if (revision is not None and index is not None
2998
 
            and revision[index] is not None):
2999
 
            branch = revision[index].get_branch()
3000
 
            if branch is not None:
3001
 
                return branch, branch
3002
 
        if user_location is None:
3003
 
            location = self._get_remembered(tree, 'Merging from')
3004
 
        else:
3005
 
            location = user_location
3006
 
        return location, user_location
3007
 
 
3008
 
    def _get_remembered(self, tree, verb_string):
 
2383
        except errors.AmbiguousBase, e:
 
2384
            m = ("sorry, bzr can't determine the right merge base yet\n"
 
2385
                 "candidates are:\n  "
 
2386
                 + "\n  ".join(e.bases)
 
2387
                 + "\n"
 
2388
                 "please specify an explicit base with -r,\n"
 
2389
                 "and (if you want) report this to the bzr developers\n")
 
2390
            log_error(m)
 
2391
 
 
2392
    # TODO: move up to common parent; this isn't merge-specific anymore. 
 
2393
    def _get_remembered_parent(self, tree, supplied_location, verb_string):
3009
2394
        """Use tree.branch's parent if none was supplied.
3010
2395
 
3011
2396
        Report if the remembered location was used.
3012
2397
        """
3013
 
        stored_location = tree.branch.get_submit_branch()
3014
 
        if stored_location is None:
3015
 
            stored_location = tree.branch.get_parent()
 
2398
        if supplied_location is not None:
 
2399
            return supplied_location
 
2400
        stored_location = tree.branch.get_parent()
3016
2401
        mutter("%s", stored_location)
3017
2402
        if stored_location is None:
3018
2403
            raise errors.BzrCommandError("No location specified or remembered")
3019
 
        display_url = urlutils.unescape_for_display(stored_location, 'utf-8')
3020
 
        note(u"%s remembered location %s", verb_string, display_url)
 
2404
        display_url = urlutils.unescape_for_display(stored_location, self.outf.encoding)
 
2405
        self.outf.write("%s remembered location %s\n" % (verb_string, display_url))
3021
2406
        return stored_location
3022
2407
 
3023
2408
 
3032
2417
    merge.  The difference is that remerge can (only) be run when there is a
3033
2418
    pending merge, and it lets you specify particular files.
3034
2419
 
3035
 
    :Examples:
 
2420
    Examples:
 
2421
    $ bzr remerge --show-base
3036
2422
        Re-do the merge of all conflicted files, and show the base text in
3037
 
        conflict regions, in addition to the usual THIS and OTHER texts::
3038
 
      
3039
 
            bzr remerge --show-base
 
2423
        conflict regions, in addition to the usual THIS and OTHER texts.
3040
2424
 
 
2425
    $ bzr remerge --merge-type weave --reprocess foobar
3041
2426
        Re-do the merge of "foobar", using the weave merge algorithm, with
3042
 
        additional processing to reduce the size of conflict regions::
3043
 
      
3044
 
            bzr remerge --merge-type weave --reprocess foobar
3045
 
    """
 
2427
        additional processing to reduce the size of conflict regions.
 
2428
    
 
2429
    The following merge types are available:"""
3046
2430
    takes_args = ['file*']
3047
 
    takes_options = [
3048
 
            'merge-type',
3049
 
            'reprocess',
3050
 
            Option('show-base',
3051
 
                   help="Show base revision text in conflicts."),
3052
 
            ]
 
2431
    takes_options = ['merge-type', 'reprocess',
 
2432
                     Option('show-base', help="Show base revision text in "
 
2433
                            "conflicts")]
 
2434
 
 
2435
    def help(self):
 
2436
        from inspect import getdoc
 
2437
        return getdoc(self) + '\n' + _mod_merge.merge_type_help()
3053
2438
 
3054
2439
    def run(self, file_list=None, merge_type=None, show_base=False,
3055
2440
            reprocess=False):
3064
2449
                                             " merges.  Not cherrypicking or"
3065
2450
                                             " multi-merges.")
3066
2451
            repository = tree.branch.repository
 
2452
            base_revision = common_ancestor(parents[0],
 
2453
                                            parents[1], repository)
 
2454
            base_tree = repository.revision_tree(base_revision)
 
2455
            other_tree = repository.revision_tree(parents[1])
3067
2456
            interesting_ids = None
3068
2457
            new_conflicts = []
3069
2458
            conflicts = tree.conflicts()
3094
2483
                    restore(tree.abspath(filename))
3095
2484
                except errors.NotConflicted:
3096
2485
                    pass
3097
 
            # Disable pending merges, because the file texts we are remerging
3098
 
            # have not had those merges performed.  If we use the wrong parents
3099
 
            # list, we imply that the working tree text has seen and rejected
3100
 
            # all the changes from the other tree, when in fact those changes
3101
 
            # have not yet been seen.
3102
 
            pb = ui.ui_factory.nested_progress_bar()
3103
 
            tree.set_parent_ids(parents[:1])
3104
 
            try:
3105
 
                merger = _mod_merge.Merger.from_revision_ids(pb,
3106
 
                                                             tree, parents[1])
3107
 
                merger.interesting_ids = interesting_ids
3108
 
                merger.merge_type = merge_type
3109
 
                merger.show_base = show_base
3110
 
                merger.reprocess = reprocess
3111
 
                conflicts = merger.do_merge()
3112
 
            finally:
3113
 
                tree.set_parent_ids(parents)
3114
 
                pb.finished()
 
2486
            conflicts = _mod_merge.merge_inner(
 
2487
                                      tree.branch, other_tree, base_tree,
 
2488
                                      this_tree=tree,
 
2489
                                      interesting_ids=interesting_ids,
 
2490
                                      other_rev_id=parents[1],
 
2491
                                      merge_type=merge_type,
 
2492
                                      show_base=show_base,
 
2493
                                      reprocess=reprocess)
3115
2494
        finally:
3116
2495
            tree.unlock()
3117
2496
        if conflicts > 0:
3128
2507
    last committed revision is used.
3129
2508
 
3130
2509
    To remove only some changes, without reverting to a prior version, use
3131
 
    merge instead.  For example, "merge . --revision -2..-3" will remove the
3132
 
    changes introduced by -2, without affecting the changes introduced by -1.
3133
 
    Or to remove certain changes on a hunk-by-hunk basis, see the Shelf plugin.
 
2510
    merge instead.  For example, "merge . --r-2..-3" will remove the changes
 
2511
    introduced by -2, without affecting the changes introduced by -1.  Or
 
2512
    to remove certain changes on a hunk-by-hunk basis, see the Shelf plugin.
3134
2513
    
3135
2514
    By default, any files that have been manually changed will be backed up
3136
2515
    first.  (Files changed only by merge are not backed up.)  Backup files have
3140
2519
    from the target revision.  So you can use revert to "undelete" a file by
3141
2520
    name.  If you name a directory, all the contents of that directory will be
3142
2521
    reverted.
3143
 
 
3144
 
    Any files that have been newly added since that revision will be deleted,
3145
 
    with a backup kept if appropriate.  Directories containing unknown files
3146
 
    will not be deleted.
3147
 
 
3148
 
    The working tree contains a list of pending merged revisions, which will
3149
 
    be included as parents in the next commit.  Normally, revert clears that
3150
 
    list as well as reverting the files.  If any files are specified, revert
3151
 
    leaves the pending merge list alone and reverts only the files.  Use "bzr
3152
 
    revert ." in the tree root to revert all files but keep the merge record,
3153
 
    and "bzr revert --forget-merges" to clear the pending merge list without
3154
 
    reverting any files.
3155
2522
    """
3156
 
 
3157
 
    _see_also = ['cat', 'export']
3158
 
    takes_options = [
3159
 
        'revision',
3160
 
        Option('no-backup', "Do not save backups of reverted files."),
3161
 
        Option('forget-merges',
3162
 
               'Remove pending merge marker, without changing any files.'),
3163
 
        ]
 
2523
    takes_options = ['revision', 'no-backup']
3164
2524
    takes_args = ['file*']
 
2525
    aliases = ['merge-revert']
3165
2526
 
3166
 
    def run(self, revision=None, no_backup=False, file_list=None,
3167
 
            forget_merges=None):
 
2527
    def run(self, revision=None, no_backup=False, file_list=None):
 
2528
        if file_list is not None:
 
2529
            if len(file_list) == 0:
 
2530
                raise errors.BzrCommandError("No files specified")
 
2531
        else:
 
2532
            file_list = []
 
2533
        
3168
2534
        tree, file_list = tree_files(file_list)
3169
 
        if forget_merges:
3170
 
            tree.set_parent_ids(tree.get_parent_ids()[:1])
3171
 
        else:
3172
 
            self._revert_tree_to_revision(tree, revision, file_list, no_backup)
3173
 
 
3174
 
    @staticmethod
3175
 
    def _revert_tree_to_revision(tree, revision, file_list, no_backup):
3176
2535
        if revision is None:
 
2536
            # FIXME should be tree.last_revision
3177
2537
            rev_id = tree.last_revision()
3178
2538
        elif len(revision) != 1:
3179
2539
            raise errors.BzrCommandError('bzr revert --revision takes exactly 1 argument')
3180
2540
        else:
3181
 
            rev_id = revision[0].as_revision_id(tree.branch)
 
2541
            rev_id = revision[0].in_history(tree.branch).rev_id
3182
2542
        pb = ui.ui_factory.nested_progress_bar()
3183
2543
        try:
3184
 
            tree.revert(file_list,
 
2544
            tree.revert(file_list, 
3185
2545
                        tree.branch.repository.revision_tree(rev_id),
3186
2546
                        not no_backup, pb, report_changes=True)
3187
2547
        finally:
3200
2560
 
3201
2561
class cmd_help(Command):
3202
2562
    """Show help on a command or other topic.
 
2563
 
 
2564
    For a list of all available commands, say 'bzr help commands'.
3203
2565
    """
3204
 
 
3205
 
    _see_also = ['topics']
3206
 
    takes_options = [
3207
 
            Option('long', 'Show help on all commands.'),
3208
 
            ]
 
2566
    takes_options = [Option('long', 'show help on all commands')]
3209
2567
    takes_args = ['topic?']
3210
2568
    aliases = ['?', '--help', '-?', '-h']
3211
2569
    
3232
2590
        shellcomplete.shellcomplete(context)
3233
2591
 
3234
2592
 
 
2593
class cmd_fetch(Command):
 
2594
    """Copy in history from another branch but don't merge it.
 
2595
 
 
2596
    This is an internal method used for pull and merge.
 
2597
    """
 
2598
    hidden = True
 
2599
    takes_args = ['from_branch', 'to_branch']
 
2600
    def run(self, from_branch, to_branch):
 
2601
        from bzrlib.fetch import Fetcher
 
2602
        from_b = Branch.open(from_branch)
 
2603
        to_b = Branch.open(to_branch)
 
2604
        Fetcher(to_b, from_b)
 
2605
 
 
2606
 
3235
2607
class cmd_missing(Command):
3236
2608
    """Show unmerged/unpulled revisions between two branches.
3237
 
    
 
2609
 
3238
2610
    OTHER_BRANCH may be local or remote.
3239
2611
    """
3240
 
 
3241
 
    _see_also = ['merge', 'pull']
3242
2612
    takes_args = ['other_branch?']
3243
 
    takes_options = [
3244
 
            Option('reverse', 'Reverse the order of revisions.'),
3245
 
            Option('mine-only',
3246
 
                   'Display changes in the local branch only.'),
3247
 
            Option('this' , 'Same as --mine-only.'),
3248
 
            Option('theirs-only',
3249
 
                   'Display changes in the remote branch only.'),
3250
 
            Option('other', 'Same as --theirs-only.'),
3251
 
            'log-format',
3252
 
            'show-ids',
3253
 
            'verbose'
3254
 
            ]
 
2613
    takes_options = [Option('reverse', 'Reverse the order of revisions'),
 
2614
                     Option('mine-only', 
 
2615
                            'Display changes in the local branch only'),
 
2616
                     Option('theirs-only', 
 
2617
                            'Display changes in the remote branch only'), 
 
2618
                     'log-format',
 
2619
                     'line',
 
2620
                     'long', 
 
2621
                     'short',
 
2622
                     'show-ids',
 
2623
                     'verbose'
 
2624
                     ]
3255
2625
    encoding_type = 'replace'
3256
2626
 
3257
2627
    @display_command
3258
2628
    def run(self, other_branch=None, reverse=False, mine_only=False,
3259
2629
            theirs_only=False, log_format=None, long=False, short=False, line=False, 
3260
 
            show_ids=False, verbose=False, this=False, other=False):
3261
 
        from bzrlib.missing import find_unmerged, iter_log_revisions
3262
 
 
3263
 
        if this:
3264
 
            mine_only = this
3265
 
        if other:
3266
 
            theirs_only = other
3267
 
        # TODO: We should probably check that we don't have mine-only and
3268
 
        #       theirs-only set, but it gets complicated because we also have
3269
 
        #       this and other which could be used.
3270
 
        restrict = 'all'
3271
 
        if mine_only:
3272
 
            restrict = 'local'
3273
 
        elif theirs_only:
3274
 
            restrict = 'remote'
3275
 
 
 
2630
            show_ids=False, verbose=False):
 
2631
        from bzrlib.missing import find_unmerged, iter_log_data
 
2632
        from bzrlib.log import log_formatter
3276
2633
        local_branch = Branch.open_containing(u".")[0]
3277
2634
        parent = local_branch.get_parent()
3278
2635
        if other_branch is None:
3279
2636
            other_branch = parent
3280
2637
            if other_branch is None:
3281
 
                raise errors.BzrCommandError("No peer location known"
3282
 
                                             " or specified.")
 
2638
                raise errors.BzrCommandError("No peer location known or specified.")
3283
2639
            display_url = urlutils.unescape_for_display(parent,
3284
2640
                                                        self.outf.encoding)
3285
 
            self.outf.write("Using last location: " + display_url + "\n")
 
2641
            print "Using last location: " + display_url
3286
2642
 
3287
2643
        remote_branch = Branch.open(other_branch)
3288
2644
        if remote_branch.base == local_branch.base:
3291
2647
        try:
3292
2648
            remote_branch.lock_read()
3293
2649
            try:
3294
 
                local_extra, remote_extra = find_unmerged(
3295
 
                    local_branch, remote_branch, restrict)
3296
 
 
3297
 
                if log_format is None:
3298
 
                    registry = log.log_formatter_registry
3299
 
                    log_format = registry.get_default(local_branch)
3300
 
                lf = log_format(to_file=self.outf,
3301
 
                                show_ids=show_ids,
3302
 
                                show_timezone='original')
 
2650
                local_extra, remote_extra = find_unmerged(local_branch, remote_branch)
 
2651
                if (log_format is None):
 
2652
                    default = local_branch.get_config().log_format()
 
2653
                    log_format = get_log_format(long=long, short=short, 
 
2654
                                                line=line, default=default)
 
2655
                lf = log_formatter(log_format,
 
2656
                                   to_file=self.outf,
 
2657
                                   show_ids=show_ids,
 
2658
                                   show_timezone='original')
3303
2659
                if reverse is False:
3304
 
                    if local_extra is not None:
3305
 
                        local_extra.reverse()
3306
 
                    if remote_extra is not None:
3307
 
                        remote_extra.reverse()
3308
 
 
3309
 
                status_code = 0
 
2660
                    local_extra.reverse()
 
2661
                    remote_extra.reverse()
3310
2662
                if local_extra and not theirs_only:
3311
 
                    self.outf.write("You have %d extra revision(s):\n" %
3312
 
                                    len(local_extra))
3313
 
                    for revision in iter_log_revisions(local_extra,
3314
 
                                        local_branch.repository,
3315
 
                                        verbose):
3316
 
                        lf.log_revision(revision)
 
2663
                    print "You have %d extra revision(s):" % len(local_extra)
 
2664
                    for data in iter_log_data(local_extra, local_branch.repository,
 
2665
                                              verbose):
 
2666
                        lf.show(*data)
3317
2667
                    printed_local = True
3318
 
                    status_code = 1
3319
2668
                else:
3320
2669
                    printed_local = False
3321
 
 
3322
2670
                if remote_extra and not mine_only:
3323
2671
                    if printed_local is True:
3324
 
                        self.outf.write("\n\n\n")
3325
 
                    self.outf.write("You are missing %d revision(s):\n" %
3326
 
                                    len(remote_extra))
3327
 
                    for revision in iter_log_revisions(remote_extra,
3328
 
                                        remote_branch.repository,
3329
 
                                        verbose):
3330
 
                        lf.log_revision(revision)
 
2672
                        print "\n\n"
 
2673
                    print "You are missing %d revision(s):" % len(remote_extra)
 
2674
                    for data in iter_log_data(remote_extra, remote_branch.repository, 
 
2675
                                              verbose):
 
2676
                        lf.show(*data)
 
2677
                if not remote_extra and not local_extra:
 
2678
                    status_code = 0
 
2679
                    print "Branches are up to date."
 
2680
                else:
3331
2681
                    status_code = 1
3332
 
 
3333
 
                if mine_only and not local_extra:
3334
 
                    # We checked local, and found nothing extra
3335
 
                    self.outf.write('This branch is up to date.\n')
3336
 
                elif theirs_only and not remote_extra:
3337
 
                    # We checked remote, and found nothing extra
3338
 
                    self.outf.write('Other branch is up to date.\n')
3339
 
                elif not (mine_only or theirs_only or local_extra or
3340
 
                          remote_extra):
3341
 
                    # We checked both branches, and neither one had extra
3342
 
                    # revisions
3343
 
                    self.outf.write("Branches are up to date.\n")
3344
2682
            finally:
3345
2683
                remote_branch.unlock()
3346
2684
        finally:
3356
2694
        return status_code
3357
2695
 
3358
2696
 
3359
 
class cmd_pack(Command):
3360
 
    """Compress the data within a repository."""
3361
 
 
3362
 
    _see_also = ['repositories']
3363
 
    takes_args = ['branch_or_repo?']
3364
 
 
3365
 
    def run(self, branch_or_repo='.'):
3366
 
        dir = bzrdir.BzrDir.open_containing(branch_or_repo)[0]
3367
 
        try:
3368
 
            branch = dir.open_branch()
3369
 
            repository = branch.repository
3370
 
        except errors.NotBranchError:
3371
 
            repository = dir.open_repository()
3372
 
        repository.pack()
3373
 
 
3374
 
 
3375
2697
class cmd_plugins(Command):
3376
 
    """List the installed plugins.
3377
 
    
3378
 
    This command displays the list of installed plugins including
3379
 
    version of plugin and a short description of each.
3380
 
 
3381
 
    --verbose shows the path where each plugin is located.
3382
 
 
3383
 
    A plugin is an external component for Bazaar that extends the
3384
 
    revision control system, by adding or replacing code in Bazaar.
3385
 
    Plugins can do a variety of things, including overriding commands,
3386
 
    adding new commands, providing additional network transports and
3387
 
    customizing log output.
3388
 
 
3389
 
    See the Bazaar web site, http://bazaar-vcs.org, for further
3390
 
    information on plugins including where to find them and how to
3391
 
    install them. Instructions are also provided there on how to
3392
 
    write new plugins using the Python programming language.
3393
 
    """
3394
 
    takes_options = ['verbose']
3395
 
 
 
2698
    """List plugins"""
 
2699
    hidden = True
3396
2700
    @display_command
3397
 
    def run(self, verbose=False):
 
2701
    def run(self):
3398
2702
        import bzrlib.plugin
3399
2703
        from inspect import getdoc
3400
 
        result = []
3401
 
        for name, plugin in bzrlib.plugin.plugins().items():
3402
 
            version = plugin.__version__
3403
 
            if version == 'unknown':
3404
 
                version = ''
3405
 
            name_ver = '%s %s' % (name, version)
3406
 
            d = getdoc(plugin.module)
 
2704
        for name, plugin in bzrlib.plugin.all_plugins().items():
 
2705
            if getattr(plugin, '__path__', None) is not None:
 
2706
                print plugin.__path__[0]
 
2707
            elif getattr(plugin, '__file__', None) is not None:
 
2708
                print plugin.__file__
 
2709
            else:
 
2710
                print repr(plugin)
 
2711
                
 
2712
            d = getdoc(plugin)
3407
2713
            if d:
3408
 
                doc = d.split('\n')[0]
3409
 
            else:
3410
 
                doc = '(no description)'
3411
 
            result.append((name_ver, doc, plugin.path()))
3412
 
        for name_ver, doc, path in sorted(result):
3413
 
            print name_ver
3414
 
            print '   ', doc
3415
 
            if verbose:
3416
 
                print '   ', path
3417
 
            print
 
2714
                print '\t', d.split('\n')[0]
3418
2715
 
3419
2716
 
3420
2717
class cmd_testament(Command):
3421
2718
    """Show testament (signing-form) of a revision."""
3422
 
    takes_options = [
3423
 
            'revision',
3424
 
            Option('long', help='Produce long-format testament.'),
3425
 
            Option('strict',
3426
 
                   help='Produce a strict-format testament.')]
 
2719
    takes_options = ['revision', 
 
2720
                     Option('long', help='Produce long-format testament'), 
 
2721
                     Option('strict', help='Produce a strict-format'
 
2722
                            ' testament')]
3427
2723
    takes_args = ['branch?']
3428
2724
    @display_command
3429
2725
    def run(self, branch=u'.', revision=None, long=False, strict=False):
3432
2728
            testament_class = StrictTestament
3433
2729
        else:
3434
2730
            testament_class = Testament
3435
 
        if branch == '.':
3436
 
            b = Branch.open_containing(branch)[0]
3437
 
        else:
3438
 
            b = Branch.open(branch)
 
2731
        b = WorkingTree.open_containing(branch)[0].branch
3439
2732
        b.lock_read()
3440
2733
        try:
3441
2734
            if revision is None:
3442
2735
                rev_id = b.last_revision()
3443
2736
            else:
3444
 
                rev_id = revision[0].as_revision_id(b)
 
2737
                rev_id = revision[0].in_history(b).rev_id
3445
2738
            t = testament_class.from_revision(b.repository, rev_id)
3446
2739
            if long:
3447
2740
                sys.stdout.writelines(t.as_text_lines())
3465
2758
    #       with new uncommitted lines marked
3466
2759
    aliases = ['ann', 'blame', 'praise']
3467
2760
    takes_args = ['filename']
3468
 
    takes_options = [Option('all', help='Show annotations on all lines.'),
3469
 
                     Option('long', help='Show commit date in annotations.'),
 
2761
    takes_options = [Option('all', help='show annotations on all lines'),
 
2762
                     Option('long', help='show date in annotations'),
3470
2763
                     'revision',
3471
2764
                     'show-ids',
3472
2765
                     ]
3473
 
    encoding_type = 'exact'
3474
2766
 
3475
2767
    @display_command
3476
2768
    def run(self, filename, all=False, long=False, revision=None,
3477
2769
            show_ids=False):
3478
2770
        from bzrlib.annotate import annotate_file
3479
 
        wt, branch, relpath = \
3480
 
            bzrdir.BzrDir.open_containing_tree_or_branch(filename)
3481
 
        if wt is not None:
3482
 
            wt.lock_read()
3483
 
        else:
3484
 
            branch.lock_read()
 
2771
        tree, relpath = WorkingTree.open_containing(filename)
 
2772
        branch = tree.branch
 
2773
        branch.lock_read()
3485
2774
        try:
3486
2775
            if revision is None:
3487
2776
                revision_id = branch.last_revision()
3488
2777
            elif len(revision) != 1:
3489
2778
                raise errors.BzrCommandError('bzr annotate --revision takes exactly 1 argument')
3490
2779
            else:
3491
 
                revision_id = revision[0].as_revision_id(branch)
 
2780
                revision_id = revision[0].in_history(branch).rev_id
 
2781
            file_id = tree.inventory.path2id(relpath)
3492
2782
            tree = branch.repository.revision_tree(revision_id)
3493
 
            if wt is not None:
3494
 
                file_id = wt.path2id(relpath)
3495
 
            else:
3496
 
                file_id = tree.path2id(relpath)
3497
 
            if file_id is None:
3498
 
                raise errors.NotVersionedError(filename)
3499
2783
            file_version = tree.inventory[file_id].revision
3500
 
            annotate_file(branch, file_version, file_id, long, all, self.outf,
 
2784
            annotate_file(branch, file_version, file_id, long, all, sys.stdout,
3501
2785
                          show_ids=show_ids)
3502
2786
        finally:
3503
 
            if wt is not None:
3504
 
                wt.unlock()
3505
 
            else:
3506
 
                branch.unlock()
 
2787
            branch.unlock()
3507
2788
 
3508
2789
 
3509
2790
class cmd_re_sign(Command):
3515
2796
    takes_options = ['revision']
3516
2797
    
3517
2798
    def run(self, revision_id_list=None, revision=None):
 
2799
        import bzrlib.gpg as gpg
3518
2800
        if revision_id_list is not None and revision is not None:
3519
2801
            raise errors.BzrCommandError('You can only supply one of revision_id or --revision')
3520
2802
        if revision_id_list is None and revision is None:
3521
2803
            raise errors.BzrCommandError('You must supply either --revision or a revision_id')
3522
2804
        b = WorkingTree.open_containing(u'.')[0].branch
3523
 
        b.lock_write()
3524
 
        try:
3525
 
            return self._run(b, revision_id_list, revision)
3526
 
        finally:
3527
 
            b.unlock()
3528
 
 
3529
 
    def _run(self, b, revision_id_list, revision):
3530
 
        import bzrlib.gpg as gpg
3531
2805
        gpg_strategy = gpg.GPGStrategy(b.get_config())
3532
2806
        if revision_id_list is not None:
3533
 
            b.repository.start_write_group()
3534
 
            try:
3535
 
                for revision_id in revision_id_list:
3536
 
                    b.repository.sign_revision(revision_id, gpg_strategy)
3537
 
            except:
3538
 
                b.repository.abort_write_group()
3539
 
                raise
3540
 
            else:
3541
 
                b.repository.commit_write_group()
 
2807
            for revision_id in revision_id_list:
 
2808
                b.repository.sign_revision(revision_id, gpg_strategy)
3542
2809
        elif revision is not None:
3543
2810
            if len(revision) == 1:
3544
2811
                revno, rev_id = revision[0].in_history(b)
3545
 
                b.repository.start_write_group()
3546
 
                try:
3547
 
                    b.repository.sign_revision(rev_id, gpg_strategy)
3548
 
                except:
3549
 
                    b.repository.abort_write_group()
3550
 
                    raise
3551
 
                else:
3552
 
                    b.repository.commit_write_group()
 
2812
                b.repository.sign_revision(rev_id, gpg_strategy)
3553
2813
            elif len(revision) == 2:
3554
2814
                # are they both on rh- if so we can walk between them
3555
2815
                # might be nice to have a range helper for arbitrary
3560
2820
                    to_revno = b.revno()
3561
2821
                if from_revno is None or to_revno is None:
3562
2822
                    raise errors.BzrCommandError('Cannot sign a range of non-revision-history revisions')
3563
 
                b.repository.start_write_group()
3564
 
                try:
3565
 
                    for revno in range(from_revno, to_revno + 1):
3566
 
                        b.repository.sign_revision(b.get_rev_id(revno),
3567
 
                                                   gpg_strategy)
3568
 
                except:
3569
 
                    b.repository.abort_write_group()
3570
 
                    raise
3571
 
                else:
3572
 
                    b.repository.commit_write_group()
 
2823
                for revno in range(from_revno, to_revno + 1):
 
2824
                    b.repository.sign_revision(b.get_rev_id(revno), 
 
2825
                                               gpg_strategy)
3573
2826
            else:
3574
2827
                raise errors.BzrCommandError('Please supply either one revision, or a range.')
3575
2828
 
3576
2829
 
3577
2830
class cmd_bind(Command):
3578
 
    """Convert the current branch into a checkout of the supplied branch.
 
2831
    """Bind the current branch to a master branch.
3579
2832
 
3580
 
    Once converted into a checkout, commits must succeed on the master branch
3581
 
    before they will be applied to the local branch.
 
2833
    After binding, commits must succeed on the master branch
 
2834
    before they are executed on the local one.
3582
2835
    """
3583
2836
 
3584
 
    _see_also = ['checkouts', 'unbind']
3585
 
    takes_args = ['location?']
 
2837
    takes_args = ['location']
3586
2838
    takes_options = []
3587
2839
 
3588
2840
    def run(self, location=None):
3589
2841
        b, relpath = Branch.open_containing(u'.')
3590
 
        if location is None:
3591
 
            try:
3592
 
                location = b.get_old_bound_location()
3593
 
            except errors.UpgradeRequired:
3594
 
                raise errors.BzrCommandError('No location supplied.  '
3595
 
                    'This format does not remember old locations.')
3596
 
            else:
3597
 
                if location is None:
3598
 
                    raise errors.BzrCommandError('No location supplied and no '
3599
 
                        'previous location known')
3600
2842
        b_other = Branch.open(location)
3601
2843
        try:
3602
2844
            b.bind(b_other)
3606
2848
 
3607
2849
 
3608
2850
class cmd_unbind(Command):
3609
 
    """Convert the current checkout into a regular branch.
 
2851
    """Unbind the current branch from its master branch.
3610
2852
 
3611
 
    After unbinding, the local branch is considered independent and subsequent
3612
 
    commits will be local only.
 
2853
    After unbinding, the local branch is considered independent.
 
2854
    All subsequent commits will be local.
3613
2855
    """
3614
2856
 
3615
 
    _see_also = ['checkouts', 'bind']
3616
2857
    takes_args = []
3617
2858
    takes_options = []
3618
2859
 
3628
2869
    --verbose will print out what is being removed.
3629
2870
    --dry-run will go through all the motions, but not actually
3630
2871
    remove anything.
3631
 
 
3632
 
    If --revision is specified, uncommit revisions to leave the branch at the
3633
 
    specified revision.  For example, "bzr uncommit -r 15" will leave the
3634
 
    branch at revision 15.
3635
 
 
3636
 
    Uncommit leaves the working tree ready for a new commit.  The only change
3637
 
    it may make is to restore any pending merges that were present before
3638
 
    the commit.
 
2872
    
 
2873
    In the future, uncommit will create a revision bundle, which can then
 
2874
    be re-applied.
3639
2875
    """
3640
2876
 
3641
2877
    # TODO: jam 20060108 Add an option to allow uncommit to remove
3642
2878
    # unreferenced information in 'branch-as-repository' branches.
3643
2879
    # TODO: jam 20060108 Add the ability for uncommit to remove unreferenced
3644
2880
    # information in shared branches as well.
3645
 
    _see_also = ['commit']
3646
2881
    takes_options = ['verbose', 'revision',
3647
 
                    Option('dry-run', help='Don\'t actually make changes.'),
3648
 
                    Option('force', help='Say yes to all questions.'),
3649
 
                    Option('local',
3650
 
                           help="Only remove the commits from the local branch"
3651
 
                                " when in a checkout."
3652
 
                           ),
3653
 
                    ]
 
2882
                    Option('dry-run', help='Don\'t actually make changes'),
 
2883
                    Option('force', help='Say yes to all questions.')]
3654
2884
    takes_args = ['location?']
3655
2885
    aliases = []
3656
 
    encoding_type = 'replace'
3657
2886
 
3658
2887
    def run(self, location=None,
3659
2888
            dry_run=False, verbose=False,
3660
 
            revision=None, force=False, local=False):
 
2889
            revision=None, force=False):
 
2890
        from bzrlib.log import log_formatter, show_log
 
2891
        import sys
 
2892
        from bzrlib.uncommit import uncommit
 
2893
 
3661
2894
        if location is None:
3662
2895
            location = u'.'
3663
2896
        control, relpath = bzrdir.BzrDir.open_containing(location)
3668
2901
            tree = None
3669
2902
            b = control.open_branch()
3670
2903
 
3671
 
        if tree is not None:
3672
 
            tree.lock_write()
3673
 
        else:
3674
 
            b.lock_write()
3675
 
        try:
3676
 
            return self._run(b, tree, dry_run, verbose, revision, force,
3677
 
                             local=local)
3678
 
        finally:
3679
 
            if tree is not None:
3680
 
                tree.unlock()
3681
 
            else:
3682
 
                b.unlock()
3683
 
 
3684
 
    def _run(self, b, tree, dry_run, verbose, revision, force, local=False):
3685
 
        from bzrlib.log import log_formatter, show_log
3686
 
        from bzrlib.uncommit import uncommit
3687
 
 
3688
 
        last_revno, last_rev_id = b.last_revision_info()
3689
 
 
3690
2904
        rev_id = None
3691
2905
        if revision is None:
3692
 
            revno = last_revno
3693
 
            rev_id = last_rev_id
 
2906
            revno = b.revno()
3694
2907
        else:
3695
2908
            # 'bzr uncommit -r 10' actually means uncommit
3696
2909
            # so that the final tree is at revno 10.
3697
2910
            # but bzrlib.uncommit.uncommit() actually uncommits
3698
2911
            # the revisions that are supplied.
3699
2912
            # So we need to offset it by one
3700
 
            revno = revision[0].in_history(b).revno + 1
3701
 
            if revno <= last_revno:
3702
 
                rev_id = b.get_rev_id(revno)
 
2913
            revno = revision[0].in_history(b).revno+1
3703
2914
 
3704
 
        if rev_id is None or _mod_revision.is_null(rev_id):
 
2915
        if revno <= b.revno():
 
2916
            rev_id = b.get_rev_id(revno)
 
2917
        if rev_id is None:
3705
2918
            self.outf.write('No revisions to uncommit.\n')
3706
2919
            return 1
3707
2920
 
3714
2927
                 verbose=False,
3715
2928
                 direction='forward',
3716
2929
                 start_revision=revno,
3717
 
                 end_revision=last_revno)
 
2930
                 end_revision=b.revno())
3718
2931
 
3719
2932
        if dry_run:
3720
2933
            print 'Dry-run, pretending to remove the above revisions.'
3729
2942
                    return 0
3730
2943
 
3731
2944
        uncommit(b, tree=tree, dry_run=dry_run, verbose=verbose,
3732
 
                 revno=revno, local=local)
 
2945
                revno=revno)
3733
2946
 
3734
2947
 
3735
2948
class cmd_break_lock(Command):
3740
2953
 
3741
2954
    You can get information on what locks are open via the 'bzr info' command.
3742
2955
    
3743
 
    :Examples:
 
2956
    example:
3744
2957
        bzr break-lock
3745
2958
    """
3746
2959
    takes_args = ['location?']
3776
2989
 
3777
2990
    takes_options = [
3778
2991
        Option('inet',
3779
 
               help='Serve on stdin/out for use from inetd or sshd.'),
 
2992
               help='serve on stdin/out for use from inetd or sshd'),
3780
2993
        Option('port',
3781
 
               help='Listen for connections on nominated port of the form '
3782
 
                    '[hostname:]portnumber.  Passing 0 as the port number will '
3783
 
                    'result in a dynamically allocated port.  The default port is '
3784
 
                    '4155.',
 
2994
               help='listen for connections on nominated port of the form '
 
2995
                    '[hostname:]portnumber. Passing 0 as the port number will '
 
2996
                    'result in a dynamically allocated port.',
3785
2997
               type=str),
3786
2998
        Option('directory',
3787
 
               help='Serve contents of this directory.',
 
2999
               help='serve contents of directory',
3788
3000
               type=unicode),
3789
3001
        Option('allow-writes',
3790
 
               help='By default the server is a readonly server.  Supplying '
 
3002
               help='By default the server is a readonly server. Supplying '
3791
3003
                    '--allow-writes enables write access to the contents of '
3792
 
                    'the served directory and below.'
 
3004
                    'the served directory and below. '
3793
3005
                ),
3794
3006
        ]
3795
3007
 
3796
3008
    def run(self, port=None, inet=False, directory=None, allow_writes=False):
3797
 
        from bzrlib import lockdir
3798
 
        from bzrlib.smart import medium, server
 
3009
        from bzrlib.transport import smart
3799
3010
        from bzrlib.transport import get_transport
3800
 
        from bzrlib.transport.chroot import ChrootServer
3801
3011
        if directory is None:
3802
3012
            directory = os.getcwd()
3803
3013
        url = urlutils.local_path_to_url(directory)
3804
3014
        if not allow_writes:
3805
3015
            url = 'readonly+' + url
3806
 
        chroot_server = ChrootServer(get_transport(url))
3807
 
        chroot_server.setUp()
3808
 
        t = get_transport(chroot_server.get_url())
 
3016
        t = get_transport(url)
3809
3017
        if inet:
3810
 
            smart_server = medium.SmartServerPipeStreamMedium(
3811
 
                sys.stdin, sys.stdout, t)
3812
 
        else:
3813
 
            host = medium.BZR_DEFAULT_INTERFACE
3814
 
            if port is None:
3815
 
                port = medium.BZR_DEFAULT_PORT
 
3018
            server = smart.SmartServerPipeStreamMedium(sys.stdin, sys.stdout, t)
 
3019
        elif port is not None:
 
3020
            if ':' in port:
 
3021
                host, port = port.split(':')
3816
3022
            else:
3817
 
                if ':' in port:
3818
 
                    host, port = port.split(':')
3819
 
                port = int(port)
3820
 
            smart_server = server.SmartTCPServer(t, host=host, port=port)
3821
 
            print 'listening on port: ', smart_server.port
 
3023
                host = '127.0.0.1'
 
3024
            server = smart.SmartTCPServer(t, host=host, port=int(port))
 
3025
            print 'listening on port: ', server.port
3822
3026
            sys.stdout.flush()
3823
 
        # for the duration of this server, no UI output is permitted.
3824
 
        # note that this may cause problems with blackbox tests. This should
3825
 
        # be changed with care though, as we dont want to use bandwidth sending
3826
 
        # progress over stderr to smart server clients!
3827
 
        old_factory = ui.ui_factory
3828
 
        old_lockdir_timeout = lockdir._DEFAULT_TIMEOUT_SECONDS
3829
 
        try:
3830
 
            ui.ui_factory = ui.SilentUIFactory()
3831
 
            lockdir._DEFAULT_TIMEOUT_SECONDS = 0
3832
 
            smart_server.serve()
3833
 
        finally:
3834
 
            ui.ui_factory = old_factory
3835
 
            lockdir._DEFAULT_TIMEOUT_SECONDS = old_lockdir_timeout
3836
 
 
3837
 
 
3838
 
class cmd_join(Command):
3839
 
    """Combine a subtree into its containing tree.
3840
 
    
3841
 
    This command is for experimental use only.  It requires the target tree
3842
 
    to be in dirstate-with-subtree format, which cannot be converted into
3843
 
    earlier formats.
3844
 
 
3845
 
    The TREE argument should be an independent tree, inside another tree, but
3846
 
    not part of it.  (Such trees can be produced by "bzr split", but also by
3847
 
    running "bzr branch" with the target inside a tree.)
3848
 
 
3849
 
    The result is a combined tree, with the subtree no longer an independant
3850
 
    part.  This is marked as a merge of the subtree into the containing tree,
3851
 
    and all history is preserved.
3852
 
 
3853
 
    If --reference is specified, the subtree retains its independence.  It can
3854
 
    be branched by itself, and can be part of multiple projects at the same
3855
 
    time.  But operations performed in the containing tree, such as commit
3856
 
    and merge, will recurse into the subtree.
3857
 
    """
3858
 
 
3859
 
    _see_also = ['split']
3860
 
    takes_args = ['tree']
3861
 
    takes_options = [
3862
 
            Option('reference', help='Join by reference.'),
3863
 
            ]
3864
 
    hidden = True
3865
 
 
3866
 
    def run(self, tree, reference=False):
3867
 
        sub_tree = WorkingTree.open(tree)
3868
 
        parent_dir = osutils.dirname(sub_tree.basedir)
3869
 
        containing_tree = WorkingTree.open_containing(parent_dir)[0]
3870
 
        repo = containing_tree.branch.repository
3871
 
        if not repo.supports_rich_root():
3872
 
            raise errors.BzrCommandError(
3873
 
                "Can't join trees because %s doesn't support rich root data.\n"
3874
 
                "You can use bzr upgrade on the repository."
3875
 
                % (repo,))
3876
 
        if reference:
3877
 
            try:
3878
 
                containing_tree.add_reference(sub_tree)
3879
 
            except errors.BadReferenceTarget, e:
3880
 
                # XXX: Would be better to just raise a nicely printable
3881
 
                # exception from the real origin.  Also below.  mbp 20070306
3882
 
                raise errors.BzrCommandError("Cannot join %s.  %s" %
3883
 
                                             (tree, e.reason))
3884
 
        else:
3885
 
            try:
3886
 
                containing_tree.subsume(sub_tree)
3887
 
            except errors.BadSubsumeSource, e:
3888
 
                raise errors.BzrCommandError("Cannot join %s.  %s" % 
3889
 
                                             (tree, e.reason))
3890
 
 
3891
 
 
3892
 
class cmd_split(Command):
3893
 
    """Split a subdirectory of a tree into a separate tree.
3894
 
 
3895
 
    This command will produce a target tree in a format that supports
3896
 
    rich roots, like 'rich-root' or 'rich-root-pack'.  These formats cannot be
3897
 
    converted into earlier formats like 'dirstate-tags'.
3898
 
 
3899
 
    The TREE argument should be a subdirectory of a working tree.  That
3900
 
    subdirectory will be converted into an independent tree, with its own
3901
 
    branch.  Commits in the top-level tree will not apply to the new subtree.
3902
 
    """
3903
 
 
3904
 
    # join is not un-hidden yet
3905
 
    #_see_also = ['join']
3906
 
    takes_args = ['tree']
3907
 
 
3908
 
    def run(self, tree):
3909
 
        containing_tree, subdir = WorkingTree.open_containing(tree)
3910
 
        sub_id = containing_tree.path2id(subdir)
3911
 
        if sub_id is None:
3912
 
            raise errors.NotVersionedError(subdir)
3913
 
        try:
3914
 
            containing_tree.extract(sub_id)
3915
 
        except errors.RootNotRich:
3916
 
            raise errors.UpgradeRequired(containing_tree.branch.base)
3917
 
 
3918
 
 
3919
 
class cmd_merge_directive(Command):
3920
 
    """Generate a merge directive for auto-merge tools.
3921
 
 
3922
 
    A directive requests a merge to be performed, and also provides all the
3923
 
    information necessary to do so.  This means it must either include a
3924
 
    revision bundle, or the location of a branch containing the desired
3925
 
    revision.
3926
 
 
3927
 
    A submit branch (the location to merge into) must be supplied the first
3928
 
    time the command is issued.  After it has been supplied once, it will
3929
 
    be remembered as the default.
3930
 
 
3931
 
    A public branch is optional if a revision bundle is supplied, but required
3932
 
    if --diff or --plain is specified.  It will be remembered as the default
3933
 
    after the first use.
3934
 
    """
3935
 
 
3936
 
    takes_args = ['submit_branch?', 'public_branch?']
3937
 
 
3938
 
    hidden = True
3939
 
 
3940
 
    _see_also = ['send']
3941
 
 
3942
 
    takes_options = [
3943
 
        RegistryOption.from_kwargs('patch-type',
3944
 
            'The type of patch to include in the directive.',
3945
 
            title='Patch type',
3946
 
            value_switches=True,
3947
 
            enum_switch=False,
3948
 
            bundle='Bazaar revision bundle (default).',
3949
 
            diff='Normal unified diff.',
3950
 
            plain='No patch, just directive.'),
3951
 
        Option('sign', help='GPG-sign the directive.'), 'revision',
3952
 
        Option('mail-to', type=str,
3953
 
            help='Instead of printing the directive, email to this address.'),
3954
 
        Option('message', type=str, short_name='m',
3955
 
            help='Message to use when committing this merge.')
3956
 
        ]
3957
 
 
3958
 
    encoding_type = 'exact'
3959
 
 
3960
 
    def run(self, submit_branch=None, public_branch=None, patch_type='bundle',
3961
 
            sign=False, revision=None, mail_to=None, message=None):
3962
 
        from bzrlib.revision import ensure_null, NULL_REVISION
3963
 
        include_patch, include_bundle = {
3964
 
            'plain': (False, False),
3965
 
            'diff': (True, False),
3966
 
            'bundle': (True, True),
3967
 
            }[patch_type]
3968
 
        branch = Branch.open('.')
3969
 
        stored_submit_branch = branch.get_submit_branch()
3970
 
        if submit_branch is None:
3971
 
            submit_branch = stored_submit_branch
3972
 
        else:
3973
 
            if stored_submit_branch is None:
3974
 
                branch.set_submit_branch(submit_branch)
3975
 
        if submit_branch is None:
3976
 
            submit_branch = branch.get_parent()
3977
 
        if submit_branch is None:
3978
 
            raise errors.BzrCommandError('No submit branch specified or known')
3979
 
 
3980
 
        stored_public_branch = branch.get_public_branch()
3981
 
        if public_branch is None:
3982
 
            public_branch = stored_public_branch
3983
 
        elif stored_public_branch is None:
3984
 
            branch.set_public_branch(public_branch)
3985
 
        if not include_bundle and public_branch is None:
3986
 
            raise errors.BzrCommandError('No public branch specified or'
3987
 
                                         ' known')
3988
 
        base_revision_id = None
3989
 
        if revision is not None:
3990
 
            if len(revision) > 2:
3991
 
                raise errors.BzrCommandError('bzr merge-directive takes '
3992
 
                    'at most two one revision identifiers')
3993
 
            revision_id = revision[-1].as_revision_id(branch)
3994
 
            if len(revision) == 2:
3995
 
                base_revision_id = revision[0].as_revision_id(branch)
3996
 
        else:
3997
 
            revision_id = branch.last_revision()
3998
 
        revision_id = ensure_null(revision_id)
3999
 
        if revision_id == NULL_REVISION:
4000
 
            raise errors.BzrCommandError('No revisions to bundle.')
4001
 
        directive = merge_directive.MergeDirective2.from_objects(
4002
 
            branch.repository, revision_id, time.time(),
4003
 
            osutils.local_time_offset(), submit_branch,
4004
 
            public_branch=public_branch, include_patch=include_patch,
4005
 
            include_bundle=include_bundle, message=message,
4006
 
            base_revision_id=base_revision_id)
4007
 
        if mail_to is None:
4008
 
            if sign:
4009
 
                self.outf.write(directive.to_signed(branch))
4010
 
            else:
4011
 
                self.outf.writelines(directive.to_lines())
4012
 
        else:
4013
 
            message = directive.to_email(mail_to, branch, sign)
4014
 
            s = SMTPConnection(branch.get_config())
4015
 
            s.send_email(message)
4016
 
 
4017
 
 
4018
 
class cmd_send(Command):
4019
 
    """Mail or create a merge-directive for submiting changes.
4020
 
 
4021
 
    A merge directive provides many things needed for requesting merges:
4022
 
 
4023
 
    * A machine-readable description of the merge to perform
4024
 
 
4025
 
    * An optional patch that is a preview of the changes requested
4026
 
 
4027
 
    * An optional bundle of revision data, so that the changes can be applied
4028
 
      directly from the merge directive, without retrieving data from a
4029
 
      branch.
4030
 
 
4031
 
    If --no-bundle is specified, then public_branch is needed (and must be
4032
 
    up-to-date), so that the receiver can perform the merge using the
4033
 
    public_branch.  The public_branch is always included if known, so that
4034
 
    people can check it later.
4035
 
 
4036
 
    The submit branch defaults to the parent, but can be overridden.  Both
4037
 
    submit branch and public branch will be remembered if supplied.
4038
 
 
4039
 
    If a public_branch is known for the submit_branch, that public submit
4040
 
    branch is used in the merge instructions.  This means that a local mirror
4041
 
    can be used as your actual submit branch, once you have set public_branch
4042
 
    for that mirror.
4043
 
 
4044
 
    Mail is sent using your preferred mail program.  This should be transparent
4045
 
    on Windows (it uses MAPI).  On Linux, it requires the xdg-email utility.
4046
 
    If the preferred client can't be found (or used), your editor will be used.
4047
 
    
4048
 
    To use a specific mail program, set the mail_client configuration option.
4049
 
    (For Thunderbird 1.5, this works around some bugs.)  Supported values for
4050
 
    specific clients are "evolution", "kmail", "mutt", and "thunderbird";
4051
 
    generic options are "default", "editor", "emacsclient", "mapi", and
4052
 
    "xdg-email".
4053
 
 
4054
 
    If mail is being sent, a to address is required.  This can be supplied
4055
 
    either on the commandline, by setting the submit_to configuration
4056
 
    option in the branch itself or the child_submit_to configuration option 
4057
 
    in the submit branch.
4058
 
 
4059
 
    Two formats are currently supported: "4" uses revision bundle format 4 and
4060
 
    merge directive format 2.  It is significantly faster and smaller than
4061
 
    older formats.  It is compatible with Bazaar 0.19 and later.  It is the
4062
 
    default.  "0.9" uses revision bundle format 0.9 and merge directive
4063
 
    format 1.  It is compatible with Bazaar 0.12 - 0.18.
4064
 
    
4065
 
    Merge directives are applied using the merge command or the pull command.
4066
 
    """
4067
 
 
4068
 
    encoding_type = 'exact'
4069
 
 
4070
 
    _see_also = ['merge', 'pull']
4071
 
 
4072
 
    takes_args = ['submit_branch?', 'public_branch?']
4073
 
 
4074
 
    takes_options = [
4075
 
        Option('no-bundle',
4076
 
               help='Do not include a bundle in the merge directive.'),
4077
 
        Option('no-patch', help='Do not include a preview patch in the merge'
4078
 
               ' directive.'),
4079
 
        Option('remember',
4080
 
               help='Remember submit and public branch.'),
4081
 
        Option('from',
4082
 
               help='Branch to generate the submission from, '
4083
 
               'rather than the one containing the working directory.',
4084
 
               short_name='f',
4085
 
               type=unicode),
4086
 
        Option('output', short_name='o',
4087
 
               help='Write merge directive to this file; '
4088
 
                    'use - for stdout.',
4089
 
               type=unicode),
4090
 
        Option('mail-to', help='Mail the request to this address.',
4091
 
               type=unicode),
4092
 
        'revision',
4093
 
        'message',
4094
 
        RegistryOption.from_kwargs('format',
4095
 
        'Use the specified output format.',
4096
 
        **{'4': 'Bundle format 4, Merge Directive 2 (default)',
4097
 
           '0.9': 'Bundle format 0.9, Merge Directive 1',})
4098
 
        ]
4099
 
 
4100
 
    def run(self, submit_branch=None, public_branch=None, no_bundle=False,
4101
 
            no_patch=False, revision=None, remember=False, output=None,
4102
 
            format='4', mail_to=None, message=None, **kwargs):
4103
 
        return self._run(submit_branch, revision, public_branch, remember,
4104
 
                         format, no_bundle, no_patch, output,
4105
 
                         kwargs.get('from', '.'), mail_to, message)
4106
 
 
4107
 
    def _run(self, submit_branch, revision, public_branch, remember, format,
4108
 
             no_bundle, no_patch, output, from_, mail_to, message):
4109
 
        from bzrlib.revision import NULL_REVISION
4110
 
        branch = Branch.open_containing(from_)[0]
4111
 
        if output is None:
4112
 
            outfile = StringIO()
4113
 
        elif output == '-':
4114
 
            outfile = self.outf
4115
 
        else:
4116
 
            outfile = open(output, 'wb')
4117
 
        # we may need to write data into branch's repository to calculate
4118
 
        # the data to send.
4119
 
        branch.lock_write()
4120
 
        try:
4121
 
            if output is None:
4122
 
                config = branch.get_config()
4123
 
                if mail_to is None:
4124
 
                    mail_to = config.get_user_option('submit_to')
4125
 
                mail_client = config.get_mail_client()
4126
 
            if remember and submit_branch is None:
4127
 
                raise errors.BzrCommandError(
4128
 
                    '--remember requires a branch to be specified.')
4129
 
            stored_submit_branch = branch.get_submit_branch()
4130
 
            remembered_submit_branch = False
4131
 
            if submit_branch is None:
4132
 
                submit_branch = stored_submit_branch
4133
 
                remembered_submit_branch = True
4134
 
            else:
4135
 
                if stored_submit_branch is None or remember:
4136
 
                    branch.set_submit_branch(submit_branch)
4137
 
            if submit_branch is None:
4138
 
                submit_branch = branch.get_parent()
4139
 
                remembered_submit_branch = True
4140
 
            if submit_branch is None:
4141
 
                raise errors.BzrCommandError('No submit branch known or'
4142
 
                                             ' specified')
4143
 
            if remembered_submit_branch:
4144
 
                note('Using saved location "%s" to determine what changes to submit.', submit_branch)
4145
 
 
4146
 
            if mail_to is None:
4147
 
                submit_config = Branch.open(submit_branch).get_config()
4148
 
                mail_to = submit_config.get_user_option("child_submit_to")
4149
 
 
4150
 
            stored_public_branch = branch.get_public_branch()
4151
 
            if public_branch is None:
4152
 
                public_branch = stored_public_branch
4153
 
            elif stored_public_branch is None or remember:
4154
 
                branch.set_public_branch(public_branch)
4155
 
            if no_bundle and public_branch is None:
4156
 
                raise errors.BzrCommandError('No public branch specified or'
4157
 
                                             ' known')
4158
 
            base_revision_id = None
4159
 
            revision_id = None
4160
 
            if revision is not None:
4161
 
                if len(revision) > 2:
4162
 
                    raise errors.BzrCommandError('bzr send takes '
4163
 
                        'at most two one revision identifiers')
4164
 
                revision_id = revision[-1].as_revision_id(branch)
4165
 
                if len(revision) == 2:
4166
 
                    base_revision_id = revision[0].as_revision_id(branch)
4167
 
            if revision_id is None:
4168
 
                revision_id = branch.last_revision()
4169
 
            if revision_id == NULL_REVISION:
4170
 
                raise errors.BzrCommandError('No revisions to submit.')
4171
 
            if format == '4':
4172
 
                directive = merge_directive.MergeDirective2.from_objects(
4173
 
                    branch.repository, revision_id, time.time(),
4174
 
                    osutils.local_time_offset(), submit_branch,
4175
 
                    public_branch=public_branch, include_patch=not no_patch,
4176
 
                    include_bundle=not no_bundle, message=message,
4177
 
                    base_revision_id=base_revision_id)
4178
 
            elif format == '0.9':
4179
 
                if not no_bundle:
4180
 
                    if not no_patch:
4181
 
                        patch_type = 'bundle'
4182
 
                    else:
4183
 
                        raise errors.BzrCommandError('Format 0.9 does not'
4184
 
                            ' permit bundle with no patch')
4185
 
                else:
4186
 
                    if not no_patch:
4187
 
                        patch_type = 'diff'
4188
 
                    else:
4189
 
                        patch_type = None
4190
 
                directive = merge_directive.MergeDirective.from_objects(
4191
 
                    branch.repository, revision_id, time.time(),
4192
 
                    osutils.local_time_offset(), submit_branch,
4193
 
                    public_branch=public_branch, patch_type=patch_type,
4194
 
                    message=message)
4195
 
 
4196
 
            outfile.writelines(directive.to_lines())
4197
 
            if output is None:
4198
 
                subject = '[MERGE] '
4199
 
                if message is not None:
4200
 
                    subject += message
4201
 
                else:
4202
 
                    revision = branch.repository.get_revision(revision_id)
4203
 
                    subject += revision.get_summary()
4204
 
                basename = directive.get_disk_name(branch)
4205
 
                mail_client.compose_merge_request(mail_to, subject,
4206
 
                                                  outfile.getvalue(), basename)
4207
 
        finally:
4208
 
            if output != '-':
4209
 
                outfile.close()
4210
 
            branch.unlock()
4211
 
 
4212
 
 
4213
 
class cmd_bundle_revisions(cmd_send):
4214
 
 
4215
 
    """Create a merge-directive for submiting changes.
4216
 
 
4217
 
    A merge directive provides many things needed for requesting merges:
4218
 
 
4219
 
    * A machine-readable description of the merge to perform
4220
 
 
4221
 
    * An optional patch that is a preview of the changes requested
4222
 
 
4223
 
    * An optional bundle of revision data, so that the changes can be applied
4224
 
      directly from the merge directive, without retrieving data from a
4225
 
      branch.
4226
 
 
4227
 
    If --no-bundle is specified, then public_branch is needed (and must be
4228
 
    up-to-date), so that the receiver can perform the merge using the
4229
 
    public_branch.  The public_branch is always included if known, so that
4230
 
    people can check it later.
4231
 
 
4232
 
    The submit branch defaults to the parent, but can be overridden.  Both
4233
 
    submit branch and public branch will be remembered if supplied.
4234
 
 
4235
 
    If a public_branch is known for the submit_branch, that public submit
4236
 
    branch is used in the merge instructions.  This means that a local mirror
4237
 
    can be used as your actual submit branch, once you have set public_branch
4238
 
    for that mirror.
4239
 
 
4240
 
    Two formats are currently supported: "4" uses revision bundle format 4 and
4241
 
    merge directive format 2.  It is significantly faster and smaller than
4242
 
    older formats.  It is compatible with Bazaar 0.19 and later.  It is the
4243
 
    default.  "0.9" uses revision bundle format 0.9 and merge directive
4244
 
    format 1.  It is compatible with Bazaar 0.12 - 0.18.
4245
 
    """
4246
 
 
4247
 
    takes_options = [
4248
 
        Option('no-bundle',
4249
 
               help='Do not include a bundle in the merge directive.'),
4250
 
        Option('no-patch', help='Do not include a preview patch in the merge'
4251
 
               ' directive.'),
4252
 
        Option('remember',
4253
 
               help='Remember submit and public branch.'),
4254
 
        Option('from',
4255
 
               help='Branch to generate the submission from, '
4256
 
               'rather than the one containing the working directory.',
4257
 
               short_name='f',
4258
 
               type=unicode),
4259
 
        Option('output', short_name='o', help='Write directive to this file.',
4260
 
               type=unicode),
4261
 
        'revision',
4262
 
        RegistryOption.from_kwargs('format',
4263
 
        'Use the specified output format.',
4264
 
        **{'4': 'Bundle format 4, Merge Directive 2 (default)',
4265
 
           '0.9': 'Bundle format 0.9, Merge Directive 1',})
4266
 
        ]
4267
 
    aliases = ['bundle']
4268
 
 
4269
 
    _see_also = ['send', 'merge']
4270
 
 
4271
 
    hidden = True
4272
 
 
4273
 
    def run(self, submit_branch=None, public_branch=None, no_bundle=False,
4274
 
            no_patch=False, revision=None, remember=False, output=None,
4275
 
            format='4', **kwargs):
4276
 
        if output is None:
4277
 
            output = '-'
4278
 
        return self._run(submit_branch, revision, public_branch, remember,
4279
 
                         format, no_bundle, no_patch, output,
4280
 
                         kwargs.get('from', '.'), None, None)
4281
 
 
4282
 
 
4283
 
class cmd_tag(Command):
4284
 
    """Create, remove or modify a tag naming a revision.
4285
 
    
4286
 
    Tags give human-meaningful names to revisions.  Commands that take a -r
4287
 
    (--revision) option can be given -rtag:X, where X is any previously
4288
 
    created tag.
4289
 
 
4290
 
    Tags are stored in the branch.  Tags are copied from one branch to another
4291
 
    along when you branch, push, pull or merge.
4292
 
 
4293
 
    It is an error to give a tag name that already exists unless you pass 
4294
 
    --force, in which case the tag is moved to point to the new revision.
4295
 
    """
4296
 
 
4297
 
    _see_also = ['commit', 'tags']
4298
 
    takes_args = ['tag_name']
4299
 
    takes_options = [
4300
 
        Option('delete',
4301
 
            help='Delete this tag rather than placing it.',
4302
 
            ),
4303
 
        Option('directory',
4304
 
            help='Branch in which to place the tag.',
4305
 
            short_name='d',
4306
 
            type=unicode,
4307
 
            ),
4308
 
        Option('force',
4309
 
            help='Replace existing tags.',
4310
 
            ),
4311
 
        'revision',
4312
 
        ]
4313
 
 
4314
 
    def run(self, tag_name,
4315
 
            delete=None,
4316
 
            directory='.',
4317
 
            force=None,
4318
 
            revision=None,
4319
 
            ):
4320
 
        branch, relpath = Branch.open_containing(directory)
4321
 
        branch.lock_write()
4322
 
        try:
4323
 
            if delete:
4324
 
                branch.tags.delete_tag(tag_name)
4325
 
                self.outf.write('Deleted tag %s.\n' % tag_name)
4326
 
            else:
4327
 
                if revision:
4328
 
                    if len(revision) != 1:
4329
 
                        raise errors.BzrCommandError(
4330
 
                            "Tags can only be placed on a single revision, "
4331
 
                            "not on a range")
4332
 
                    revision_id = revision[0].as_revision_id(branch)
4333
 
                else:
4334
 
                    revision_id = branch.last_revision()
4335
 
                if (not force) and branch.tags.has_tag(tag_name):
4336
 
                    raise errors.TagAlreadyExists(tag_name)
4337
 
                branch.tags.set_tag(tag_name, revision_id)
4338
 
                self.outf.write('Created tag %s.\n' % tag_name)
4339
 
        finally:
4340
 
            branch.unlock()
4341
 
 
4342
 
 
4343
 
class cmd_tags(Command):
4344
 
    """List tags.
4345
 
 
4346
 
    This command shows a table of tag names and the revisions they reference.
4347
 
    """
4348
 
 
4349
 
    _see_also = ['tag']
4350
 
    takes_options = [
4351
 
        Option('directory',
4352
 
            help='Branch whose tags should be displayed.',
4353
 
            short_name='d',
4354
 
            type=unicode,
4355
 
            ),
4356
 
        RegistryOption.from_kwargs('sort',
4357
 
            'Sort tags by different criteria.', title='Sorting',
4358
 
            alpha='Sort tags lexicographically (default).',
4359
 
            time='Sort tags chronologically.',
4360
 
            ),
4361
 
        'show-ids',
4362
 
    ]
4363
 
 
4364
 
    @display_command
4365
 
    def run(self,
4366
 
            directory='.',
4367
 
            sort='alpha',
4368
 
            show_ids=False,
4369
 
            ):
4370
 
        branch, relpath = Branch.open_containing(directory)
4371
 
        tags = branch.tags.get_tag_dict().items()
4372
 
        if sort == 'alpha':
4373
 
            tags.sort()
4374
 
        elif sort == 'time':
4375
 
            timestamps = {}
4376
 
            for tag, revid in tags:
4377
 
                try:
4378
 
                    revobj = branch.repository.get_revision(revid)
4379
 
                except errors.NoSuchRevision:
4380
 
                    timestamp = sys.maxint # place them at the end
4381
 
                else:
4382
 
                    timestamp = revobj.timestamp
4383
 
                timestamps[revid] = timestamp
4384
 
            tags.sort(key=lambda x: timestamps[x[1]])
4385
 
        if not show_ids:
4386
 
            # [ (tag, revid), ... ] -> [ (tag, dotted_revno), ... ]
4387
 
            revno_map = branch.get_revision_id_to_revno_map()
4388
 
            tags = [ (tag, '.'.join(map(str, revno_map.get(revid, ('?',)))))
4389
 
                        for tag, revid in tags ]
4390
 
        for tag, revspec in tags:
4391
 
            self.outf.write('%-20s %s\n' % (tag, revspec))
4392
 
 
4393
 
 
4394
 
class cmd_reconfigure(Command):
4395
 
    """Reconfigure the type of a bzr directory.
4396
 
 
4397
 
    A target configuration must be specified.
4398
 
 
4399
 
    For checkouts, the bind-to location will be auto-detected if not specified.
4400
 
    The order of preference is
4401
 
    1. For a lightweight checkout, the current bound location.
4402
 
    2. For branches that used to be checkouts, the previously-bound location.
4403
 
    3. The push location.
4404
 
    4. The parent location.
4405
 
    If none of these is available, --bind-to must be specified.
4406
 
    """
4407
 
 
4408
 
    _see_also = ['branches', 'checkouts', 'standalone-trees', 'working-trees']
4409
 
    takes_args = ['location?']
4410
 
    takes_options = [RegistryOption.from_kwargs('target_type',
4411
 
                     title='Target type',
4412
 
                     help='The type to reconfigure the directory to.',
4413
 
                     value_switches=True, enum_switch=False,
4414
 
                     branch='Reconfigure to be an unbound branch '
4415
 
                        'with no working tree.',
4416
 
                     tree='Reconfigure to be an unbound branch '
4417
 
                        'with a working tree.',
4418
 
                     checkout='Reconfigure to be a bound branch '
4419
 
                        'with a working tree.',
4420
 
                     lightweight_checkout='Reconfigure to be a lightweight'
4421
 
                     ' checkout (with no local history).',
4422
 
                     standalone='Reconfigure to be a standalone branch '
4423
 
                        '(i.e. stop using shared repository).',
4424
 
                     use_shared='Reconfigure to use a shared repository.'),
4425
 
                     Option('bind-to', help='Branch to bind checkout to.',
4426
 
                            type=str),
4427
 
                     Option('force',
4428
 
                        help='Perform reconfiguration even if local changes'
4429
 
                        ' will be lost.')
4430
 
                     ]
4431
 
 
4432
 
    def run(self, location=None, target_type=None, bind_to=None, force=False):
4433
 
        directory = bzrdir.BzrDir.open(location)
4434
 
        if target_type is None:
4435
 
            raise errors.BzrCommandError('No target configuration specified')
4436
 
        elif target_type == 'branch':
4437
 
            reconfiguration = reconfigure.Reconfigure.to_branch(directory)
4438
 
        elif target_type == 'tree':
4439
 
            reconfiguration = reconfigure.Reconfigure.to_tree(directory)
4440
 
        elif target_type == 'checkout':
4441
 
            reconfiguration = reconfigure.Reconfigure.to_checkout(directory,
4442
 
                                                                  bind_to)
4443
 
        elif target_type == 'lightweight-checkout':
4444
 
            reconfiguration = reconfigure.Reconfigure.to_lightweight_checkout(
4445
 
                directory, bind_to)
4446
 
        elif target_type == 'use-shared':
4447
 
            reconfiguration = reconfigure.Reconfigure.to_use_shared(directory)
4448
 
        elif target_type == 'standalone':
4449
 
            reconfiguration = reconfigure.Reconfigure.to_standalone(directory)
4450
 
        reconfiguration.apply(force)
4451
 
 
4452
 
 
4453
 
class cmd_switch(Command):
4454
 
    """Set the branch of a checkout and update.
4455
 
    
4456
 
    For lightweight checkouts, this changes the branch being referenced.
4457
 
    For heavyweight checkouts, this checks that there are no local commits
4458
 
    versus the current bound branch, then it makes the local branch a mirror
4459
 
    of the new location and binds to it.
4460
 
    
4461
 
    In both cases, the working tree is updated and uncommitted changes
4462
 
    are merged. The user can commit or revert these as they desire.
4463
 
 
4464
 
    Pending merges need to be committed or reverted before using switch.
4465
 
 
4466
 
    The path to the branch to switch to can be specified relative to the parent
4467
 
    directory of the current branch. For example, if you are currently in a
4468
 
    checkout of /path/to/branch, specifying 'newbranch' will find a branch at
4469
 
    /path/to/newbranch.
4470
 
    """
4471
 
 
4472
 
    takes_args = ['to_location']
4473
 
    takes_options = [Option('force',
4474
 
                        help='Switch even if local commits will be lost.')
4475
 
                     ]
4476
 
 
4477
 
    def run(self, to_location, force=False):
4478
 
        from bzrlib import switch
4479
 
        tree_location = '.'
4480
 
        control_dir = bzrdir.BzrDir.open_containing(tree_location)[0]
4481
 
        try:
4482
 
            to_branch = Branch.open(to_location)
4483
 
        except errors.NotBranchError:
4484
 
            to_branch = Branch.open(
4485
 
                control_dir.open_branch().base + '../' + to_location)
4486
 
        switch.switch(control_dir, to_branch, force)
4487
 
        note('Switched to branch: %s',
4488
 
            urlutils.unescape_for_display(to_branch.base, 'utf-8'))
4489
 
 
4490
 
 
4491
 
class cmd_hooks(Command):
4492
 
    """Show a branch's currently registered hooks.
4493
 
    """
4494
 
 
4495
 
    hidden = True
4496
 
    takes_args = ['path?']
4497
 
 
4498
 
    def run(self, path=None):
4499
 
        if path is None:
4500
 
            path = '.'
4501
 
        branch_hooks = Branch.open(path).hooks
4502
 
        for hook_type in branch_hooks:
4503
 
            hooks = branch_hooks[hook_type]
4504
 
            self.outf.write("%s:\n" % (hook_type,))
4505
 
            if hooks:
4506
 
                for hook in hooks:
4507
 
                    self.outf.write("  %s\n" %
4508
 
                                    (branch_hooks.get_hook_name(hook),))
4509
 
            else:
4510
 
                self.outf.write("  <no hooks installed>\n")
4511
 
 
4512
 
 
4513
 
def _create_prefix(cur_transport):
4514
 
    needed = [cur_transport]
4515
 
    # Recurse upwards until we can create a directory successfully
4516
 
    while True:
4517
 
        new_transport = cur_transport.clone('..')
4518
 
        if new_transport.base == cur_transport.base:
4519
 
            raise errors.BzrCommandError(
4520
 
                "Failed to create path prefix for %s."
4521
 
                % cur_transport.base)
4522
 
        try:
4523
 
            new_transport.mkdir('.')
4524
 
        except errors.NoSuchFile:
4525
 
            needed.append(new_transport)
4526
 
            cur_transport = new_transport
4527
 
        else:
4528
 
            break
4529
 
    # Now we only need to create child directories
4530
 
    while needed:
4531
 
        cur_transport = needed.pop()
4532
 
        cur_transport.ensure_base()
 
3027
        else:
 
3028
            raise errors.BzrCommandError("bzr serve requires one of --inet or --port")
 
3029
        server.serve()
 
3030
 
 
3031
 
 
3032
# command-line interpretation helper for merge-related commands
 
3033
def _merge_helper(other_revision, base_revision,
 
3034
                  check_clean=True, ignore_zero=False,
 
3035
                  this_dir=None, backup_files=False,
 
3036
                  merge_type=None,
 
3037
                  file_list=None, show_base=False, reprocess=False,
 
3038
                  pull=False,
 
3039
                  pb=DummyProgress()):
 
3040
    """Merge changes into a tree.
 
3041
 
 
3042
    base_revision
 
3043
        list(path, revno) Base for three-way merge.  
 
3044
        If [None, None] then a base will be automatically determined.
 
3045
    other_revision
 
3046
        list(path, revno) Other revision for three-way merge.
 
3047
    this_dir
 
3048
        Directory to merge changes into; '.' by default.
 
3049
    check_clean
 
3050
        If true, this_dir must have no uncommitted changes before the
 
3051
        merge begins.
 
3052
    ignore_zero - If true, suppress the "zero conflicts" message when 
 
3053
        there are no conflicts; should be set when doing something we expect
 
3054
        to complete perfectly.
 
3055
    file_list - If supplied, merge only changes to selected files.
 
3056
 
 
3057
    All available ancestors of other_revision and base_revision are
 
3058
    automatically pulled into the branch.
 
3059
 
 
3060
    The revno may be -1 to indicate the last revision on the branch, which is
 
3061
    the typical case.
 
3062
 
 
3063
    This function is intended for use from the command line; programmatic
 
3064
    clients might prefer to call merge.merge_inner(), which has less magic 
 
3065
    behavior.
 
3066
    """
 
3067
    # Loading it late, so that we don't always have to import bzrlib.merge
 
3068
    if merge_type is None:
 
3069
        merge_type = _mod_merge.Merge3Merger
 
3070
    if this_dir is None:
 
3071
        this_dir = u'.'
 
3072
    this_tree = WorkingTree.open_containing(this_dir)[0]
 
3073
    if show_base and not merge_type is _mod_merge.Merge3Merger:
 
3074
        raise errors.BzrCommandError("Show-base is not supported for this merge"
 
3075
                                     " type. %s" % merge_type)
 
3076
    if reprocess and not merge_type.supports_reprocess:
 
3077
        raise errors.BzrCommandError("Conflict reduction is not supported for merge"
 
3078
                                     " type %s." % merge_type)
 
3079
    if reprocess and show_base:
 
3080
        raise errors.BzrCommandError("Cannot do conflict reduction and show base.")
 
3081
    try:
 
3082
        merger = _mod_merge.Merger(this_tree.branch, this_tree=this_tree,
 
3083
                                   pb=pb)
 
3084
        merger.pp = ProgressPhase("Merge phase", 5, pb)
 
3085
        merger.pp.next_phase()
 
3086
        merger.check_basis(check_clean)
 
3087
        merger.set_other(other_revision)
 
3088
        merger.pp.next_phase()
 
3089
        merger.set_base(base_revision)
 
3090
        if merger.base_rev_id == merger.other_rev_id:
 
3091
            note('Nothing to do.')
 
3092
            return 0
 
3093
        if file_list is None:
 
3094
            if pull and merger.base_rev_id == merger.this_rev_id:
 
3095
                count = merger.this_tree.pull(merger.this_branch,
 
3096
                        False, merger.other_rev_id)
 
3097
                note('%d revision(s) pulled.' % (count,))
 
3098
                return 0
 
3099
        merger.backup_files = backup_files
 
3100
        merger.merge_type = merge_type 
 
3101
        merger.set_interesting_files(file_list)
 
3102
        merger.show_base = show_base 
 
3103
        merger.reprocess = reprocess
 
3104
        conflicts = merger.do_merge()
 
3105
        if file_list is None:
 
3106
            merger.set_pending()
 
3107
    finally:
 
3108
        pb.clear()
 
3109
    return conflicts
 
3110
 
 
3111
 
 
3112
# Compatibility
 
3113
merge = _merge_helper
4533
3114
 
4534
3115
 
4535
3116
# these get imported and then picked up by the scan for cmd_*
4539
3120
# details were needed.
4540
3121
from bzrlib.cmd_version_info import cmd_version_info
4541
3122
from bzrlib.conflicts import cmd_resolve, cmd_conflicts, restore
4542
 
from bzrlib.bundle.commands import (
4543
 
    cmd_bundle_info,
4544
 
    )
 
3123
from bzrlib.bundle.commands import cmd_bundle_revisions
4545
3124
from bzrlib.sign_my_commits import cmd_sign_my_commits
4546
 
from bzrlib.weave_commands import cmd_versionedfile_list, \
 
3125
from bzrlib.weave_commands import cmd_weave_list, cmd_weave_join, \
4547
3126
        cmd_weave_plan_merge, cmd_weave_merge_text