/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to bzrlib/builtins.py

  • Committer: Andrew Bennetts
  • Date: 2010-01-12 03:53:21 UTC
  • mfrom: (4948 +trunk)
  • mto: This revision was merged to the branch mainline in revision 4964.
  • Revision ID: andrew.bennetts@canonical.com-20100112035321-hofpz5p10224ryj3
Merge lp:bzr, resolving conflicts.

Show diffs side-by-side

added added

removed removed

Lines of Context:
12
12
#
13
13
# You should have received a copy of the GNU General Public License
14
14
# along with this program; if not, write to the Free Software
15
 
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
16
 
17
17
"""builtin bzr commands"""
18
18
 
31
31
    bundle,
32
32
    btree_index,
33
33
    bzrdir,
 
34
    directory_service,
34
35
    delta,
35
36
    config,
36
37
    errors,
37
38
    globbing,
 
39
    hooks,
38
40
    log,
39
41
    merge as _mod_merge,
40
42
    merge_directive,
41
43
    osutils,
42
44
    reconfigure,
 
45
    rename_map,
43
46
    revision as _mod_revision,
 
47
    static_tuple,
44
48
    symbol_versioning,
 
49
    timestamp,
45
50
    transport,
46
 
    tree as _mod_tree,
47
51
    ui,
48
52
    urlutils,
 
53
    views,
49
54
    )
50
55
from bzrlib.branch import Branch
51
56
from bzrlib.conflicts import ConflictList
65
70
from bzrlib.trace import mutter, note, warning, is_quiet, get_verbosity_level
66
71
 
67
72
 
68
 
def tree_files(file_list, default_branch=u'.', canonicalize=True):
 
73
def tree_files(file_list, default_branch=u'.', canonicalize=True,
 
74
    apply_view=True):
69
75
    try:
70
 
        return internal_tree_files(file_list, default_branch, canonicalize)
 
76
        return internal_tree_files(file_list, default_branch, canonicalize,
 
77
            apply_view)
71
78
    except errors.FileInWrongBranch, e:
72
79
        raise errors.BzrCommandError("%s is not in the same branch as %s" %
73
80
                                     (e.path, file_list[0]))
74
81
 
75
82
 
 
83
def tree_files_for_add(file_list):
 
84
    """
 
85
    Return a tree and list of absolute paths from a file list.
 
86
 
 
87
    Similar to tree_files, but add handles files a bit differently, so it a
 
88
    custom implementation.  In particular, MutableTreeTree.smart_add expects
 
89
    absolute paths, which it immediately converts to relative paths.
 
90
    """
 
91
    # FIXME Would be nice to just return the relative paths like
 
92
    # internal_tree_files does, but there are a large number of unit tests
 
93
    # that assume the current interface to mutabletree.smart_add
 
94
    if file_list:
 
95
        tree, relpath = WorkingTree.open_containing(file_list[0])
 
96
        if tree.supports_views():
 
97
            view_files = tree.views.lookup_view()
 
98
            if view_files:
 
99
                for filename in file_list:
 
100
                    if not osutils.is_inside_any(view_files, filename):
 
101
                        raise errors.FileOutsideView(filename, view_files)
 
102
        file_list = file_list[:]
 
103
        file_list[0] = tree.abspath(relpath)
 
104
    else:
 
105
        tree = WorkingTree.open_containing(u'.')[0]
 
106
        if tree.supports_views():
 
107
            view_files = tree.views.lookup_view()
 
108
            if view_files:
 
109
                file_list = view_files
 
110
                view_str = views.view_display_str(view_files)
 
111
                note("Ignoring files outside view. View is %s" % view_str)
 
112
    return tree, file_list
 
113
 
 
114
 
76
115
def _get_one_revision(command_name, revisions):
77
116
    if revisions is None:
78
117
        return None
84
123
 
85
124
 
86
125
def _get_one_revision_tree(command_name, revisions, branch=None, tree=None):
 
126
    """Get a revision tree. Not suitable for commands that change the tree.
 
127
    
 
128
    Specifically, the basis tree in dirstate trees is coupled to the dirstate
 
129
    and doing a commit/uncommit/pull will at best fail due to changing the
 
130
    basis revision data.
 
131
 
 
132
    If tree is passed in, it should be already locked, for lifetime management
 
133
    of the trees internal cached state.
 
134
    """
87
135
    if branch is None:
88
136
        branch = tree.branch
89
137
    if revisions is None:
99
147
 
100
148
# XXX: Bad function name; should possibly also be a class method of
101
149
# WorkingTree rather than a function.
102
 
def internal_tree_files(file_list, default_branch=u'.', canonicalize=True):
 
150
def internal_tree_files(file_list, default_branch=u'.', canonicalize=True,
 
151
    apply_view=True):
103
152
    """Convert command-line paths to a WorkingTree and relative paths.
104
153
 
105
154
    This is typically used for command-line processors that take one or
107
156
 
108
157
    The filenames given are not required to exist.
109
158
 
110
 
    :param file_list: Filenames to convert.  
 
159
    :param file_list: Filenames to convert.
111
160
 
112
161
    :param default_branch: Fallback tree path to use if file_list is empty or
113
162
        None.
114
163
 
 
164
    :param apply_view: if True and a view is set, apply it or check that
 
165
        specified files are within it
 
166
 
115
167
    :return: workingtree, [relative_paths]
116
168
    """
117
169
    if file_list is None or len(file_list) == 0:
118
 
        return WorkingTree.open_containing(default_branch)[0], file_list
 
170
        tree = WorkingTree.open_containing(default_branch)[0]
 
171
        if tree.supports_views() and apply_view:
 
172
            view_files = tree.views.lookup_view()
 
173
            if view_files:
 
174
                file_list = view_files
 
175
                view_str = views.view_display_str(view_files)
 
176
                note("Ignoring files outside view. View is %s" % view_str)
 
177
        return tree, file_list
119
178
    tree = WorkingTree.open_containing(osutils.realpath(file_list[0]))[0]
120
 
    return tree, safe_relpath_files(tree, file_list, canonicalize)
121
 
 
122
 
 
123
 
def safe_relpath_files(tree, file_list, canonicalize=True):
 
179
    return tree, safe_relpath_files(tree, file_list, canonicalize,
 
180
        apply_view=apply_view)
 
181
 
 
182
 
 
183
def safe_relpath_files(tree, file_list, canonicalize=True, apply_view=True):
124
184
    """Convert file_list into a list of relpaths in tree.
125
185
 
126
186
    :param tree: A tree to operate on.
127
187
    :param file_list: A list of user provided paths or None.
 
188
    :param apply_view: if True and a view is set, apply it or check that
 
189
        specified files are within it
128
190
    :return: A list of relative paths.
129
191
    :raises errors.PathNotChild: When a provided path is in a different tree
130
192
        than tree.
131
193
    """
132
194
    if file_list is None:
133
195
        return None
 
196
    if tree.supports_views() and apply_view:
 
197
        view_files = tree.views.lookup_view()
 
198
    else:
 
199
        view_files = []
134
200
    new_list = []
135
201
    # tree.relpath exists as a "thunk" to osutils, but canonical_relpath
136
202
    # doesn't - fix that up here before we enter the loop.
140
206
        fixer = tree.relpath
141
207
    for filename in file_list:
142
208
        try:
143
 
            new_list.append(fixer(osutils.dereference_path(filename)))
 
209
            relpath = fixer(osutils.dereference_path(filename))
 
210
            if  view_files and not osutils.is_inside_any(view_files, relpath):
 
211
                raise errors.FileOutsideView(filename, view_files)
 
212
            new_list.append(relpath)
144
213
        except errors.PathNotChild:
145
214
            raise errors.FileInWrongBranch(tree.branch, filename)
146
215
    return new_list
147
216
 
148
217
 
 
218
def _get_view_info_for_change_reporter(tree):
 
219
    """Get the view information from a tree for change reporting."""
 
220
    view_info = None
 
221
    try:
 
222
        current_view = tree.views.get_view_info()[0]
 
223
        if current_view is not None:
 
224
            view_info = (current_view, tree.views.lookup_view())
 
225
    except errors.ViewsNotSupported:
 
226
        pass
 
227
    return view_info
 
228
 
 
229
 
149
230
# TODO: Make sure no commands unconditionally use the working directory as a
150
231
# branch.  If a filename argument is used, the first of them should be used to
151
232
# specify the branch.  (Perhaps this can be factored out into some kind of
179
260
    unknown
180
261
        Not versioned and not matching an ignore pattern.
181
262
 
 
263
    Additionally for directories, symlinks and files with an executable
 
264
    bit, Bazaar indicates their type using a trailing character: '/', '@'
 
265
    or '*' respectively.
 
266
 
182
267
    To see ignored files use 'bzr ignored'.  For details on the
183
268
    changes to file texts, use 'bzr diff'.
184
 
    
 
269
 
185
270
    Note that --short or -S gives status flags for each item, similar
186
271
    to Subversion's status command. To get output similar to svn -q,
187
272
    use bzr status -SV.
199
284
    If a revision argument is given, the status is calculated against
200
285
    that revision, or between two revisions if two are provided.
201
286
    """
202
 
    
 
287
 
203
288
    # TODO: --no-recurse, --recurse options
204
 
    
 
289
 
205
290
    takes_args = ['file*']
206
291
    takes_options = ['show-ids', 'revision', 'change', 'verbose',
207
292
                     Option('short', help='Use short status indicators.',
215
300
 
216
301
    encoding_type = 'replace'
217
302
    _see_also = ['diff', 'revert', 'status-flags']
218
 
    
 
303
 
219
304
    @display_command
220
305
    def run(self, show_ids=False, file_list=None, revision=None, short=False,
221
306
            versioned=False, no_pending=False, verbose=False):
243
328
 
244
329
class cmd_cat_revision(Command):
245
330
    """Write out metadata for a revision.
246
 
    
 
331
 
247
332
    The revision to print can either be specified by a specific
248
333
    revision identifier, or you can use --revision.
249
334
    """
253
338
    takes_options = ['revision']
254
339
    # cat-revision is more for frontends so should be exact
255
340
    encoding = 'strict'
256
 
    
 
341
 
257
342
    @display_command
258
343
    def run(self, revision_id=None, revision=None):
259
344
        if revision_id is not None and revision is not None:
353
438
        for node in bt.iter_all_entries():
354
439
            # Node is made up of:
355
440
            # (index, key, value, [references])
356
 
            self.outf.write('%s\n' % (node[1:],))
 
441
            refs_as_tuples = static_tuple.as_tuples(node[3])
 
442
            as_tuple = (tuple(node[1]), node[2], refs_as_tuples)
 
443
            self.outf.write('%s\n' % (as_tuple,))
357
444
 
358
445
 
359
446
class cmd_remove_tree(Command):
374
461
 
375
462
    def run(self, location='.', force=False):
376
463
        d = bzrdir.BzrDir.open(location)
377
 
        
 
464
 
378
465
        try:
379
466
            working = d.open_workingtree()
380
467
        except errors.NoWorkingTree:
381
468
            raise errors.BzrCommandError("No working tree to remove")
382
469
        except errors.NotLocalUrl:
383
 
            raise errors.BzrCommandError("You cannot remove the working tree of a "
384
 
                                         "remote path")
 
470
            raise errors.BzrCommandError("You cannot remove the working tree"
 
471
                                         " of a remote path")
385
472
        if not force:
386
 
            changes = working.changes_from(working.basis_tree())
387
 
            if changes.has_changed():
 
473
            if (working.has_changes()):
388
474
                raise errors.UncommittedChanges(working)
389
475
 
390
476
        working_path = working.bzrdir.root_transport.base
391
477
        branch_path = working.branch.bzrdir.root_transport.base
392
478
        if working_path != branch_path:
393
 
            raise errors.BzrCommandError("You cannot remove the working tree from "
394
 
                                         "a lightweight checkout")
395
 
        
 
479
            raise errors.BzrCommandError("You cannot remove the working tree"
 
480
                                         " from a lightweight checkout")
 
481
 
396
482
        d.destroy_workingtree()
397
 
        
 
483
 
398
484
 
399
485
class cmd_revno(Command):
400
486
    """Show current revision number.
404
490
 
405
491
    _see_also = ['info']
406
492
    takes_args = ['location?']
 
493
    takes_options = [
 
494
        Option('tree', help='Show revno of working tree'),
 
495
        ]
407
496
 
408
497
    @display_command
409
 
    def run(self, location=u'.'):
410
 
        self.outf.write(str(Branch.open_containing(location)[0].revno()))
411
 
        self.outf.write('\n')
 
498
    def run(self, tree=False, location=u'.'):
 
499
        if tree:
 
500
            try:
 
501
                wt = WorkingTree.open_containing(location)[0]
 
502
                wt.lock_read()
 
503
            except (errors.NoWorkingTree, errors.NotLocalUrl):
 
504
                raise errors.NoWorkingTree(location)
 
505
            self.add_cleanup(wt.unlock)
 
506
            revid = wt.last_revision()
 
507
            try:
 
508
                revno_t = wt.branch.revision_id_to_dotted_revno(revid)
 
509
            except errors.NoSuchRevision:
 
510
                revno_t = ('???',)
 
511
            revno = ".".join(str(n) for n in revno_t)
 
512
        else:
 
513
            b = Branch.open_containing(location)[0]
 
514
            b.lock_read()
 
515
            self.add_cleanup(b.unlock)
 
516
            revno = b.revno()
 
517
        self.cleanup_now()
 
518
        self.outf.write(str(revno) + '\n')
412
519
 
413
520
 
414
521
class cmd_revision_info(Command):
424
531
            short_name='d',
425
532
            type=unicode,
426
533
            ),
 
534
        Option('tree', help='Show revno of working tree'),
427
535
        ]
428
536
 
429
537
    @display_command
430
 
    def run(self, revision=None, directory=u'.', revision_info_list=[]):
 
538
    def run(self, revision=None, directory=u'.', tree=False,
 
539
            revision_info_list=[]):
431
540
 
432
 
        revs = []
 
541
        try:
 
542
            wt = WorkingTree.open_containing(directory)[0]
 
543
            b = wt.branch
 
544
            wt.lock_read()
 
545
            self.add_cleanup(wt.unlock)
 
546
        except (errors.NoWorkingTree, errors.NotLocalUrl):
 
547
            wt = None
 
548
            b = Branch.open_containing(directory)[0]
 
549
            b.lock_read()
 
550
            self.add_cleanup(b.unlock)
 
551
        revision_ids = []
433
552
        if revision is not None:
434
 
            revs.extend(revision)
 
553
            revision_ids.extend(rev.as_revision_id(b) for rev in revision)
435
554
        if revision_info_list is not None:
436
 
            for rev in revision_info_list:
437
 
                revs.append(RevisionSpec.from_string(rev))
438
 
 
439
 
        b = Branch.open_containing(directory)[0]
440
 
 
441
 
        if len(revs) == 0:
442
 
            revs.append(RevisionSpec.from_string('-1'))
443
 
 
444
 
        for rev in revs:
445
 
            revision_id = rev.as_revision_id(b)
 
555
            for rev_str in revision_info_list:
 
556
                rev_spec = RevisionSpec.from_string(rev_str)
 
557
                revision_ids.append(rev_spec.as_revision_id(b))
 
558
        # No arguments supplied, default to the last revision
 
559
        if len(revision_ids) == 0:
 
560
            if tree:
 
561
                if wt is None:
 
562
                    raise errors.NoWorkingTree(directory)
 
563
                revision_ids.append(wt.last_revision())
 
564
            else:
 
565
                revision_ids.append(b.last_revision())
 
566
 
 
567
        revinfos = []
 
568
        maxlen = 0
 
569
        for revision_id in revision_ids:
446
570
            try:
447
 
                revno = '%4d' % (b.revision_id_to_revno(revision_id))
 
571
                dotted_revno = b.revision_id_to_dotted_revno(revision_id)
 
572
                revno = '.'.join(str(i) for i in dotted_revno)
448
573
            except errors.NoSuchRevision:
449
 
                dotted_map = b.get_revision_id_to_revno_map()
450
 
                revno = '.'.join(str(i) for i in dotted_map[revision_id])
451
 
            print '%s %s' % (revno, revision_id)
452
 
 
453
 
    
 
574
                revno = '???'
 
575
            maxlen = max(maxlen, len(revno))
 
576
            revinfos.append([revno, revision_id])
 
577
 
 
578
        self.cleanup_now()
 
579
        for ri in revinfos:
 
580
            self.outf.write('%*s %s\n' % (maxlen, ri[0], ri[1]))
 
581
 
 
582
 
454
583
class cmd_add(Command):
455
584
    """Add specified files or directories.
456
585
 
474
603
    you should never need to explicitly add a directory, they'll just
475
604
    get added when you add a file in the directory.
476
605
 
477
 
    --dry-run will show which files would be added, but not actually 
 
606
    --dry-run will show which files would be added, but not actually
478
607
    add them.
479
608
 
480
609
    --file-ids-from will try to use the file ids from the supplied path.
484
613
    branches that will be merged later (without showing the two different
485
614
    adds as a conflict). It is also useful when merging another project
486
615
    into a subdirectory of this one.
 
616
    
 
617
    Any files matching patterns in the ignore list will not be added
 
618
    unless they are explicitly mentioned.
487
619
    """
488
620
    takes_args = ['file*']
489
621
    takes_options = [
497
629
               help='Lookup file ids from this tree.'),
498
630
        ]
499
631
    encoding_type = 'replace'
500
 
    _see_also = ['remove']
 
632
    _see_also = ['remove', 'ignore']
501
633
 
502
634
    def run(self, file_list, no_recurse=False, dry_run=False, verbose=False,
503
635
            file_ids_from=None):
521
653
 
522
654
        if base_tree:
523
655
            base_tree.lock_read()
524
 
        try:
525
 
            file_list = self._maybe_expand_globs(file_list)
526
 
            if file_list:
527
 
                tree = WorkingTree.open_containing(file_list[0])[0]
528
 
            else:
529
 
                tree = WorkingTree.open_containing(u'.')[0]
530
 
            added, ignored = tree.smart_add(file_list, not
531
 
                no_recurse, action=action, save=not dry_run)
532
 
        finally:
533
 
            if base_tree is not None:
534
 
                base_tree.unlock()
535
 
        if not is_quiet() and len(added) > 0:
536
 
            self.outf.write('add completed\n')
 
656
            self.add_cleanup(base_tree.unlock)
 
657
        tree, file_list = tree_files_for_add(file_list)
 
658
        added, ignored = tree.smart_add(file_list, not
 
659
            no_recurse, action=action, save=not dry_run)
 
660
        self.cleanup_now()
537
661
        if len(ignored) > 0:
538
662
            if verbose:
539
663
                for glob in sorted(ignored.keys()):
540
664
                    for path in ignored[glob]:
541
 
                        self.outf.write("ignored %s matching \"%s\"\n" 
 
665
                        self.outf.write("ignored %s matching \"%s\"\n"
542
666
                                        % (path, glob))
543
 
            else:
544
 
                match_len = 0
545
 
                for glob, paths in ignored.items():
546
 
                    match_len += len(paths)
547
 
                self.outf.write("ignored %d file(s).\n" % match_len)
548
 
            self.outf.write("If you wish to add some of these files,"
549
 
                            " please add them by name.\n")
550
667
 
551
668
 
552
669
class cmd_mkdir(Command):
571
688
 
572
689
    takes_args = ['filename']
573
690
    hidden = True
574
 
    
 
691
 
575
692
    @display_command
576
693
    def run(self, filename):
577
694
        # TODO: jam 20050106 Can relpath return a munged path if
610
727
        revision = _get_one_revision('inventory', revision)
611
728
        work_tree, file_list = tree_files(file_list)
612
729
        work_tree.lock_read()
613
 
        try:
614
 
            if revision is not None:
615
 
                tree = revision.as_tree(work_tree.branch)
616
 
 
617
 
                extra_trees = [work_tree]
618
 
                tree.lock_read()
619
 
            else:
620
 
                tree = work_tree
621
 
                extra_trees = []
622
 
 
623
 
            if file_list is not None:
624
 
                file_ids = tree.paths2ids(file_list, trees=extra_trees,
625
 
                                          require_versioned=True)
626
 
                # find_ids_across_trees may include some paths that don't
627
 
                # exist in 'tree'.
628
 
                entries = sorted((tree.id2path(file_id), tree.inventory[file_id])
629
 
                                 for file_id in file_ids if file_id in tree)
630
 
            else:
631
 
                entries = tree.inventory.entries()
632
 
        finally:
633
 
            tree.unlock()
634
 
            if tree is not work_tree:
635
 
                work_tree.unlock()
636
 
 
 
730
        self.add_cleanup(work_tree.unlock)
 
731
        if revision is not None:
 
732
            tree = revision.as_tree(work_tree.branch)
 
733
 
 
734
            extra_trees = [work_tree]
 
735
            tree.lock_read()
 
736
            self.add_cleanup(tree.unlock)
 
737
        else:
 
738
            tree = work_tree
 
739
            extra_trees = []
 
740
 
 
741
        if file_list is not None:
 
742
            file_ids = tree.paths2ids(file_list, trees=extra_trees,
 
743
                                      require_versioned=True)
 
744
            # find_ids_across_trees may include some paths that don't
 
745
            # exist in 'tree'.
 
746
            entries = sorted((tree.id2path(file_id), tree.inventory[file_id])
 
747
                             for file_id in file_ids if file_id in tree)
 
748
        else:
 
749
            entries = tree.inventory.entries()
 
750
 
 
751
        self.cleanup_now()
637
752
        for path, entry in entries:
638
753
            if kind and kind != entry.kind:
639
754
                continue
668
783
    takes_args = ['names*']
669
784
    takes_options = [Option("after", help="Move only the bzr identifier"
670
785
        " of the file, because the file has already been moved."),
 
786
        Option('auto', help='Automatically guess renames.'),
 
787
        Option('dry-run', help='Avoid making changes when guessing renames.'),
671
788
        ]
672
789
    aliases = ['move', 'rename']
673
790
    encoding_type = 'replace'
674
791
 
675
 
    def run(self, names_list, after=False):
 
792
    def run(self, names_list, after=False, auto=False, dry_run=False):
 
793
        if auto:
 
794
            return self.run_auto(names_list, after, dry_run)
 
795
        elif dry_run:
 
796
            raise errors.BzrCommandError('--dry-run requires --auto.')
676
797
        if names_list is None:
677
798
            names_list = []
678
 
 
679
799
        if len(names_list) < 2:
680
800
            raise errors.BzrCommandError("missing file argument")
681
801
        tree, rel_names = tree_files(names_list, canonicalize=False)
682
 
        tree.lock_write()
683
 
        try:
684
 
            self._run(tree, names_list, rel_names, after)
685
 
        finally:
686
 
            tree.unlock()
 
802
        tree.lock_tree_write()
 
803
        self.add_cleanup(tree.unlock)
 
804
        self._run(tree, names_list, rel_names, after)
 
805
 
 
806
    def run_auto(self, names_list, after, dry_run):
 
807
        if names_list is not None and len(names_list) > 1:
 
808
            raise errors.BzrCommandError('Only one path may be specified to'
 
809
                                         ' --auto.')
 
810
        if after:
 
811
            raise errors.BzrCommandError('--after cannot be specified with'
 
812
                                         ' --auto.')
 
813
        work_tree, file_list = tree_files(names_list, default_branch='.')
 
814
        work_tree.lock_tree_write()
 
815
        self.add_cleanup(work_tree.unlock)
 
816
        rename_map.RenameMap.guess_renames(work_tree, dry_run)
687
817
 
688
818
    def _run(self, tree, names_list, rel_names, after):
689
819
        into_existing = osutils.isdir(names_list[-1])
710
840
            # All entries reference existing inventory items, so fix them up
711
841
            # for cicp file-systems.
712
842
            rel_names = tree.get_canonical_inventory_paths(rel_names)
713
 
            for pair in tree.move(rel_names[:-1], rel_names[-1], after=after):
714
 
                self.outf.write("%s => %s\n" % pair)
 
843
            for src, dest in tree.move(rel_names[:-1], rel_names[-1], after=after):
 
844
                if not is_quiet():
 
845
                    self.outf.write("%s => %s\n" % (src, dest))
715
846
        else:
716
847
            if len(names_list) != 2:
717
848
                raise errors.BzrCommandError('to mv multiple files the'
748
879
                        # pathjoin with an empty tail adds a slash, which breaks
749
880
                        # relpath :(
750
881
                        dest_parent_fq = tree.basedir
751
 
    
 
882
 
752
883
                    dest_tail = osutils.canonical_relpath(
753
884
                                    dest_parent_fq,
754
885
                                    osutils.pathjoin(dest_parent_fq, spec_tail))
761
892
            dest = osutils.pathjoin(dest_parent, dest_tail)
762
893
            mutter("attempting to move %s => %s", src, dest)
763
894
            tree.rename_one(src, dest, after=after)
764
 
            self.outf.write("%s => %s\n" % (src, dest))
 
895
            if not is_quiet():
 
896
                self.outf.write("%s => %s\n" % (src, dest))
765
897
 
766
898
 
767
899
class cmd_pull(Command):
768
900
    """Turn this branch into a mirror of another branch.
769
901
 
770
 
    This command only works on branches that have not diverged.  Branches are
771
 
    considered diverged if the destination branch's most recent commit is one
772
 
    that has not been merged (directly or indirectly) into the parent.
 
902
    By default, this command only works on branches that have not diverged.
 
903
    Branches are considered diverged if the destination branch's most recent 
 
904
    commit is one that has not been merged (directly or indirectly) into the 
 
905
    parent.
773
906
 
774
907
    If branches have diverged, you can use 'bzr merge' to integrate the changes
775
908
    from one into the other.  Once one branch has merged, the other should
776
909
    be able to pull it again.
777
910
 
778
 
    If you want to forget your local changes and just update your branch to
779
 
    match the remote one, use pull --overwrite.
 
911
    If you want to replace your local changes and just want your branch to
 
912
    match the remote one, use pull --overwrite. This will work even if the two
 
913
    branches have diverged.
780
914
 
781
915
    If there is no default location set, the first pull will set it.  After
782
916
    that, you can omit the location to use the default.  To change the
788
922
    with bzr send.
789
923
    """
790
924
 
791
 
    _see_also = ['push', 'update', 'status-flags']
 
925
    _see_also = ['push', 'update', 'status-flags', 'send']
792
926
    takes_options = ['remember', 'overwrite', 'revision',
793
927
        custom_help('verbose',
794
928
            help='Show logs of pulled revisions.'),
798
932
            short_name='d',
799
933
            type=unicode,
800
934
            ),
 
935
        Option('local',
 
936
            help="Perform a local pull in a bound "
 
937
                 "branch.  Local pulls are not applied to "
 
938
                 "the master branch."
 
939
            ),
801
940
        ]
802
941
    takes_args = ['location?']
803
942
    encoding_type = 'replace'
804
943
 
805
944
    def run(self, location=None, remember=False, overwrite=False,
806
945
            revision=None, verbose=False,
807
 
            directory=None):
 
946
            directory=None, local=False):
808
947
        # FIXME: too much stuff is in the command class
809
948
        revision_id = None
810
949
        mergeable = None
816
955
        except errors.NoWorkingTree:
817
956
            tree_to = None
818
957
            branch_to = Branch.open_containing(directory)[0]
 
958
        
 
959
        if local and not branch_to.get_bound_location():
 
960
            raise errors.LocalRequiresBoundBranch()
819
961
 
820
962
        possible_transports = []
821
963
        if location is not None:
853
995
            if branch_to.get_parent() is None or remember:
854
996
                branch_to.set_parent(branch_from.base)
855
997
 
 
998
        if branch_from is not branch_to:
 
999
            branch_from.lock_read()
 
1000
            self.add_cleanup(branch_from.unlock)
856
1001
        if revision is not None:
857
1002
            revision_id = revision.as_revision_id(branch_from)
858
1003
 
859
1004
        branch_to.lock_write()
860
 
        try:
861
 
            if tree_to is not None:
862
 
                change_reporter = delta._ChangeReporter(
863
 
                    unversioned_filter=tree_to.is_ignored)
864
 
                result = tree_to.pull(branch_from, overwrite, revision_id,
865
 
                                      change_reporter,
866
 
                                      possible_transports=possible_transports)
867
 
            else:
868
 
                result = branch_to.pull(branch_from, overwrite, revision_id)
 
1005
        self.add_cleanup(branch_to.unlock)
 
1006
        if tree_to is not None:
 
1007
            view_info = _get_view_info_for_change_reporter(tree_to)
 
1008
            change_reporter = delta._ChangeReporter(
 
1009
                unversioned_filter=tree_to.is_ignored,
 
1010
                view_info=view_info)
 
1011
            result = tree_to.pull(
 
1012
                branch_from, overwrite, revision_id, change_reporter,
 
1013
                possible_transports=possible_transports, local=local)
 
1014
        else:
 
1015
            result = branch_to.pull(
 
1016
                branch_from, overwrite, revision_id, local=local)
869
1017
 
870
 
            result.report(self.outf)
871
 
            if verbose and result.old_revid != result.new_revid:
872
 
                log.show_branch_change(branch_to, self.outf, result.old_revno,
873
 
                                       result.old_revid)
874
 
        finally:
875
 
            branch_to.unlock()
 
1018
        result.report(self.outf)
 
1019
        if verbose and result.old_revid != result.new_revid:
 
1020
            log.show_branch_change(
 
1021
                branch_to, self.outf, result.old_revno,
 
1022
                result.old_revid)
876
1023
 
877
1024
 
878
1025
class cmd_push(Command):
879
1026
    """Update a mirror of this branch.
880
 
    
 
1027
 
881
1028
    The target branch will not have its working tree populated because this
882
1029
    is both expensive, and is not supported on remote file systems.
883
 
    
 
1030
 
884
1031
    Some smart servers or protocols *may* put the working tree in place in
885
1032
    the future.
886
1033
 
890
1037
 
891
1038
    If branches have diverged, you can use 'bzr push --overwrite' to replace
892
1039
    the other branch completely, discarding its unmerged changes.
893
 
    
 
1040
 
894
1041
    If you want to ensure you have the different changes in the other branch,
895
1042
    do a merge (see bzr help merge) from the other branch, and commit that.
896
1043
    After that you will be able to do a push without '--overwrite'.
925
1072
                'for the commit history. Only the work not present in the '
926
1073
                'referenced branch is included in the branch created.',
927
1074
            type=unicode),
 
1075
        Option('strict',
 
1076
               help='Refuse to push if there are uncommitted changes in'
 
1077
               ' the working tree, --no-strict disables the check.'),
928
1078
        ]
929
1079
    takes_args = ['location?']
930
1080
    encoding_type = 'replace'
932
1082
    def run(self, location=None, remember=False, overwrite=False,
933
1083
        create_prefix=False, verbose=False, revision=None,
934
1084
        use_existing_dir=False, directory=None, stacked_on=None,
935
 
        stacked=False):
 
1085
        stacked=False, strict=None):
936
1086
        from bzrlib.push import _show_push_branch
937
1087
 
938
 
        # Get the source branch and revision_id
939
1088
        if directory is None:
940
1089
            directory = '.'
941
 
        br_from = Branch.open_containing(directory)[0]
 
1090
        # Get the source branch
 
1091
        (tree, br_from,
 
1092
         _unused) = bzrdir.BzrDir.open_containing_tree_or_branch(directory)
 
1093
        if strict is None:
 
1094
            strict = br_from.get_config().get_user_option_as_bool('push_strict')
 
1095
        if strict is None: strict = True # default value
 
1096
        # Get the tip's revision_id
942
1097
        revision = _get_one_revision('push', revision)
943
1098
        if revision is not None:
944
1099
            revision_id = revision.in_history(br_from).rev_id
945
1100
        else:
946
 
            revision_id = br_from.last_revision()
 
1101
            revision_id = None
 
1102
        if strict and tree is not None and revision_id is None:
 
1103
            if (tree.has_changes()):
 
1104
                raise errors.UncommittedChanges(
 
1105
                    tree, more='Use --no-strict to force the push.')
 
1106
            if tree.last_revision() != tree.branch.last_revision():
 
1107
                # The tree has lost sync with its branch, there is little
 
1108
                # chance that the user is aware of it but he can still force
 
1109
                # the push with --no-strict
 
1110
                raise errors.OutOfDateTree(
 
1111
                    tree, more='Use --no-strict to force the push.')
947
1112
 
948
1113
        # Get the stacked_on branch, if any
949
1114
        if stacked_on is not None:
982
1147
 
983
1148
 
984
1149
class cmd_branch(Command):
985
 
    """Create a new copy of a branch.
 
1150
    """Create a new branch that is a copy of an existing branch.
986
1151
 
987
1152
    If the TO_LOCATION is omitted, the last component of the FROM_LOCATION will
988
1153
    be used.  In other words, "branch ../foo/bar" will attempt to create ./bar.
999
1164
    takes_args = ['from_location', 'to_location?']
1000
1165
    takes_options = ['revision', Option('hardlink',
1001
1166
        help='Hard-link working tree files where possible.'),
 
1167
        Option('no-tree',
 
1168
            help="Create a branch without a working-tree."),
 
1169
        Option('switch',
 
1170
            help="Switch the checkout in the current directory "
 
1171
                 "to the new branch."),
1002
1172
        Option('stacked',
1003
1173
            help='Create a stacked branch referring to the source branch. '
1004
1174
                'The new branch will depend on the availability of the source '
1005
1175
                'branch for all operations.'),
1006
1176
        Option('standalone',
1007
1177
               help='Do not use a shared repository, even if available.'),
 
1178
        Option('use-existing-dir',
 
1179
               help='By default branch will fail if the target'
 
1180
                    ' directory exists, but does not already'
 
1181
                    ' have a control directory.  This flag will'
 
1182
                    ' allow branch to proceed.'),
1008
1183
        ]
1009
1184
    aliases = ['get', 'clone']
1010
1185
 
1011
1186
    def run(self, from_location, to_location=None, revision=None,
1012
 
            hardlink=False, stacked=False, standalone=False):
 
1187
            hardlink=False, stacked=False, standalone=False, no_tree=False,
 
1188
            use_existing_dir=False, switch=False):
 
1189
        from bzrlib import switch as _mod_switch
1013
1190
        from bzrlib.tag import _merge_tags_if_possible
1014
 
 
1015
1191
        accelerator_tree, br_from = bzrdir.BzrDir.open_tree_or_branch(
1016
1192
            from_location)
1017
1193
        revision = _get_one_revision('branch', revision)
1018
1194
        br_from.lock_read()
 
1195
        self.add_cleanup(br_from.unlock)
 
1196
        if revision is not None:
 
1197
            revision_id = revision.as_revision_id(br_from)
 
1198
        else:
 
1199
            # FIXME - wt.last_revision, fallback to branch, fall back to
 
1200
            # None or perhaps NULL_REVISION to mean copy nothing
 
1201
            # RBC 20060209
 
1202
            revision_id = br_from.last_revision()
 
1203
        if to_location is None:
 
1204
            to_location = urlutils.derive_to_location(from_location)
 
1205
        to_transport = transport.get_transport(to_location)
1019
1206
        try:
1020
 
            if revision is not None:
1021
 
                revision_id = revision.as_revision_id(br_from)
 
1207
            to_transport.mkdir('.')
 
1208
        except errors.FileExists:
 
1209
            if not use_existing_dir:
 
1210
                raise errors.BzrCommandError('Target directory "%s" '
 
1211
                    'already exists.' % to_location)
1022
1212
            else:
1023
 
                # FIXME - wt.last_revision, fallback to branch, fall back to
1024
 
                # None or perhaps NULL_REVISION to mean copy nothing
1025
 
                # RBC 20060209
1026
 
                revision_id = br_from.last_revision()
1027
 
            if to_location is None:
1028
 
                to_location = urlutils.derive_to_location(from_location)
1029
 
            to_transport = transport.get_transport(to_location)
1030
 
            try:
1031
 
                to_transport.mkdir('.')
1032
 
            except errors.FileExists:
1033
 
                raise errors.BzrCommandError('Target directory "%s" already'
1034
 
                                             ' exists.' % to_location)
1035
 
            except errors.NoSuchFile:
1036
 
                raise errors.BzrCommandError('Parent of "%s" does not exist.'
1037
 
                                             % to_location)
1038
 
            try:
1039
 
                # preserve whatever source format we have.
1040
 
                dir = br_from.bzrdir.sprout(to_transport.base, revision_id,
1041
 
                                            possible_transports=[to_transport],
1042
 
                                            accelerator_tree=accelerator_tree,
1043
 
                                            hardlink=hardlink, stacked=stacked,
1044
 
                                            force_new_repo=standalone,
1045
 
                                            source_branch=br_from)
1046
 
                branch = dir.open_branch()
1047
 
            except errors.NoSuchRevision:
1048
 
                to_transport.delete_tree('.')
1049
 
                msg = "The branch %s has no revision %s." % (from_location,
1050
 
                    revision)
1051
 
                raise errors.BzrCommandError(msg)
1052
 
            _merge_tags_if_possible(br_from, branch)
1053
 
            # If the source branch is stacked, the new branch may
1054
 
            # be stacked whether we asked for that explicitly or not.
1055
 
            # We therefore need a try/except here and not just 'if stacked:'
1056
 
            try:
1057
 
                note('Created new stacked branch referring to %s.' %
1058
 
                    branch.get_stacked_on_url())
1059
 
            except (errors.NotStacked, errors.UnstackableBranchFormat,
1060
 
                errors.UnstackableRepositoryFormat), e:
1061
 
                note('Branched %d revision(s).' % branch.revno())
1062
 
        finally:
1063
 
            br_from.unlock()
 
1213
                try:
 
1214
                    bzrdir.BzrDir.open_from_transport(to_transport)
 
1215
                except errors.NotBranchError:
 
1216
                    pass
 
1217
                else:
 
1218
                    raise errors.AlreadyBranchError(to_location)
 
1219
        except errors.NoSuchFile:
 
1220
            raise errors.BzrCommandError('Parent of "%s" does not exist.'
 
1221
                                         % to_location)
 
1222
        try:
 
1223
            # preserve whatever source format we have.
 
1224
            dir = br_from.bzrdir.sprout(to_transport.base, revision_id,
 
1225
                                        possible_transports=[to_transport],
 
1226
                                        accelerator_tree=accelerator_tree,
 
1227
                                        hardlink=hardlink, stacked=stacked,
 
1228
                                        force_new_repo=standalone,
 
1229
                                        create_tree_if_local=not no_tree,
 
1230
                                        source_branch=br_from)
 
1231
            branch = dir.open_branch()
 
1232
        except errors.NoSuchRevision:
 
1233
            to_transport.delete_tree('.')
 
1234
            msg = "The branch %s has no revision %s." % (from_location,
 
1235
                revision)
 
1236
            raise errors.BzrCommandError(msg)
 
1237
        _merge_tags_if_possible(br_from, branch)
 
1238
        # If the source branch is stacked, the new branch may
 
1239
        # be stacked whether we asked for that explicitly or not.
 
1240
        # We therefore need a try/except here and not just 'if stacked:'
 
1241
        try:
 
1242
            note('Created new stacked branch referring to %s.' %
 
1243
                branch.get_stacked_on_url())
 
1244
        except (errors.NotStacked, errors.UnstackableBranchFormat,
 
1245
            errors.UnstackableRepositoryFormat), e:
 
1246
            note('Branched %d revision(s).' % branch.revno())
 
1247
        if switch:
 
1248
            # Switch to the new branch
 
1249
            wt, _ = WorkingTree.open_containing('.')
 
1250
            _mod_switch.switch(wt.bzrdir, branch)
 
1251
            note('Switched to branch: %s',
 
1252
                urlutils.unescape_for_display(branch.base, 'utf-8'))
1064
1253
 
1065
1254
 
1066
1255
class cmd_checkout(Command):
1070
1259
    the branch found in '.'. This is useful if you have removed the working tree
1071
1260
    or if it was never created - i.e. if you pushed the branch to its current
1072
1261
    location using SFTP.
1073
 
    
 
1262
 
1074
1263
    If the TO_LOCATION is omitted, the last component of the BRANCH_LOCATION will
1075
1264
    be used.  In other words, "checkout ../foo/bar" will attempt to create ./bar.
1076
1265
    If the BRANCH_LOCATION has no / or path separator embedded, the TO_LOCATION
1118
1307
            revision_id = None
1119
1308
        if to_location is None:
1120
1309
            to_location = urlutils.derive_to_location(branch_location)
1121
 
        # if the source and to_location are the same, 
 
1310
        # if the source and to_location are the same,
1122
1311
        # and there is no working tree,
1123
1312
        # then reconstitute a branch
1124
1313
        if (osutils.abspath(to_location) ==
1145
1334
    def run(self, dir=u'.'):
1146
1335
        tree = WorkingTree.open_containing(dir)[0]
1147
1336
        tree.lock_read()
1148
 
        try:
1149
 
            new_inv = tree.inventory
1150
 
            old_tree = tree.basis_tree()
1151
 
            old_tree.lock_read()
1152
 
            try:
1153
 
                old_inv = old_tree.inventory
1154
 
                renames = []
1155
 
                iterator = tree.iter_changes(old_tree, include_unchanged=True)
1156
 
                for f, paths, c, v, p, n, k, e in iterator:
1157
 
                    if paths[0] == paths[1]:
1158
 
                        continue
1159
 
                    if None in (paths):
1160
 
                        continue
1161
 
                    renames.append(paths)
1162
 
                renames.sort()
1163
 
                for old_name, new_name in renames:
1164
 
                    self.outf.write("%s => %s\n" % (old_name, new_name))
1165
 
            finally:
1166
 
                old_tree.unlock()
1167
 
        finally:
1168
 
            tree.unlock()
 
1337
        self.add_cleanup(tree.unlock)
 
1338
        new_inv = tree.inventory
 
1339
        old_tree = tree.basis_tree()
 
1340
        old_tree.lock_read()
 
1341
        self.add_cleanup(old_tree.unlock)
 
1342
        old_inv = old_tree.inventory
 
1343
        renames = []
 
1344
        iterator = tree.iter_changes(old_tree, include_unchanged=True)
 
1345
        for f, paths, c, v, p, n, k, e in iterator:
 
1346
            if paths[0] == paths[1]:
 
1347
                continue
 
1348
            if None in (paths):
 
1349
                continue
 
1350
            renames.append(paths)
 
1351
        renames.sort()
 
1352
        for old_name, new_name in renames:
 
1353
            self.outf.write("%s => %s\n" % (old_name, new_name))
1169
1354
 
1170
1355
 
1171
1356
class cmd_update(Command):
1172
1357
    """Update a tree to have the latest code committed to its branch.
1173
 
    
 
1358
 
1174
1359
    This will perform a merge into the working tree, and may generate
1175
 
    conflicts. If you have any local changes, you will still 
 
1360
    conflicts. If you have any local changes, you will still
1176
1361
    need to commit them after the update for the update to be complete.
1177
 
    
1178
 
    If you want to discard your local changes, you can just do a 
 
1362
 
 
1363
    If you want to discard your local changes, you can just do a
1179
1364
    'bzr revert' instead of 'bzr commit' after the update.
 
1365
 
 
1366
    If the tree's branch is bound to a master branch, it will also update
 
1367
    the branch from the master.
1180
1368
    """
1181
1369
 
1182
1370
    _see_also = ['pull', 'working-trees', 'status-flags']
1183
1371
    takes_args = ['dir?']
 
1372
    takes_options = ['revision']
1184
1373
    aliases = ['up']
1185
1374
 
1186
 
    def run(self, dir='.'):
 
1375
    def run(self, dir='.', revision=None):
 
1376
        if revision is not None and len(revision) != 1:
 
1377
            raise errors.BzrCommandError(
 
1378
                        "bzr update --revision takes exactly one revision")
1187
1379
        tree = WorkingTree.open_containing(dir)[0]
 
1380
        branch = tree.branch
1188
1381
        possible_transports = []
1189
 
        master = tree.branch.get_master_branch(
 
1382
        master = branch.get_master_branch(
1190
1383
            possible_transports=possible_transports)
1191
1384
        if master is not None:
1192
1385
            tree.lock_write()
 
1386
            branch_location = master.base
1193
1387
        else:
1194
1388
            tree.lock_tree_write()
 
1389
            branch_location = tree.branch.base
 
1390
        self.add_cleanup(tree.unlock)
 
1391
        # get rid of the final '/' and be ready for display
 
1392
        branch_location = urlutils.unescape_for_display(branch_location[:-1],
 
1393
                                                        self.outf.encoding)
 
1394
        existing_pending_merges = tree.get_parent_ids()[1:]
 
1395
        if master is None:
 
1396
            old_tip = None
 
1397
        else:
 
1398
            # may need to fetch data into a heavyweight checkout
 
1399
            # XXX: this may take some time, maybe we should display a
 
1400
            # message
 
1401
            old_tip = branch.update(possible_transports)
 
1402
        if revision is not None:
 
1403
            revision_id = revision[0].as_revision_id(branch)
 
1404
        else:
 
1405
            revision_id = branch.last_revision()
 
1406
        if revision_id == _mod_revision.ensure_null(tree.last_revision()):
 
1407
            revno = branch.revision_id_to_revno(revision_id)
 
1408
            note("Tree is up to date at revision %d of branch %s" %
 
1409
                (revno, branch_location))
 
1410
            return 0
 
1411
        view_info = _get_view_info_for_change_reporter(tree)
 
1412
        change_reporter = delta._ChangeReporter(
 
1413
            unversioned_filter=tree.is_ignored,
 
1414
            view_info=view_info)
1195
1415
        try:
1196
 
            existing_pending_merges = tree.get_parent_ids()[1:]
1197
 
            last_rev = _mod_revision.ensure_null(tree.last_revision())
1198
 
            if last_rev == _mod_revision.ensure_null(
1199
 
                tree.branch.last_revision()):
1200
 
                # may be up to date, check master too.
1201
 
                if master is None or last_rev == _mod_revision.ensure_null(
1202
 
                    master.last_revision()):
1203
 
                    revno = tree.branch.revision_id_to_revno(last_rev)
1204
 
                    note("Tree is up to date at revision %d." % (revno,))
1205
 
                    return 0
1206
1416
            conflicts = tree.update(
1207
 
                delta._ChangeReporter(unversioned_filter=tree.is_ignored),
1208
 
                possible_transports=possible_transports)
1209
 
            revno = tree.branch.revision_id_to_revno(
1210
 
                _mod_revision.ensure_null(tree.last_revision()))
1211
 
            note('Updated to revision %d.' % (revno,))
1212
 
            if tree.get_parent_ids()[1:] != existing_pending_merges:
1213
 
                note('Your local commits will now show as pending merges with '
1214
 
                     "'bzr status', and can be committed with 'bzr commit'.")
1215
 
            if conflicts != 0:
1216
 
                return 1
1217
 
            else:
1218
 
                return 0
1219
 
        finally:
1220
 
            tree.unlock()
 
1417
                change_reporter,
 
1418
                possible_transports=possible_transports,
 
1419
                revision=revision_id,
 
1420
                old_tip=old_tip)
 
1421
        except errors.NoSuchRevision, e:
 
1422
            raise errors.BzrCommandError(
 
1423
                                  "branch has no revision %s\n"
 
1424
                                  "bzr update --revision only works"
 
1425
                                  " for a revision in the branch history"
 
1426
                                  % (e.revision))
 
1427
        revno = tree.branch.revision_id_to_revno(
 
1428
            _mod_revision.ensure_null(tree.last_revision()))
 
1429
        note('Updated to revision %d of branch %s' %
 
1430
             (revno, branch_location))
 
1431
        if tree.get_parent_ids()[1:] != existing_pending_merges:
 
1432
            note('Your local commits will now show as pending merges with '
 
1433
                 "'bzr status', and can be committed with 'bzr commit'.")
 
1434
        if conflicts != 0:
 
1435
            return 1
 
1436
        else:
 
1437
            return 0
1221
1438
 
1222
1439
 
1223
1440
class cmd_info(Command):
1224
1441
    """Show information about a working tree, branch or repository.
1225
1442
 
1226
1443
    This command will show all known locations and formats associated to the
1227
 
    tree, branch or repository.  Statistical information is included with
1228
 
    each report.
 
1444
    tree, branch or repository.
 
1445
 
 
1446
    In verbose mode, statistical information is included with each report.
 
1447
    To see extended statistic information, use a verbosity level of 2 or
 
1448
    higher by specifying the verbose option multiple times, e.g. -vv.
1229
1449
 
1230
1450
    Branches and working trees will also report any missing revisions.
 
1451
 
 
1452
    :Examples:
 
1453
 
 
1454
      Display information on the format and related locations:
 
1455
 
 
1456
        bzr info
 
1457
 
 
1458
      Display the above together with extended format information and
 
1459
      basic statistics (like the number of files in the working tree and
 
1460
      number of revisions in the branch and repository):
 
1461
 
 
1462
        bzr info -v
 
1463
 
 
1464
      Display the above together with number of committers to the branch:
 
1465
 
 
1466
        bzr info -vv
1231
1467
    """
1232
1468
    _see_also = ['revno', 'working-trees', 'repositories']
1233
1469
    takes_args = ['location?']
1237
1473
    @display_command
1238
1474
    def run(self, location=None, verbose=False):
1239
1475
        if verbose:
1240
 
            noise_level = 2
 
1476
            noise_level = get_verbosity_level()
1241
1477
        else:
1242
1478
            noise_level = 0
1243
1479
        from bzrlib.info import show_bzrdir_info
1261
1497
            title='Deletion Strategy', value_switches=True, enum_switch=False,
1262
1498
            safe='Only delete files if they can be'
1263
1499
                 ' safely recovered (default).',
1264
 
            keep="Don't delete any files.",
 
1500
            keep='Delete from bzr but leave the working copy.',
1265
1501
            force='Delete all the specified files, even if they can not be '
1266
1502
                'recovered and even if they are non-empty directories.')]
1267
1503
    aliases = ['rm', 'del']
1275
1511
            file_list = [f for f in file_list]
1276
1512
 
1277
1513
        tree.lock_write()
1278
 
        try:
1279
 
            # Heuristics should probably all move into tree.remove_smart or
1280
 
            # some such?
1281
 
            if new:
1282
 
                added = tree.changes_from(tree.basis_tree(),
1283
 
                    specific_files=file_list).added
1284
 
                file_list = sorted([f[0] for f in added], reverse=True)
1285
 
                if len(file_list) == 0:
1286
 
                    raise errors.BzrCommandError('No matching files.')
1287
 
            elif file_list is None:
1288
 
                # missing files show up in iter_changes(basis) as
1289
 
                # versioned-with-no-kind.
1290
 
                missing = []
1291
 
                for change in tree.iter_changes(tree.basis_tree()):
1292
 
                    # Find paths in the working tree that have no kind:
1293
 
                    if change[1][1] is not None and change[6][1] is None:
1294
 
                        missing.append(change[1][1])
1295
 
                file_list = sorted(missing, reverse=True)
1296
 
                file_deletion_strategy = 'keep'
1297
 
            tree.remove(file_list, verbose=verbose, to_file=self.outf,
1298
 
                keep_files=file_deletion_strategy=='keep',
1299
 
                force=file_deletion_strategy=='force')
1300
 
        finally:
1301
 
            tree.unlock()
 
1514
        self.add_cleanup(tree.unlock)
 
1515
        # Heuristics should probably all move into tree.remove_smart or
 
1516
        # some such?
 
1517
        if new:
 
1518
            added = tree.changes_from(tree.basis_tree(),
 
1519
                specific_files=file_list).added
 
1520
            file_list = sorted([f[0] for f in added], reverse=True)
 
1521
            if len(file_list) == 0:
 
1522
                raise errors.BzrCommandError('No matching files.')
 
1523
        elif file_list is None:
 
1524
            # missing files show up in iter_changes(basis) as
 
1525
            # versioned-with-no-kind.
 
1526
            missing = []
 
1527
            for change in tree.iter_changes(tree.basis_tree()):
 
1528
                # Find paths in the working tree that have no kind:
 
1529
                if change[1][1] is not None and change[6][1] is None:
 
1530
                    missing.append(change[1][1])
 
1531
            file_list = sorted(missing, reverse=True)
 
1532
            file_deletion_strategy = 'keep'
 
1533
        tree.remove(file_list, verbose=verbose, to_file=self.outf,
 
1534
            keep_files=file_deletion_strategy=='keep',
 
1535
            force=file_deletion_strategy=='force')
1302
1536
 
1303
1537
 
1304
1538
class cmd_file_id(Command):
1350
1584
 
1351
1585
    This can correct data mismatches that may have been caused by
1352
1586
    previous ghost operations or bzr upgrades. You should only
1353
 
    need to run this command if 'bzr check' or a bzr developer 
 
1587
    need to run this command if 'bzr check' or a bzr developer
1354
1588
    advises you to run it.
1355
1589
 
1356
1590
    If a second branch is provided, cross-branch reconciliation is
1358
1592
    id which was not present in very early bzr versions is represented
1359
1593
    correctly in both branches.
1360
1594
 
1361
 
    At the same time it is run it may recompress data resulting in 
 
1595
    At the same time it is run it may recompress data resulting in
1362
1596
    a potential saving in disk space or performance gain.
1363
1597
 
1364
1598
    The branch *MUST* be on a listable system such as local disk or sftp.
1420
1654
    Use this to create an empty branch, or before importing an
1421
1655
    existing project.
1422
1656
 
1423
 
    If there is a repository in a parent directory of the location, then 
 
1657
    If there is a repository in a parent directory of the location, then
1424
1658
    the history of the branch will be stored in the repository.  Otherwise
1425
1659
    init creates a standalone branch which carries its own history
1426
1660
    in the .bzr directory.
1449
1683
                lazy_registry=('bzrlib.bzrdir', 'format_registry'),
1450
1684
                converter=lambda name: bzrdir.format_registry.make_bzrdir(name),
1451
1685
                value_switches=True,
1452
 
                title="Branch Format",
 
1686
                title="Branch format",
1453
1687
                ),
1454
1688
         Option('append-revisions-only',
1455
1689
                help='Never change revnos or the existing log.'
1478
1712
                    "\nYou may supply --create-prefix to create all"
1479
1713
                    " leading parent directories."
1480
1714
                    % location)
1481
 
            _create_prefix(to_transport)
 
1715
            to_transport.create_prefix()
1482
1716
 
1483
1717
        try:
1484
1718
            a_bzrdir = bzrdir.BzrDir.open_from_transport(to_transport)
1502
1736
                branch.set_append_revisions_only(True)
1503
1737
            except errors.UpgradeRequired:
1504
1738
                raise errors.BzrCommandError('This branch format cannot be set'
1505
 
                    ' to append-revisions-only.  Try --experimental-branch6')
 
1739
                    ' to append-revisions-only.  Try --default.')
1506
1740
        if not is_quiet():
1507
1741
            from bzrlib.info import describe_layout, describe_format
1508
1742
            try:
1524
1758
 
1525
1759
 
1526
1760
class cmd_init_repository(Command):
1527
 
    """Create a shared repository to hold branches.
 
1761
    """Create a shared repository for branches to share storage space.
1528
1762
 
1529
1763
    New branches created under the repository directory will store their
1530
 
    revisions in the repository, not in the branch directory.
 
1764
    revisions in the repository, not in the branch directory.  For branches
 
1765
    with shared history, this reduces the amount of storage needed and 
 
1766
    speeds up the creation of new branches.
1531
1767
 
1532
 
    If the --no-trees option is used then the branches in the repository
1533
 
    will not have working trees by default.
 
1768
    If the --no-trees option is given then the branches in the repository
 
1769
    will not have working trees by default.  They will still exist as 
 
1770
    directories on disk, but they will not have separate copies of the 
 
1771
    files at a certain revision.  This can be useful for repositories that
 
1772
    store branches which are interacted with through checkouts or remote
 
1773
    branches, such as on a server.
1534
1774
 
1535
1775
    :Examples:
1536
 
        Create a shared repositories holding just branches::
 
1776
        Create a shared repository holding just branches::
1537
1777
 
1538
1778
            bzr init-repo --no-trees repo
1539
1779
            bzr init repo/trunk
1579
1819
 
1580
1820
class cmd_diff(Command):
1581
1821
    """Show differences in the working tree, between revisions or branches.
1582
 
    
 
1822
 
1583
1823
    If no arguments are given, all changes for the current tree are listed.
1584
1824
    If files are given, only the changes in those files are listed.
1585
1825
    Remote and multiple branches can be compared by using the --old and
1605
1845
 
1606
1846
            bzr diff -r1
1607
1847
 
1608
 
        Difference between revision 2 and revision 1::
1609
 
 
1610
 
            bzr diff -r1..2
1611
 
 
1612
 
        Difference between revision 2 and revision 1 for branch xxx::
1613
 
 
1614
 
            bzr diff -r1..2 xxx
 
1848
        Difference between revision 3 and revision 1::
 
1849
 
 
1850
            bzr diff -r1..3
 
1851
 
 
1852
        Difference between revision 3 and revision 1 for branch xxx::
 
1853
 
 
1854
            bzr diff -r1..3 xxx
 
1855
 
 
1856
        To see the changes introduced in revision X::
 
1857
        
 
1858
            bzr diff -cX
 
1859
 
 
1860
        Note that in the case of a merge, the -c option shows the changes
 
1861
        compared to the left hand parent. To see the changes against
 
1862
        another parent, use::
 
1863
 
 
1864
            bzr diff -r<chosen_parent>..X
 
1865
 
 
1866
        The changes introduced by revision 2 (equivalent to -r1..2)::
 
1867
 
 
1868
            bzr diff -c2
1615
1869
 
1616
1870
        Show just the differences for file NEWS::
1617
1871
 
1663
1917
    @display_command
1664
1918
    def run(self, revision=None, file_list=None, diff_options=None,
1665
1919
            prefix=None, old=None, new=None, using=None):
1666
 
        from bzrlib.diff import _get_trees_to_diff, show_diff_trees
 
1920
        from bzrlib.diff import get_trees_and_branches_to_diff, show_diff_trees
1667
1921
 
1668
1922
        if (prefix is None) or (prefix == '0'):
1669
1923
            # diff -p0 format
1683
1937
            raise errors.BzrCommandError('bzr diff --revision takes exactly'
1684
1938
                                         ' one or two revision specifiers')
1685
1939
 
1686
 
        old_tree, new_tree, specific_files, extra_trees = \
1687
 
                _get_trees_to_diff(file_list, revision, old, new)
1688
 
        return show_diff_trees(old_tree, new_tree, sys.stdout, 
 
1940
        (old_tree, new_tree,
 
1941
         old_branch, new_branch,
 
1942
         specific_files, extra_trees) = get_trees_and_branches_to_diff(
 
1943
            file_list, revision, old, new, apply_view=True)
 
1944
        return show_diff_trees(old_tree, new_tree, sys.stdout,
1689
1945
                               specific_files=specific_files,
1690
1946
                               external_diff_options=diff_options,
1691
1947
                               old_label=old_label, new_label=new_label,
1708
1964
    def run(self, show_ids=False):
1709
1965
        tree = WorkingTree.open_containing(u'.')[0]
1710
1966
        tree.lock_read()
1711
 
        try:
1712
 
            old = tree.basis_tree()
1713
 
            old.lock_read()
1714
 
            try:
1715
 
                for path, ie in old.inventory.iter_entries():
1716
 
                    if not tree.has_id(ie.file_id):
1717
 
                        self.outf.write(path)
1718
 
                        if show_ids:
1719
 
                            self.outf.write(' ')
1720
 
                            self.outf.write(ie.file_id)
1721
 
                        self.outf.write('\n')
1722
 
            finally:
1723
 
                old.unlock()
1724
 
        finally:
1725
 
            tree.unlock()
 
1967
        self.add_cleanup(tree.unlock)
 
1968
        old = tree.basis_tree()
 
1969
        old.lock_read()
 
1970
        self.add_cleanup(old.unlock)
 
1971
        for path, ie in old.inventory.iter_entries():
 
1972
            if not tree.has_id(ie.file_id):
 
1973
                self.outf.write(path)
 
1974
                if show_ids:
 
1975
                    self.outf.write(' ')
 
1976
                    self.outf.write(ie.file_id)
 
1977
                self.outf.write('\n')
1726
1978
 
1727
1979
 
1728
1980
class cmd_modified(Command):
1764
2016
    def run(self, null=False):
1765
2017
        wt = WorkingTree.open_containing(u'.')[0]
1766
2018
        wt.lock_read()
1767
 
        try:
1768
 
            basis = wt.basis_tree()
1769
 
            basis.lock_read()
1770
 
            try:
1771
 
                basis_inv = basis.inventory
1772
 
                inv = wt.inventory
1773
 
                for file_id in inv:
1774
 
                    if file_id in basis_inv:
1775
 
                        continue
1776
 
                    if inv.is_root(file_id) and len(basis_inv) == 0:
1777
 
                        continue
1778
 
                    path = inv.id2path(file_id)
1779
 
                    if not os.access(osutils.abspath(path), os.F_OK):
1780
 
                        continue
1781
 
                    if null:
1782
 
                        self.outf.write(path + '\0')
1783
 
                    else:
1784
 
                        self.outf.write(osutils.quotefn(path) + '\n')
1785
 
            finally:
1786
 
                basis.unlock()
1787
 
        finally:
1788
 
            wt.unlock()
 
2019
        self.add_cleanup(wt.unlock)
 
2020
        basis = wt.basis_tree()
 
2021
        basis.lock_read()
 
2022
        self.add_cleanup(basis.unlock)
 
2023
        basis_inv = basis.inventory
 
2024
        inv = wt.inventory
 
2025
        for file_id in inv:
 
2026
            if file_id in basis_inv:
 
2027
                continue
 
2028
            if inv.is_root(file_id) and len(basis_inv) == 0:
 
2029
                continue
 
2030
            path = inv.id2path(file_id)
 
2031
            if not os.access(osutils.abspath(path), os.F_OK):
 
2032
                continue
 
2033
            if null:
 
2034
                self.outf.write(path + '\0')
 
2035
            else:
 
2036
                self.outf.write(osutils.quotefn(path) + '\n')
1789
2037
 
1790
2038
 
1791
2039
class cmd_root(Command):
1819
2067
 
1820
2068
 
1821
2069
class cmd_log(Command):
1822
 
    """Show log of a branch, file, or directory.
1823
 
 
1824
 
    By default show the log of the branch containing the working directory.
1825
 
 
1826
 
    To request a range of logs, you can use the command -r begin..end
1827
 
    -r revision requests a specific revision, -r ..end or -r begin.. are
1828
 
    also valid.
1829
 
 
1830
 
    :Examples:
1831
 
        Log the current branch::
1832
 
 
1833
 
            bzr log
1834
 
 
1835
 
        Log a file::
1836
 
 
1837
 
            bzr log foo.c
1838
 
 
1839
 
        Log the last 10 revisions of a branch::
1840
 
 
1841
 
            bzr log -r -10.. http://server/branch
 
2070
    """Show historical log for a branch or subset of a branch.
 
2071
 
 
2072
    log is bzr's default tool for exploring the history of a branch.
 
2073
    The branch to use is taken from the first parameter. If no parameters
 
2074
    are given, the branch containing the working directory is logged.
 
2075
    Here are some simple examples::
 
2076
 
 
2077
      bzr log                       log the current branch
 
2078
      bzr log foo.py                log a file in its branch
 
2079
      bzr log http://server/branch  log a branch on a server
 
2080
 
 
2081
    The filtering, ordering and information shown for each revision can
 
2082
    be controlled as explained below. By default, all revisions are
 
2083
    shown sorted (topologically) so that newer revisions appear before
 
2084
    older ones and descendants always appear before ancestors. If displayed,
 
2085
    merged revisions are shown indented under the revision in which they
 
2086
    were merged.
 
2087
 
 
2088
    :Output control:
 
2089
 
 
2090
      The log format controls how information about each revision is
 
2091
      displayed. The standard log formats are called ``long``, ``short``
 
2092
      and ``line``. The default is long. See ``bzr help log-formats``
 
2093
      for more details on log formats.
 
2094
 
 
2095
      The following options can be used to control what information is
 
2096
      displayed::
 
2097
 
 
2098
        -l N        display a maximum of N revisions
 
2099
        -n N        display N levels of revisions (0 for all, 1 for collapsed)
 
2100
        -v          display a status summary (delta) for each revision
 
2101
        -p          display a diff (patch) for each revision
 
2102
        --show-ids  display revision-ids (and file-ids), not just revnos
 
2103
 
 
2104
      Note that the default number of levels to display is a function of the
 
2105
      log format. If the -n option is not used, the standard log formats show
 
2106
      just the top level (mainline).
 
2107
 
 
2108
      Status summaries are shown using status flags like A, M, etc. To see
 
2109
      the changes explained using words like ``added`` and ``modified``
 
2110
      instead, use the -vv option.
 
2111
 
 
2112
    :Ordering control:
 
2113
 
 
2114
      To display revisions from oldest to newest, use the --forward option.
 
2115
      In most cases, using this option will have little impact on the total
 
2116
      time taken to produce a log, though --forward does not incrementally
 
2117
      display revisions like --reverse does when it can.
 
2118
 
 
2119
    :Revision filtering:
 
2120
 
 
2121
      The -r option can be used to specify what revision or range of revisions
 
2122
      to filter against. The various forms are shown below::
 
2123
 
 
2124
        -rX      display revision X
 
2125
        -rX..    display revision X and later
 
2126
        -r..Y    display up to and including revision Y
 
2127
        -rX..Y   display from X to Y inclusive
 
2128
 
 
2129
      See ``bzr help revisionspec`` for details on how to specify X and Y.
 
2130
      Some common examples are given below::
 
2131
 
 
2132
        -r-1                show just the tip
 
2133
        -r-10..             show the last 10 mainline revisions
 
2134
        -rsubmit:..         show what's new on this branch
 
2135
        -rancestor:path..   show changes since the common ancestor of this
 
2136
                            branch and the one at location path
 
2137
        -rdate:yesterday..  show changes since yesterday
 
2138
 
 
2139
      When logging a range of revisions using -rX..Y, log starts at
 
2140
      revision Y and searches back in history through the primary
 
2141
      ("left-hand") parents until it finds X. When logging just the
 
2142
      top level (using -n1), an error is reported if X is not found
 
2143
      along the way. If multi-level logging is used (-n0), X may be
 
2144
      a nested merge revision and the log will be truncated accordingly.
 
2145
 
 
2146
    :Path filtering:
 
2147
 
 
2148
      If parameters are given and the first one is not a branch, the log
 
2149
      will be filtered to show only those revisions that changed the
 
2150
      nominated files or directories.
 
2151
 
 
2152
      Filenames are interpreted within their historical context. To log a
 
2153
      deleted file, specify a revision range so that the file existed at
 
2154
      the end or start of the range.
 
2155
 
 
2156
      Historical context is also important when interpreting pathnames of
 
2157
      renamed files/directories. Consider the following example:
 
2158
 
 
2159
      * revision 1: add tutorial.txt
 
2160
      * revision 2: modify tutorial.txt
 
2161
      * revision 3: rename tutorial.txt to guide.txt; add tutorial.txt
 
2162
 
 
2163
      In this case:
 
2164
 
 
2165
      * ``bzr log guide.txt`` will log the file added in revision 1
 
2166
 
 
2167
      * ``bzr log tutorial.txt`` will log the new file added in revision 3
 
2168
 
 
2169
      * ``bzr log -r2 -p tutorial.txt`` will show the changes made to
 
2170
        the original file in revision 2.
 
2171
 
 
2172
      * ``bzr log -r2 -p guide.txt`` will display an error message as there
 
2173
        was no file called guide.txt in revision 2.
 
2174
 
 
2175
      Renames are always followed by log. By design, there is no need to
 
2176
      explicitly ask for this (and no way to stop logging a file back
 
2177
      until it was last renamed).
 
2178
 
 
2179
    :Other filtering:
 
2180
 
 
2181
      The --message option can be used for finding revisions that match a
 
2182
      regular expression in a commit message.
 
2183
 
 
2184
    :Tips & tricks:
 
2185
 
 
2186
      GUI tools and IDEs are often better at exploring history than command
 
2187
      line tools. You may prefer qlog or glog from the QBzr and Bzr-Gtk packages
 
2188
      respectively for example. (TortoiseBzr uses qlog for displaying logs.) See
 
2189
      http://bazaar-vcs.org/BzrPlugins and http://bazaar-vcs.org/IDEIntegration.
 
2190
 
 
2191
      Web interfaces are often better at exploring history than command line
 
2192
      tools, particularly for branches on servers. You may prefer Loggerhead
 
2193
      or one of its alternatives. See http://bazaar-vcs.org/WebInterface.
 
2194
 
 
2195
      You may find it useful to add the aliases below to ``bazaar.conf``::
 
2196
 
 
2197
        [ALIASES]
 
2198
        tip = log -r-1
 
2199
        top = log -l10 --line
 
2200
        show = log -v -p
 
2201
 
 
2202
      ``bzr tip`` will then show the latest revision while ``bzr top``
 
2203
      will show the last 10 mainline revisions. To see the details of a
 
2204
      particular revision X,  ``bzr show -rX``.
 
2205
 
 
2206
      If you are interested in looking deeper into a particular merge X,
 
2207
      use ``bzr log -n0 -rX``.
 
2208
 
 
2209
      ``bzr log -v`` on a branch with lots of history is currently
 
2210
      very slow. A fix for this issue is currently under development.
 
2211
      With or without that fix, it is recommended that a revision range
 
2212
      be given when using the -v option.
 
2213
 
 
2214
      bzr has a generic full-text matching plugin, bzr-search, that can be
 
2215
      used to find revisions matching user names, commit messages, etc.
 
2216
      Among other features, this plugin can find all revisions containing
 
2217
      a list of words but not others.
 
2218
 
 
2219
      When exploring non-mainline history on large projects with deep
 
2220
      history, the performance of log can be greatly improved by installing
 
2221
      the historycache plugin. This plugin buffers historical information
 
2222
      trading disk space for faster speed.
1842
2223
    """
1843
 
 
1844
 
    # TODO: Make --revision support uuid: and hash: [future tag:] notation.
1845
 
 
1846
 
    takes_args = ['location?']
 
2224
    takes_args = ['file*']
 
2225
    _see_also = ['log-formats', 'revisionspec']
1847
2226
    takes_options = [
1848
2227
            Option('forward',
1849
2228
                   help='Show from oldest to newest.'),
1876
2255
            Option('show-diff',
1877
2256
                   short_name='p',
1878
2257
                   help='Show changes made in each revision as a patch.'),
 
2258
            Option('include-merges',
 
2259
                   help='Show merged revisions like --levels 0 does.'),
1879
2260
            ]
1880
2261
    encoding_type = 'replace'
1881
2262
 
1882
2263
    @display_command
1883
 
    def run(self, location=None, timezone='original',
 
2264
    def run(self, file_list=None, timezone='original',
1884
2265
            verbose=False,
1885
2266
            show_ids=False,
1886
2267
            forward=False,
1890
2271
            levels=None,
1891
2272
            message=None,
1892
2273
            limit=None,
1893
 
            show_diff=False):
1894
 
        from bzrlib.log import show_log, _get_fileid_to_log
 
2274
            show_diff=False,
 
2275
            include_merges=False):
 
2276
        from bzrlib.log import (
 
2277
            Logger,
 
2278
            make_log_request_dict,
 
2279
            _get_info_for_log_files,
 
2280
            )
1895
2281
        direction = (forward and 'forward') or 'reverse'
 
2282
        if include_merges:
 
2283
            if levels is None:
 
2284
                levels = 0
 
2285
            else:
 
2286
                raise errors.BzrCommandError(
 
2287
                    '--levels and --include-merges are mutually exclusive')
1896
2288
 
1897
2289
        if change is not None:
1898
2290
            if len(change) > 1:
1903
2295
            else:
1904
2296
                revision = change
1905
2297
 
1906
 
        # log everything
1907
 
        file_id = None
1908
 
        if location:
1909
 
            # find the file id to log:
1910
 
 
1911
 
            tree, b, fp = bzrdir.BzrDir.open_containing_tree_or_branch(
1912
 
                location)
1913
 
            if fp != '':
1914
 
                file_id = _get_fileid_to_log(revision, tree, b, fp)
 
2298
        file_ids = []
 
2299
        filter_by_dir = False
 
2300
        if file_list:
 
2301
            # find the file ids to log and check for directory filtering
 
2302
            b, file_info_list, rev1, rev2 = _get_info_for_log_files(
 
2303
                revision, file_list)
 
2304
            self.add_cleanup(b.unlock)
 
2305
            for relpath, file_id, kind in file_info_list:
1915
2306
                if file_id is None:
1916
2307
                    raise errors.BzrCommandError(
1917
2308
                        "Path unknown at end or start of revision range: %s" %
1918
 
                        location)
 
2309
                        relpath)
 
2310
                # If the relpath is the top of the tree, we log everything
 
2311
                if relpath == '':
 
2312
                    file_ids = []
 
2313
                    break
 
2314
                else:
 
2315
                    file_ids.append(file_id)
 
2316
                filter_by_dir = filter_by_dir or (
 
2317
                    kind in ['directory', 'tree-reference'])
1919
2318
        else:
1920
 
            # local dir only
1921
 
            # FIXME ? log the current subdir only RBC 20060203 
 
2319
            # log everything
 
2320
            # FIXME ? log the current subdir only RBC 20060203
1922
2321
            if revision is not None \
1923
2322
                    and len(revision) > 0 and revision[0].get_branch():
1924
2323
                location = revision[0].get_branch()
1926
2325
                location = '.'
1927
2326
            dir, relpath = bzrdir.BzrDir.open_containing(location)
1928
2327
            b = dir.open_branch()
1929
 
 
1930
 
        b.lock_read()
1931
 
        try:
 
2328
            b.lock_read()
 
2329
            self.add_cleanup(b.unlock)
1932
2330
            rev1, rev2 = _get_revision_range(revision, b, self.name())
1933
 
            if log_format is None:
1934
 
                log_format = log.log_formatter_registry.get_default(b)
1935
 
 
1936
 
            lf = log_format(show_ids=show_ids, to_file=self.outf,
1937
 
                            show_timezone=timezone,
1938
 
                            delta_format=get_verbosity_level(),
1939
 
                            levels=levels)
1940
 
 
1941
 
            show_log(b,
1942
 
                     lf,
1943
 
                     file_id,
1944
 
                     verbose=verbose,
1945
 
                     direction=direction,
1946
 
                     start_revision=rev1,
1947
 
                     end_revision=rev2,
1948
 
                     search=message,
1949
 
                     limit=limit,
1950
 
                     show_diff=show_diff)
1951
 
        finally:
1952
 
            b.unlock()
 
2331
 
 
2332
        # Decide on the type of delta & diff filtering to use
 
2333
        # TODO: add an --all-files option to make this configurable & consistent
 
2334
        if not verbose:
 
2335
            delta_type = None
 
2336
        else:
 
2337
            delta_type = 'full'
 
2338
        if not show_diff:
 
2339
            diff_type = None
 
2340
        elif file_ids:
 
2341
            diff_type = 'partial'
 
2342
        else:
 
2343
            diff_type = 'full'
 
2344
 
 
2345
        # Build the log formatter
 
2346
        if log_format is None:
 
2347
            log_format = log.log_formatter_registry.get_default(b)
 
2348
        # Make a non-encoding output to include the diffs - bug 328007
 
2349
        unencoded_output = ui.ui_factory.make_output_stream(encoding_type='exact')
 
2350
        lf = log_format(show_ids=show_ids, to_file=self.outf,
 
2351
                        to_exact_file=unencoded_output,
 
2352
                        show_timezone=timezone,
 
2353
                        delta_format=get_verbosity_level(),
 
2354
                        levels=levels,
 
2355
                        show_advice=levels is None)
 
2356
 
 
2357
        # Choose the algorithm for doing the logging. It's annoying
 
2358
        # having multiple code paths like this but necessary until
 
2359
        # the underlying repository format is faster at generating
 
2360
        # deltas or can provide everything we need from the indices.
 
2361
        # The default algorithm - match-using-deltas - works for
 
2362
        # multiple files and directories and is faster for small
 
2363
        # amounts of history (200 revisions say). However, it's too
 
2364
        # slow for logging a single file in a repository with deep
 
2365
        # history, i.e. > 10K revisions. In the spirit of "do no
 
2366
        # evil when adding features", we continue to use the
 
2367
        # original algorithm - per-file-graph - for the "single
 
2368
        # file that isn't a directory without showing a delta" case.
 
2369
        partial_history = revision and b.repository._format.supports_chks
 
2370
        match_using_deltas = (len(file_ids) != 1 or filter_by_dir
 
2371
            or delta_type or partial_history)
 
2372
 
 
2373
        # Build the LogRequest and execute it
 
2374
        if len(file_ids) == 0:
 
2375
            file_ids = None
 
2376
        rqst = make_log_request_dict(
 
2377
            direction=direction, specific_fileids=file_ids,
 
2378
            start_revision=rev1, end_revision=rev2, limit=limit,
 
2379
            message_search=message, delta_type=delta_type,
 
2380
            diff_type=diff_type, _match_using_deltas=match_using_deltas)
 
2381
        Logger(b, rqst).show(lf)
1953
2382
 
1954
2383
 
1955
2384
def _get_revision_range(revisionspec_list, branch, command_name):
1956
2385
    """Take the input of a revision option and turn it into a revision range.
1957
2386
 
1958
2387
    It returns RevisionInfo objects which can be used to obtain the rev_id's
1959
 
    of the desired revisons. It does some user input validations.
 
2388
    of the desired revisions. It does some user input validations.
1960
2389
    """
1961
2390
    if revisionspec_list is None:
1962
2391
        rev1 = None
2019
2448
    @display_command
2020
2449
    def run(self, filename):
2021
2450
        tree, relpath = WorkingTree.open_containing(filename)
 
2451
        file_id = tree.path2id(relpath)
2022
2452
        b = tree.branch
2023
 
        file_id = tree.path2id(relpath)
2024
 
        for revno, revision_id, what in log.find_touching_revisions(b, file_id):
 
2453
        b.lock_read()
 
2454
        self.add_cleanup(b.unlock)
 
2455
        touching_revs = log.find_touching_revisions(b, file_id)
 
2456
        for revno, revision_id, what in touching_revs:
2025
2457
            self.outf.write("%6d %s\n" % (revno, what))
2026
2458
 
2027
2459
 
2031
2463
 
2032
2464
    _see_also = ['status', 'cat']
2033
2465
    takes_args = ['path?']
2034
 
    # TODO: Take a revision or remote path and list that tree instead.
2035
2466
    takes_options = [
2036
2467
            'verbose',
2037
2468
            'revision',
2038
 
            Option('non-recursive',
2039
 
                   help='Don\'t recurse into subdirectories.'),
 
2469
            Option('recursive', short_name='R',
 
2470
                   help='Recurse into subdirectories.'),
2040
2471
            Option('from-root',
2041
2472
                   help='Print paths relative to the root of the branch.'),
2042
2473
            Option('unknown', help='Print unknown files.'),
2053
2484
            ]
2054
2485
    @display_command
2055
2486
    def run(self, revision=None, verbose=False,
2056
 
            non_recursive=False, from_root=False,
 
2487
            recursive=False, from_root=False,
2057
2488
            unknown=False, versioned=False, ignored=False,
2058
2489
            null=False, kind=None, show_ids=False, path=None):
2059
2490
 
2068
2499
 
2069
2500
        if path is None:
2070
2501
            fs_path = '.'
2071
 
            prefix = ''
2072
2502
        else:
2073
2503
            if from_root:
2074
2504
                raise errors.BzrCommandError('cannot specify both --from-root'
2075
2505
                                             ' and PATH')
2076
2506
            fs_path = path
2077
 
            prefix = path
2078
2507
        tree, branch, relpath = bzrdir.BzrDir.open_containing_tree_or_branch(
2079
2508
            fs_path)
 
2509
 
 
2510
        # Calculate the prefix to use
 
2511
        prefix = None
2080
2512
        if from_root:
2081
 
            relpath = u''
2082
 
        elif relpath:
2083
 
            relpath += '/'
 
2513
            if relpath:
 
2514
                prefix = relpath + '/'
 
2515
        elif fs_path != '.' and not fs_path.endswith('/'):
 
2516
            prefix = fs_path + '/'
 
2517
 
2084
2518
        if revision is not None or tree is None:
2085
2519
            tree = _get_one_revision_tree('ls', revision, branch=branch)
2086
2520
 
 
2521
        apply_view = False
 
2522
        if isinstance(tree, WorkingTree) and tree.supports_views():
 
2523
            view_files = tree.views.lookup_view()
 
2524
            if view_files:
 
2525
                apply_view = True
 
2526
                view_str = views.view_display_str(view_files)
 
2527
                note("Ignoring files outside view. View is %s" % view_str)
 
2528
 
2087
2529
        tree.lock_read()
2088
 
        try:
2089
 
            for fp, fc, fkind, fid, entry in tree.list_files(include_root=False):
2090
 
                if fp.startswith(relpath):
2091
 
                    fp = osutils.pathjoin(prefix, fp[len(relpath):])
2092
 
                    if non_recursive and '/' in fp:
2093
 
                        continue
2094
 
                    if not all and not selection[fc]:
2095
 
                        continue
2096
 
                    if kind is not None and fkind != kind:
2097
 
                        continue
2098
 
                    kindch = entry.kind_character()
2099
 
                    outstring = fp + kindch
2100
 
                    if verbose:
2101
 
                        outstring = '%-8s %s' % (fc, outstring)
2102
 
                        if show_ids and fid is not None:
2103
 
                            outstring = "%-50s %s" % (outstring, fid)
2104
 
                        self.outf.write(outstring + '\n')
2105
 
                    elif null:
2106
 
                        self.outf.write(fp + '\0')
2107
 
                        if show_ids:
2108
 
                            if fid is not None:
2109
 
                                self.outf.write(fid)
2110
 
                            self.outf.write('\0')
2111
 
                        self.outf.flush()
2112
 
                    else:
2113
 
                        if fid is not None:
2114
 
                            my_id = fid
2115
 
                        else:
2116
 
                            my_id = ''
2117
 
                        if show_ids:
2118
 
                            self.outf.write('%-50s %s\n' % (outstring, my_id))
2119
 
                        else:
2120
 
                            self.outf.write(outstring + '\n')
2121
 
        finally:
2122
 
            tree.unlock()
 
2530
        self.add_cleanup(tree.unlock)
 
2531
        for fp, fc, fkind, fid, entry in tree.list_files(include_root=False,
 
2532
            from_dir=relpath, recursive=recursive):
 
2533
            # Apply additional masking
 
2534
            if not all and not selection[fc]:
 
2535
                continue
 
2536
            if kind is not None and fkind != kind:
 
2537
                continue
 
2538
            if apply_view:
 
2539
                try:
 
2540
                    if relpath:
 
2541
                        fullpath = osutils.pathjoin(relpath, fp)
 
2542
                    else:
 
2543
                        fullpath = fp
 
2544
                    views.check_path_in_view(tree, fullpath)
 
2545
                except errors.FileOutsideView:
 
2546
                    continue
 
2547
 
 
2548
            # Output the entry
 
2549
            if prefix:
 
2550
                fp = osutils.pathjoin(prefix, fp)
 
2551
            kindch = entry.kind_character()
 
2552
            outstring = fp + kindch
 
2553
            ui.ui_factory.clear_term()
 
2554
            if verbose:
 
2555
                outstring = '%-8s %s' % (fc, outstring)
 
2556
                if show_ids and fid is not None:
 
2557
                    outstring = "%-50s %s" % (outstring, fid)
 
2558
                self.outf.write(outstring + '\n')
 
2559
            elif null:
 
2560
                self.outf.write(fp + '\0')
 
2561
                if show_ids:
 
2562
                    if fid is not None:
 
2563
                        self.outf.write(fid)
 
2564
                    self.outf.write('\0')
 
2565
                self.outf.flush()
 
2566
            else:
 
2567
                if show_ids:
 
2568
                    if fid is not None:
 
2569
                        my_id = fid
 
2570
                    else:
 
2571
                        my_id = ''
 
2572
                    self.outf.write('%-50s %s\n' % (outstring, my_id))
 
2573
                else:
 
2574
                    self.outf.write(outstring + '\n')
2123
2575
 
2124
2576
 
2125
2577
class cmd_unknowns(Command):
2140
2592
 
2141
2593
    See ``bzr help patterns`` for details on the syntax of patterns.
2142
2594
 
 
2595
    If a .bzrignore file does not exist, the ignore command
 
2596
    will create one and add the specified files or patterns to the newly
 
2597
    created file. The ignore command will also automatically add the 
 
2598
    .bzrignore file to be versioned. Creating a .bzrignore file without
 
2599
    the use of the ignore command will require an explicit add command.
 
2600
 
2143
2601
    To remove patterns from the ignore list, edit the .bzrignore file.
2144
2602
    After adding, editing or deleting that file either indirectly by
2145
2603
    using this command or directly by using an editor, be sure to commit
2146
2604
    it.
2147
2605
 
2148
 
    Note: ignore patterns containing shell wildcards must be quoted from 
 
2606
    Note: ignore patterns containing shell wildcards must be quoted from
2149
2607
    the shell on Unix.
2150
2608
 
2151
2609
    :Examples:
2176
2634
        Option('old-default-rules',
2177
2635
               help='Write out the ignore rules bzr < 0.9 always used.')
2178
2636
        ]
2179
 
    
 
2637
 
2180
2638
    def run(self, name_pattern_list=None, old_default_rules=None):
2181
2639
        from bzrlib import ignores
2182
2640
        if old_default_rules is not None:
2187
2645
        if not name_pattern_list:
2188
2646
            raise errors.BzrCommandError("ignore requires at least one "
2189
2647
                                  "NAME_PATTERN or --old-default-rules")
2190
 
        name_pattern_list = [globbing.normalize_pattern(p) 
 
2648
        name_pattern_list = [globbing.normalize_pattern(p)
2191
2649
                             for p in name_pattern_list]
2192
2650
        for name_pattern in name_pattern_list:
2193
 
            if (name_pattern[0] == '/' or 
 
2651
            if (name_pattern[0] == '/' or
2194
2652
                (len(name_pattern) > 1 and name_pattern[1] == ':')):
2195
2653
                raise errors.BzrCommandError(
2196
2654
                    "NAME_PATTERN should not be an absolute path")
2208
2666
        tree.unlock()
2209
2667
        if len(matches) > 0:
2210
2668
            print "Warning: the following files are version controlled and" \
2211
 
                  " match your ignore pattern:\n%s" % ("\n".join(matches),)
 
2669
                  " match your ignore pattern:\n%s" \
 
2670
                  "\nThese files will continue to be version controlled" \
 
2671
                  " unless you 'bzr remove' them." % ("\n".join(matches),)
2212
2672
 
2213
2673
 
2214
2674
class cmd_ignored(Command):
2229
2689
    def run(self):
2230
2690
        tree = WorkingTree.open_containing(u'.')[0]
2231
2691
        tree.lock_read()
2232
 
        try:
2233
 
            for path, file_class, kind, file_id, entry in tree.list_files():
2234
 
                if file_class != 'I':
2235
 
                    continue
2236
 
                ## XXX: Slightly inefficient since this was already calculated
2237
 
                pat = tree.is_ignored(path)
2238
 
                self.outf.write('%-50s %s\n' % (path, pat))
2239
 
        finally:
2240
 
            tree.unlock()
 
2692
        self.add_cleanup(tree.unlock)
 
2693
        for path, file_class, kind, file_id, entry in tree.list_files():
 
2694
            if file_class != 'I':
 
2695
                continue
 
2696
            ## XXX: Slightly inefficient since this was already calculated
 
2697
            pat = tree.is_ignored(path)
 
2698
            self.outf.write('%-50s %s\n' % (path, pat))
2241
2699
 
2242
2700
 
2243
2701
class cmd_lookup_revision(Command):
2248
2706
    """
2249
2707
    hidden = True
2250
2708
    takes_args = ['revno']
2251
 
    
 
2709
 
2252
2710
    @display_command
2253
2711
    def run(self, revno):
2254
2712
        try:
2293
2751
               help="Type of file to export to.",
2294
2752
               type=unicode),
2295
2753
        'revision',
 
2754
        Option('filters', help='Apply content filters to export the '
 
2755
                'convenient form.'),
2296
2756
        Option('root',
2297
2757
               type=str,
2298
2758
               help="Name of the root directory inside the exported file."),
2299
2759
        ]
2300
2760
    def run(self, dest, branch_or_subdir=None, revision=None, format=None,
2301
 
        root=None):
 
2761
        root=None, filters=False):
2302
2762
        from bzrlib.export import export
2303
2763
 
2304
2764
        if branch_or_subdir is None:
2311
2771
 
2312
2772
        rev_tree = _get_one_revision_tree('export', revision, branch=b, tree=tree)
2313
2773
        try:
2314
 
            export(rev_tree, dest, format, root, subdir)
 
2774
            export(rev_tree, dest, format, root, subdir, filtered=filters)
2315
2775
        except errors.NoSuchExportFormat, e:
2316
2776
            raise errors.BzrCommandError('Unsupported export format: %s' % e.format)
2317
2777
 
2322
2782
    If no revision is nominated, the last revision is used.
2323
2783
 
2324
2784
    Note: Take care to redirect standard output when using this command on a
2325
 
    binary file. 
 
2785
    binary file.
2326
2786
    """
2327
2787
 
2328
2788
    _see_also = ['ls']
2329
2789
    takes_options = [
2330
2790
        Option('name-from-revision', help='The path name in the old tree.'),
 
2791
        Option('filters', help='Apply content filters to display the '
 
2792
                'convenience form.'),
2331
2793
        'revision',
2332
2794
        ]
2333
2795
    takes_args = ['filename']
2334
2796
    encoding_type = 'exact'
2335
2797
 
2336
2798
    @display_command
2337
 
    def run(self, filename, revision=None, name_from_revision=False):
 
2799
    def run(self, filename, revision=None, name_from_revision=False,
 
2800
            filters=False):
2338
2801
        if revision is not None and len(revision) != 1:
2339
2802
            raise errors.BzrCommandError("bzr cat --revision takes exactly"
2340
2803
                                         " one revision specifier")
2341
2804
        tree, branch, relpath = \
2342
2805
            bzrdir.BzrDir.open_containing_tree_or_branch(filename)
2343
2806
        branch.lock_read()
2344
 
        try:
2345
 
            return self._run(tree, branch, relpath, filename, revision,
2346
 
                             name_from_revision)
2347
 
        finally:
2348
 
            branch.unlock()
 
2807
        self.add_cleanup(branch.unlock)
 
2808
        return self._run(tree, branch, relpath, filename, revision,
 
2809
                         name_from_revision, filters)
2349
2810
 
2350
 
    def _run(self, tree, b, relpath, filename, revision, name_from_revision):
 
2811
    def _run(self, tree, b, relpath, filename, revision, name_from_revision,
 
2812
        filtered):
2351
2813
        if tree is None:
2352
2814
            tree = b.basis_tree()
2353
2815
        rev_tree = _get_one_revision_tree('cat', revision, branch=b)
2354
2816
 
2355
 
        cur_file_id = tree.path2id(relpath)
2356
2817
        old_file_id = rev_tree.path2id(relpath)
2357
2818
 
2358
2819
        if name_from_revision:
 
2820
            # Try in revision if requested
2359
2821
            if old_file_id is None:
2360
2822
                raise errors.BzrCommandError(
2361
2823
                    "%r is not present in revision %s" % (
2362
2824
                        filename, rev_tree.get_revision_id()))
2363
2825
            else:
2364
2826
                content = rev_tree.get_file_text(old_file_id)
2365
 
        elif cur_file_id is not None:
2366
 
            content = rev_tree.get_file_text(cur_file_id)
2367
 
        elif old_file_id is not None:
2368
 
            content = rev_tree.get_file_text(old_file_id)
2369
 
        else:
2370
 
            raise errors.BzrCommandError(
2371
 
                "%r is not present in revision %s" % (
2372
 
                    filename, rev_tree.get_revision_id()))
2373
 
        self.outf.write(content)
 
2827
        else:
 
2828
            cur_file_id = tree.path2id(relpath)
 
2829
            found = False
 
2830
            if cur_file_id is not None:
 
2831
                # Then try with the actual file id
 
2832
                try:
 
2833
                    content = rev_tree.get_file_text(cur_file_id)
 
2834
                    found = True
 
2835
                except errors.NoSuchId:
 
2836
                    # The actual file id didn't exist at that time
 
2837
                    pass
 
2838
            if not found and old_file_id is not None:
 
2839
                # Finally try with the old file id
 
2840
                content = rev_tree.get_file_text(old_file_id)
 
2841
                found = True
 
2842
            if not found:
 
2843
                # Can't be found anywhere
 
2844
                raise errors.BzrCommandError(
 
2845
                    "%r is not present in revision %s" % (
 
2846
                        filename, rev_tree.get_revision_id()))
 
2847
        if filtered:
 
2848
            from bzrlib.filters import (
 
2849
                ContentFilterContext,
 
2850
                filtered_output_bytes,
 
2851
                )
 
2852
            filters = rev_tree._content_filter_stack(relpath)
 
2853
            chunks = content.splitlines(True)
 
2854
            content = filtered_output_bytes(chunks, filters,
 
2855
                ContentFilterContext(relpath, rev_tree))
 
2856
            self.outf.writelines(content)
 
2857
        else:
 
2858
            self.outf.write(content)
2374
2859
 
2375
2860
 
2376
2861
class cmd_local_time_offset(Command):
2377
2862
    """Show the offset in seconds from GMT to local time."""
2378
 
    hidden = True    
 
2863
    hidden = True
2379
2864
    @display_command
2380
2865
    def run(self):
2381
2866
        print osutils.local_time_offset()
2384
2869
 
2385
2870
class cmd_commit(Command):
2386
2871
    """Commit changes into a new revision.
2387
 
    
2388
 
    If no arguments are given, the entire tree is committed.
2389
 
 
2390
 
    If selected files are specified, only changes to those files are
2391
 
    committed.  If a directory is specified then the directory and everything 
2392
 
    within it is committed.
2393
 
 
2394
 
    When excludes are given, they take precedence over selected files.
2395
 
    For example, too commit only changes within foo, but not changes within
2396
 
    foo/bar::
2397
 
 
2398
 
      bzr commit foo -x foo/bar
2399
 
 
2400
 
    If author of the change is not the same person as the committer, you can
2401
 
    specify the author's name using the --author option. The name should be
2402
 
    in the same format as a committer-id, e.g. "John Doe <jdoe@example.com>".
2403
 
 
2404
 
    A selected-file commit may fail in some cases where the committed
2405
 
    tree would be invalid. Consider::
2406
 
 
2407
 
      bzr init foo
2408
 
      mkdir foo/bar
2409
 
      bzr add foo/bar
2410
 
      bzr commit foo -m "committing foo"
2411
 
      bzr mv foo/bar foo/baz
2412
 
      mkdir foo/bar
2413
 
      bzr add foo/bar
2414
 
      bzr commit foo/bar -m "committing bar but not baz"
2415
 
 
2416
 
    In the example above, the last commit will fail by design. This gives
2417
 
    the user the opportunity to decide whether they want to commit the
2418
 
    rename at the same time, separately first, or not at all. (As a general
2419
 
    rule, when in doubt, Bazaar has a policy of Doing the Safe Thing.)
2420
 
 
2421
 
    Note: A selected-file commit after a merge is not yet supported.
 
2872
 
 
2873
    An explanatory message needs to be given for each commit. This is
 
2874
    often done by using the --message option (getting the message from the
 
2875
    command line) or by using the --file option (getting the message from
 
2876
    a file). If neither of these options is given, an editor is opened for
 
2877
    the user to enter the message. To see the changed files in the
 
2878
    boilerplate text loaded into the editor, use the --show-diff option.
 
2879
 
 
2880
    By default, the entire tree is committed and the person doing the
 
2881
    commit is assumed to be the author. These defaults can be overridden
 
2882
    as explained below.
 
2883
 
 
2884
    :Selective commits:
 
2885
 
 
2886
      If selected files are specified, only changes to those files are
 
2887
      committed.  If a directory is specified then the directory and
 
2888
      everything within it is committed.
 
2889
  
 
2890
      When excludes are given, they take precedence over selected files.
 
2891
      For example, to commit only changes within foo, but not changes
 
2892
      within foo/bar::
 
2893
  
 
2894
        bzr commit foo -x foo/bar
 
2895
  
 
2896
      A selective commit after a merge is not yet supported.
 
2897
 
 
2898
    :Custom authors:
 
2899
 
 
2900
      If the author of the change is not the same person as the committer,
 
2901
      you can specify the author's name using the --author option. The
 
2902
      name should be in the same format as a committer-id, e.g.
 
2903
      "John Doe <jdoe@example.com>". If there is more than one author of
 
2904
      the change you can specify the option multiple times, once for each
 
2905
      author.
 
2906
  
 
2907
    :Checks:
 
2908
 
 
2909
      A common mistake is to forget to add a new file or directory before
 
2910
      running the commit command. The --strict option checks for unknown
 
2911
      files and aborts the commit if any are found. More advanced pre-commit
 
2912
      checks can be implemented by defining hooks. See ``bzr help hooks``
 
2913
      for details.
 
2914
 
 
2915
    :Things to note:
 
2916
 
 
2917
      If you accidentially commit the wrong changes or make a spelling
 
2918
      mistake in the commit message say, you can use the uncommit command
 
2919
      to undo it. See ``bzr help uncommit`` for details.
 
2920
 
 
2921
      Hooks can also be configured to run after a commit. This allows you
 
2922
      to trigger updates to external systems like bug trackers. The --fixes
 
2923
      option can be used to record the association between a revision and
 
2924
      one or more bugs. See ``bzr help bugs`` for details.
 
2925
 
 
2926
      A selective commit may fail in some cases where the committed
 
2927
      tree would be invalid. Consider::
 
2928
  
 
2929
        bzr init foo
 
2930
        mkdir foo/bar
 
2931
        bzr add foo/bar
 
2932
        bzr commit foo -m "committing foo"
 
2933
        bzr mv foo/bar foo/baz
 
2934
        mkdir foo/bar
 
2935
        bzr add foo/bar
 
2936
        bzr commit foo/bar -m "committing bar but not baz"
 
2937
  
 
2938
      In the example above, the last commit will fail by design. This gives
 
2939
      the user the opportunity to decide whether they want to commit the
 
2940
      rename at the same time, separately first, or not at all. (As a general
 
2941
      rule, when in doubt, Bazaar has a policy of Doing the Safe Thing.)
2422
2942
    """
2423
2943
    # TODO: Run hooks on tree to-be-committed, and after commit.
2424
2944
 
2429
2949
 
2430
2950
    # XXX: verbose currently does nothing
2431
2951
 
2432
 
    _see_also = ['bugs', 'uncommit']
 
2952
    _see_also = ['add', 'bugs', 'hooks', 'uncommit']
2433
2953
    takes_args = ['selected*']
2434
2954
    takes_options = [
2435
2955
            ListOption('exclude', type=str, short_name='x',
2447
2967
             Option('strict',
2448
2968
                    help="Refuse to commit if there are unknown "
2449
2969
                    "files in the working tree."),
 
2970
             Option('commit-time', type=str,
 
2971
                    help="Manually set a commit time using commit date "
 
2972
                    "format, e.g. '2009-10-10 08:00:00 +0100'."),
2450
2973
             ListOption('fixes', type=str,
2451
 
                    help="Mark a bug as being fixed by this revision."),
2452
 
             Option('author', type=unicode,
 
2974
                    help="Mark a bug as being fixed by this revision "
 
2975
                         "(see \"bzr help bugs\")."),
 
2976
             ListOption('author', type=unicode,
2453
2977
                    help="Set the author's name, if it's different "
2454
2978
                         "from the committer."),
2455
2979
             Option('local',
2458
2982
                         "the master branch until a normal commit "
2459
2983
                         "is performed."
2460
2984
                    ),
2461
 
              Option('show-diff',
2462
 
                     help='When no message is supplied, show the diff along'
2463
 
                     ' with the status summary in the message editor.'),
 
2985
             Option('show-diff',
 
2986
                    help='When no message is supplied, show the diff along'
 
2987
                    ' with the status summary in the message editor.'),
2464
2988
             ]
2465
2989
    aliases = ['ci', 'checkin']
2466
2990
 
2467
 
    def _get_bug_fix_properties(self, fixes, branch):
2468
 
        properties = []
 
2991
    def _iter_bug_fix_urls(self, fixes, branch):
2469
2992
        # Configure the properties for bug fixing attributes.
2470
2993
        for fixed_bug in fixes:
2471
2994
            tokens = fixed_bug.split(':')
2472
2995
            if len(tokens) != 2:
2473
2996
                raise errors.BzrCommandError(
2474
 
                    "Invalid bug %s. Must be in the form of 'tag:id'. "
2475
 
                    "Commit refused." % fixed_bug)
 
2997
                    "Invalid bug %s. Must be in the form of 'tracker:id'. "
 
2998
                    "See \"bzr help bugs\" for more information on this "
 
2999
                    "feature.\nCommit refused." % fixed_bug)
2476
3000
            tag, bug_id = tokens
2477
3001
            try:
2478
 
                bug_url = bugtracker.get_bug_url(tag, branch, bug_id)
 
3002
                yield bugtracker.get_bug_url(tag, branch, bug_id)
2479
3003
            except errors.UnknownBugTrackerAbbreviation:
2480
3004
                raise errors.BzrCommandError(
2481
3005
                    'Unrecognized bug %s. Commit refused.' % fixed_bug)
2482
 
            except errors.MalformedBugIdentifier:
 
3006
            except errors.MalformedBugIdentifier, e:
2483
3007
                raise errors.BzrCommandError(
2484
 
                    "Invalid bug identifier for %s. Commit refused."
2485
 
                    % fixed_bug)
2486
 
            properties.append('%s fixed' % bug_url)
2487
 
        return '\n'.join(properties)
 
3008
                    "%s\nCommit refused." % (str(e),))
2488
3009
 
2489
3010
    def run(self, message=None, file=None, verbose=False, selected_list=None,
2490
3011
            unchanged=False, strict=False, local=False, fixes=None,
2491
 
            author=None, show_diff=False, exclude=None):
 
3012
            author=None, show_diff=False, exclude=None, commit_time=None):
2492
3013
        from bzrlib.errors import (
2493
3014
            PointlessCommit,
2494
3015
            ConflictsInTree,
2500
3021
            make_commit_message_template_encoded
2501
3022
        )
2502
3023
 
 
3024
        commit_stamp = offset = None
 
3025
        if commit_time is not None:
 
3026
            try:
 
3027
                commit_stamp, offset = timestamp.parse_patch_date(commit_time)
 
3028
            except ValueError, e:
 
3029
                raise errors.BzrCommandError(
 
3030
                    "Could not parse --commit-time: " + str(e))
 
3031
 
2503
3032
        # TODO: Need a blackbox test for invoking the external editor; may be
2504
3033
        # slightly problematic to run this cross-platform.
2505
3034
 
2506
 
        # TODO: do more checks that the commit will succeed before 
 
3035
        # TODO: do more checks that the commit will succeed before
2507
3036
        # spending the user's valuable time typing a commit message.
2508
3037
 
2509
3038
        properties = {}
2517
3046
 
2518
3047
        if fixes is None:
2519
3048
            fixes = []
2520
 
        bug_property = self._get_bug_fix_properties(fixes, tree.branch)
 
3049
        bug_property = bugtracker.encode_fixes_bug_urls(
 
3050
            self._iter_bug_fix_urls(fixes, tree.branch))
2521
3051
        if bug_property:
2522
3052
            properties['bugs'] = bug_property
2523
3053
 
2524
3054
        if local and not tree.branch.get_bound_location():
2525
3055
            raise errors.LocalRequiresBoundBranch()
2526
3056
 
 
3057
        if message is not None:
 
3058
            try:
 
3059
                file_exists = osutils.lexists(message)
 
3060
            except UnicodeError:
 
3061
                # The commit message contains unicode characters that can't be
 
3062
                # represented in the filesystem encoding, so that can't be a
 
3063
                # file.
 
3064
                file_exists = False
 
3065
            if file_exists:
 
3066
                warning_msg = (
 
3067
                    'The commit message is a file name: "%(f)s".\n'
 
3068
                    '(use --file "%(f)s" to take commit message from that file)'
 
3069
                    % { 'f': message })
 
3070
                ui.ui_factory.show_warning(warning_msg)
 
3071
 
2527
3072
        def get_message(commit_obj):
2528
3073
            """Callback to get commit message"""
2529
3074
            my_message = message
 
3075
            if my_message is not None and '\r' in my_message:
 
3076
                my_message = my_message.replace('\r\n', '\n')
 
3077
                my_message = my_message.replace('\r', '\n')
2530
3078
            if my_message is None and not file:
2531
3079
                t = make_commit_message_template_encoded(tree,
2532
3080
                        selected_list, diff=show_diff,
2533
3081
                        output_encoding=osutils.get_user_encoding())
2534
3082
                start_message = generate_commit_message_template(commit_obj)
2535
 
                my_message = edit_commit_message_encoded(t, 
 
3083
                my_message = edit_commit_message_encoded(t,
2536
3084
                    start_message=start_message)
2537
3085
                if my_message is None:
2538
3086
                    raise errors.BzrCommandError("please specify a commit"
2547
3095
                raise errors.BzrCommandError("empty commit message specified")
2548
3096
            return my_message
2549
3097
 
 
3098
        # The API permits a commit with a filter of [] to mean 'select nothing'
 
3099
        # but the command line should not do that.
 
3100
        if not selected_list:
 
3101
            selected_list = None
2550
3102
        try:
2551
3103
            tree.commit(message_callback=get_message,
2552
3104
                        specific_files=selected_list,
2553
3105
                        allow_pointless=unchanged, strict=strict, local=local,
2554
3106
                        reporter=None, verbose=verbose, revprops=properties,
2555
 
                        author=author,
 
3107
                        authors=author, timestamp=commit_stamp,
 
3108
                        timezone=offset,
2556
3109
                        exclude=safe_relpath_files(tree, exclude))
2557
3110
        except PointlessCommit:
2558
3111
            # FIXME: This should really happen before the file is read in;
2559
3112
            # perhaps prepare the commit; get the message; then actually commit
2560
 
            raise errors.BzrCommandError("no changes to commit."
2561
 
                              " use --unchanged to commit anyhow")
 
3113
            raise errors.BzrCommandError("No changes to commit."
 
3114
                              " Use --unchanged to commit anyhow.")
2562
3115
        except ConflictsInTree:
2563
3116
            raise errors.BzrCommandError('Conflicts detected in working '
2564
3117
                'tree.  Use "bzr conflicts" to list, "bzr resolve FILE" to'
2582
3135
    The working tree and branch checks will only give output if a problem is
2583
3136
    detected. The output fields of the repository check are:
2584
3137
 
2585
 
        revisions: This is just the number of revisions checked.  It doesn't
2586
 
            indicate a problem.
2587
 
        versionedfiles: This is just the number of versionedfiles checked.  It
2588
 
            doesn't indicate a problem.
2589
 
        unreferenced ancestors: Texts that are ancestors of other texts, but
2590
 
            are not properly referenced by the revision ancestry.  This is a
2591
 
            subtle problem that Bazaar can work around.
2592
 
        unique file texts: This is the total number of unique file contents
2593
 
            seen in the checked revisions.  It does not indicate a problem.
2594
 
        repeated file texts: This is the total number of repeated texts seen
2595
 
            in the checked revisions.  Texts can be repeated when their file
2596
 
            entries are modified, but the file contents are not.  It does not
2597
 
            indicate a problem.
 
3138
    revisions
 
3139
        This is just the number of revisions checked.  It doesn't
 
3140
        indicate a problem.
 
3141
 
 
3142
    versionedfiles
 
3143
        This is just the number of versionedfiles checked.  It
 
3144
        doesn't indicate a problem.
 
3145
 
 
3146
    unreferenced ancestors
 
3147
        Texts that are ancestors of other texts, but
 
3148
        are not properly referenced by the revision ancestry.  This is a
 
3149
        subtle problem that Bazaar can work around.
 
3150
 
 
3151
    unique file texts
 
3152
        This is the total number of unique file contents
 
3153
        seen in the checked revisions.  It does not indicate a problem.
 
3154
 
 
3155
    repeated file texts
 
3156
        This is the total number of repeated texts seen
 
3157
        in the checked revisions.  Texts can be repeated when their file
 
3158
        entries are modified, but the file contents are not.  It does not
 
3159
        indicate a problem.
2598
3160
 
2599
3161
    If no restrictions are specified, all Bazaar data that is found at the given
2600
3162
    location will be checked.
2655
3217
 
2656
3218
    def run(self, url='.', format=None):
2657
3219
        from bzrlib.upgrade import upgrade
2658
 
        if format is None:
2659
 
            format = bzrdir.format_registry.make_bzrdir('default')
2660
3220
        upgrade(url, format)
2661
3221
 
2662
3222
 
2663
3223
class cmd_whoami(Command):
2664
3224
    """Show or set bzr user id.
2665
 
    
 
3225
 
2666
3226
    :Examples:
2667
3227
        Show the email of the current user::
2668
3228
 
2680
3240
                    ]
2681
3241
    takes_args = ['name?']
2682
3242
    encoding_type = 'replace'
2683
 
    
 
3243
 
2684
3244
    @display_command
2685
3245
    def run(self, email=False, branch=False, name=None):
2686
3246
        if name is None:
2701
3261
        except errors.NoEmailInUsername, e:
2702
3262
            warning('"%s" does not seem to contain an email address.  '
2703
3263
                    'This is allowed, but not recommended.', name)
2704
 
        
 
3264
 
2705
3265
        # use global config unless --branch given
2706
3266
        if branch:
2707
3267
            c = Branch.open_containing('.')[0].get_config()
2806
3366
 
2807
3367
class cmd_selftest(Command):
2808
3368
    """Run internal test suite.
2809
 
    
 
3369
 
2810
3370
    If arguments are given, they are regular expressions that say which tests
2811
3371
    should run.  Tests matching any expression are run, and other tests are
2812
3372
    not run.
2835
3395
    modified by plugins will not be tested, and tests provided by plugins will
2836
3396
    not be run.
2837
3397
 
2838
 
    Tests that need working space on disk use a common temporary directory, 
 
3398
    Tests that need working space on disk use a common temporary directory,
2839
3399
    typically inside $TMPDIR or /tmp.
2840
3400
 
 
3401
    If you set BZR_TEST_PDB=1 when running selftest, failing tests will drop
 
3402
    into a pdb postmortem session.
 
3403
 
2841
3404
    :Examples:
2842
3405
        Run only tests relating to 'ignore'::
2843
3406
 
2880
3443
                     Option('lsprof-timed',
2881
3444
                            help='Generate lsprof output for benchmarked'
2882
3445
                                 ' sections of code.'),
 
3446
                     Option('lsprof-tests',
 
3447
                            help='Generate lsprof output for each test.'),
2883
3448
                     Option('cache-dir', type=str,
2884
3449
                            help='Cache intermediate benchmark output in this '
2885
3450
                                 'directory.'),
2889
3454
                            ),
2890
3455
                     Option('list-only',
2891
3456
                            help='List the tests instead of running them.'),
 
3457
                     RegistryOption('parallel',
 
3458
                        help="Run the test suite in parallel.",
 
3459
                        lazy_registry=('bzrlib.tests', 'parallel_registry'),
 
3460
                        value_switches=False,
 
3461
                        ),
2892
3462
                     Option('randomize', type=str, argname="SEED",
2893
3463
                            help='Randomize the order of tests using the given'
2894
3464
                                 ' seed or "now" for the current time.'),
2896
3466
                            short_name='x',
2897
3467
                            help='Exclude tests that match this regular'
2898
3468
                                 ' expression.'),
 
3469
                     Option('subunit',
 
3470
                        help='Output test progress via subunit.'),
2899
3471
                     Option('strict', help='Fail on missing dependencies or '
2900
3472
                            'known failures.'),
2901
3473
                     Option('load-list', type=str, argname='TESTLISTFILE',
2909
3481
                     ]
2910
3482
    encoding_type = 'replace'
2911
3483
 
 
3484
    def __init__(self):
 
3485
        Command.__init__(self)
 
3486
        self.additional_selftest_args = {}
 
3487
 
2912
3488
    def run(self, testspecs_list=None, verbose=False, one=False,
2913
3489
            transport=None, benchmark=None,
2914
3490
            lsprof_timed=None, cache_dir=None,
2915
3491
            first=False, list_only=False,
2916
3492
            randomize=None, exclude=None, strict=False,
2917
 
            load_list=None, debugflag=None, starting_with=None):
 
3493
            load_list=None, debugflag=None, starting_with=None, subunit=False,
 
3494
            parallel=None, lsprof_tests=False):
2918
3495
        from bzrlib.tests import selftest
2919
3496
        import bzrlib.benchmarks as benchmarks
2920
3497
        from bzrlib.benchmarks import tree_creator
2924
3501
 
2925
3502
        if cache_dir is not None:
2926
3503
            tree_creator.TreeCreator.CACHE_ROOT = osutils.abspath(cache_dir)
2927
 
        if not list_only:
2928
 
            print 'testing: %s' % (osutils.realpath(sys.argv[0]),)
2929
 
            print '   %s (%s python%s)' % (
2930
 
                    bzrlib.__path__[0],
2931
 
                    bzrlib.version_string,
2932
 
                    bzrlib._format_version_tuple(sys.version_info),
2933
 
                    )
2934
 
        print
2935
3504
        if testspecs_list is not None:
2936
3505
            pattern = '|'.join(testspecs_list)
2937
3506
        else:
2938
3507
            pattern = ".*"
 
3508
        if subunit:
 
3509
            try:
 
3510
                from bzrlib.tests import SubUnitBzrRunner
 
3511
            except ImportError:
 
3512
                raise errors.BzrCommandError("subunit not available. subunit "
 
3513
                    "needs to be installed to use --subunit.")
 
3514
            self.additional_selftest_args['runner_class'] = SubUnitBzrRunner
 
3515
        if parallel:
 
3516
            self.additional_selftest_args.setdefault(
 
3517
                'suite_decorators', []).append(parallel)
2939
3518
        if benchmark:
2940
3519
            test_suite_factory = benchmarks.test_suite
2941
3520
            # Unless user explicitly asks for quiet, be verbose in benchmarks
2942
3521
            verbose = not is_quiet()
2943
3522
            # TODO: should possibly lock the history file...
2944
3523
            benchfile = open(".perf_history", "at", buffering=1)
 
3524
            self.add_cleanup(benchfile.close)
2945
3525
        else:
2946
3526
            test_suite_factory = None
2947
3527
            benchfile = None
2948
 
        try:
2949
 
            result = selftest(verbose=verbose,
2950
 
                              pattern=pattern,
2951
 
                              stop_on_failure=one,
2952
 
                              transport=transport,
2953
 
                              test_suite_factory=test_suite_factory,
2954
 
                              lsprof_timed=lsprof_timed,
2955
 
                              bench_history=benchfile,
2956
 
                              matching_tests_first=first,
2957
 
                              list_only=list_only,
2958
 
                              random_seed=randomize,
2959
 
                              exclude_pattern=exclude,
2960
 
                              strict=strict,
2961
 
                              load_list=load_list,
2962
 
                              debug_flags=debugflag,
2963
 
                              starting_with=starting_with,
2964
 
                              )
2965
 
        finally:
2966
 
            if benchfile is not None:
2967
 
                benchfile.close()
2968
 
        if result:
2969
 
            note('tests passed')
2970
 
        else:
2971
 
            note('tests failed')
 
3528
        selftest_kwargs = {"verbose": verbose,
 
3529
                          "pattern": pattern,
 
3530
                          "stop_on_failure": one,
 
3531
                          "transport": transport,
 
3532
                          "test_suite_factory": test_suite_factory,
 
3533
                          "lsprof_timed": lsprof_timed,
 
3534
                          "lsprof_tests": lsprof_tests,
 
3535
                          "bench_history": benchfile,
 
3536
                          "matching_tests_first": first,
 
3537
                          "list_only": list_only,
 
3538
                          "random_seed": randomize,
 
3539
                          "exclude_pattern": exclude,
 
3540
                          "strict": strict,
 
3541
                          "load_list": load_list,
 
3542
                          "debug_flags": debugflag,
 
3543
                          "starting_with": starting_with
 
3544
                          }
 
3545
        selftest_kwargs.update(self.additional_selftest_args)
 
3546
        result = selftest(**selftest_kwargs)
2972
3547
        return int(not result)
2973
3548
 
2974
3549
 
3005
3580
    #       merging only part of the history.
3006
3581
    takes_args = ['branch', 'other']
3007
3582
    hidden = True
3008
 
    
 
3583
 
3009
3584
    @display_command
3010
3585
    def run(self, branch, other):
3011
3586
        from bzrlib.revision import ensure_null
3012
 
        
 
3587
 
3013
3588
        branch1 = Branch.open_containing(branch)[0]
3014
3589
        branch2 = Branch.open_containing(other)[0]
3015
3590
        branch1.lock_read()
3016
 
        try:
3017
 
            branch2.lock_read()
3018
 
            try:
3019
 
                last1 = ensure_null(branch1.last_revision())
3020
 
                last2 = ensure_null(branch2.last_revision())
3021
 
 
3022
 
                graph = branch1.repository.get_graph(branch2.repository)
3023
 
                base_rev_id = graph.find_unique_lca(last1, last2)
3024
 
 
3025
 
                print 'merge base is revision %s' % base_rev_id
3026
 
            finally:
3027
 
                branch2.unlock()
3028
 
        finally:
3029
 
            branch1.unlock()
 
3591
        self.add_cleanup(branch1.unlock)
 
3592
        branch2.lock_read()
 
3593
        self.add_cleanup(branch2.unlock)
 
3594
        last1 = ensure_null(branch1.last_revision())
 
3595
        last2 = ensure_null(branch2.last_revision())
 
3596
 
 
3597
        graph = branch1.repository.get_graph(branch2.repository)
 
3598
        base_rev_id = graph.find_unique_lca(last1, last2)
 
3599
 
 
3600
        print 'merge base is revision %s' % base_rev_id
3030
3601
 
3031
3602
 
3032
3603
class cmd_merge(Command):
3033
3604
    """Perform a three-way merge.
3034
 
    
 
3605
 
3035
3606
    The source of the merge can be specified either in the form of a branch,
3036
3607
    or in the form of a path to a file containing a merge directive generated
3037
3608
    with bzr send. If neither is specified, the default is the upstream branch
3047
3618
    By default, bzr will try to merge in all new work from the other
3048
3619
    branch, automatically determining an appropriate base.  If this
3049
3620
    fails, you may need to give an explicit base.
3050
 
    
 
3621
 
3051
3622
    Merge will do its best to combine the changes in two branches, but there
3052
3623
    are some kinds of problems only a human can fix.  When it encounters those,
3053
3624
    it will mark a conflict.  A conflict means that you need to fix something,
3063
3634
    The results of the merge are placed into the destination working
3064
3635
    directory, where they can be reviewed (with bzr diff), tested, and then
3065
3636
    committed to record the result of the merge.
3066
 
    
 
3637
 
3067
3638
    merge refuses to run if there are any uncommitted changes, unless
3068
3639
    --force is given.
3069
3640
 
 
3641
    To select only some changes to merge, use "merge -i", which will prompt
 
3642
    you to apply each diff hunk and file change, similar to "shelve".
 
3643
 
3070
3644
    :Examples:
3071
3645
        To merge the latest revision from bzr.dev::
3072
3646
 
3080
3654
 
3081
3655
            bzr merge -r 81..82 ../bzr.dev
3082
3656
 
3083
 
        To apply a merge directive contained in in /tmp/merge:
 
3657
        To apply a merge directive contained in /tmp/merge::
3084
3658
 
3085
3659
            bzr merge /tmp/merge
3086
3660
    """
3087
3661
 
3088
3662
    encoding_type = 'exact'
3089
 
    _see_also = ['update', 'remerge', 'status-flags']
 
3663
    _see_also = ['update', 'remerge', 'status-flags', 'send']
3090
3664
    takes_args = ['location?']
3091
3665
    takes_options = [
3092
3666
        'change',
3110
3684
               short_name='d',
3111
3685
               type=unicode,
3112
3686
               ),
3113
 
        Option('preview', help='Instead of merging, show a diff of the merge.')
 
3687
        Option('preview', help='Instead of merging, show a diff of the'
 
3688
               ' merge.'),
 
3689
        Option('interactive', help='Select changes interactively.',
 
3690
            short_name='i')
3114
3691
    ]
3115
3692
 
3116
3693
    def run(self, location=None, revision=None, force=False,
3118
3695
            uncommitted=False, pull=False,
3119
3696
            directory=None,
3120
3697
            preview=False,
 
3698
            interactive=False,
3121
3699
            ):
3122
3700
        if merge_type is None:
3123
3701
            merge_type = _mod_merge.Merge3Merger
3128
3706
        allow_pending = True
3129
3707
        verified = 'inapplicable'
3130
3708
        tree = WorkingTree.open_containing(directory)[0]
 
3709
 
 
3710
        try:
 
3711
            basis_tree = tree.revision_tree(tree.last_revision())
 
3712
        except errors.NoSuchRevision:
 
3713
            basis_tree = tree.basis_tree()
 
3714
 
 
3715
        # die as quickly as possible if there are uncommitted changes
 
3716
        if not force:
 
3717
            if tree.has_changes():
 
3718
                raise errors.UncommittedChanges(tree)
 
3719
 
 
3720
        view_info = _get_view_info_for_change_reporter(tree)
3131
3721
        change_reporter = delta._ChangeReporter(
3132
 
            unversioned_filter=tree.is_ignored)
3133
 
        cleanups = []
3134
 
        try:
3135
 
            pb = ui.ui_factory.nested_progress_bar()
3136
 
            cleanups.append(pb.finished)
3137
 
            tree.lock_write()
3138
 
            cleanups.append(tree.unlock)
3139
 
            if location is not None:
3140
 
                try:
3141
 
                    mergeable = bundle.read_mergeable_from_url(location,
3142
 
                        possible_transports=possible_transports)
3143
 
                except errors.NotABundle:
3144
 
                    mergeable = None
3145
 
                else:
3146
 
                    if uncommitted:
3147
 
                        raise errors.BzrCommandError('Cannot use --uncommitted'
3148
 
                            ' with bundles or merge directives.')
3149
 
 
3150
 
                    if revision is not None:
3151
 
                        raise errors.BzrCommandError(
3152
 
                            'Cannot use -r with merge directives or bundles')
3153
 
                    merger, verified = _mod_merge.Merger.from_mergeable(tree,
3154
 
                       mergeable, pb)
3155
 
 
3156
 
            if merger is None and uncommitted:
3157
 
                if revision is not None and len(revision) > 0:
3158
 
                    raise errors.BzrCommandError('Cannot use --uncommitted and'
3159
 
                        ' --revision at the same time.')
3160
 
                location = self._select_branch_location(tree, location)[0]
3161
 
                other_tree, other_path = WorkingTree.open_containing(location)
3162
 
                merger = _mod_merge.Merger.from_uncommitted(tree, other_tree,
3163
 
                    pb)
3164
 
                allow_pending = False
3165
 
                if other_path != '':
3166
 
                    merger.interesting_files = [other_path]
3167
 
 
3168
 
            if merger is None:
3169
 
                merger, allow_pending = self._get_merger_from_branch(tree,
3170
 
                    location, revision, remember, possible_transports, pb)
3171
 
 
3172
 
            merger.merge_type = merge_type
3173
 
            merger.reprocess = reprocess
3174
 
            merger.show_base = show_base
3175
 
            self.sanity_check_merger(merger)
3176
 
            if (merger.base_rev_id == merger.other_rev_id and
3177
 
                merger.other_rev_id is not None):
3178
 
                note('Nothing to do.')
 
3722
            unversioned_filter=tree.is_ignored, view_info=view_info)
 
3723
        pb = ui.ui_factory.nested_progress_bar()
 
3724
        self.add_cleanup(pb.finished)
 
3725
        tree.lock_write()
 
3726
        self.add_cleanup(tree.unlock)
 
3727
        if location is not None:
 
3728
            try:
 
3729
                mergeable = bundle.read_mergeable_from_url(location,
 
3730
                    possible_transports=possible_transports)
 
3731
            except errors.NotABundle:
 
3732
                mergeable = None
 
3733
            else:
 
3734
                if uncommitted:
 
3735
                    raise errors.BzrCommandError('Cannot use --uncommitted'
 
3736
                        ' with bundles or merge directives.')
 
3737
 
 
3738
                if revision is not None:
 
3739
                    raise errors.BzrCommandError(
 
3740
                        'Cannot use -r with merge directives or bundles')
 
3741
                merger, verified = _mod_merge.Merger.from_mergeable(tree,
 
3742
                   mergeable, pb)
 
3743
 
 
3744
        if merger is None and uncommitted:
 
3745
            if revision is not None and len(revision) > 0:
 
3746
                raise errors.BzrCommandError('Cannot use --uncommitted and'
 
3747
                    ' --revision at the same time.')
 
3748
            merger = self.get_merger_from_uncommitted(tree, location, pb)
 
3749
            allow_pending = False
 
3750
 
 
3751
        if merger is None:
 
3752
            merger, allow_pending = self._get_merger_from_branch(tree,
 
3753
                location, revision, remember, possible_transports, pb)
 
3754
 
 
3755
        merger.merge_type = merge_type
 
3756
        merger.reprocess = reprocess
 
3757
        merger.show_base = show_base
 
3758
        self.sanity_check_merger(merger)
 
3759
        if (merger.base_rev_id == merger.other_rev_id and
 
3760
            merger.other_rev_id is not None):
 
3761
            note('Nothing to do.')
 
3762
            return 0
 
3763
        if pull:
 
3764
            if merger.interesting_files is not None:
 
3765
                raise errors.BzrCommandError('Cannot pull individual files')
 
3766
            if (merger.base_rev_id == tree.last_revision()):
 
3767
                result = tree.pull(merger.other_branch, False,
 
3768
                                   merger.other_rev_id)
 
3769
                result.report(self.outf)
3179
3770
                return 0
3180
 
            if pull:
3181
 
                if merger.interesting_files is not None:
3182
 
                    raise errors.BzrCommandError('Cannot pull individual files')
3183
 
                if (merger.base_rev_id == tree.last_revision()):
3184
 
                    result = tree.pull(merger.other_branch, False,
3185
 
                                       merger.other_rev_id)
3186
 
                    result.report(self.outf)
3187
 
                    return 0
3188
 
            merger.check_basis(not force)
3189
 
            if preview:
3190
 
                return self._do_preview(merger)
3191
 
            else:
3192
 
                return self._do_merge(merger, change_reporter, allow_pending,
3193
 
                                      verified)
3194
 
        finally:
3195
 
            for cleanup in reversed(cleanups):
3196
 
                cleanup()
 
3771
        if merger.this_basis is None:
 
3772
            raise errors.BzrCommandError(
 
3773
                "This branch has no commits."
 
3774
                " (perhaps you would prefer 'bzr pull')")
 
3775
        if preview:
 
3776
            return self._do_preview(merger)
 
3777
        elif interactive:
 
3778
            return self._do_interactive(merger)
 
3779
        else:
 
3780
            return self._do_merge(merger, change_reporter, allow_pending,
 
3781
                                  verified)
 
3782
 
 
3783
    def _get_preview(self, merger):
 
3784
        tree_merger = merger.make_merger()
 
3785
        tt = tree_merger.make_preview_transform()
 
3786
        self.add_cleanup(tt.finalize)
 
3787
        result_tree = tt.get_preview_tree()
 
3788
        return result_tree
3197
3789
 
3198
3790
    def _do_preview(self, merger):
3199
3791
        from bzrlib.diff import show_diff_trees
3200
 
        tree_merger = merger.make_merger()
3201
 
        tt = tree_merger.make_preview_transform()
3202
 
        try:
3203
 
            result_tree = tt.get_preview_tree()
3204
 
            show_diff_trees(merger.this_tree, result_tree, self.outf,
3205
 
                            old_label='', new_label='')
3206
 
        finally:
3207
 
            tt.finalize()
 
3792
        result_tree = self._get_preview(merger)
 
3793
        show_diff_trees(merger.this_tree, result_tree, self.outf,
 
3794
                        old_label='', new_label='')
3208
3795
 
3209
3796
    def _do_merge(self, merger, change_reporter, allow_pending, verified):
3210
3797
        merger.change_reporter = change_reporter
3218
3805
        else:
3219
3806
            return 0
3220
3807
 
 
3808
    def _do_interactive(self, merger):
 
3809
        """Perform an interactive merge.
 
3810
 
 
3811
        This works by generating a preview tree of the merge, then using
 
3812
        Shelver to selectively remove the differences between the working tree
 
3813
        and the preview tree.
 
3814
        """
 
3815
        from bzrlib import shelf_ui
 
3816
        result_tree = self._get_preview(merger)
 
3817
        writer = bzrlib.option.diff_writer_registry.get()
 
3818
        shelver = shelf_ui.Shelver(merger.this_tree, result_tree, destroy=True,
 
3819
                                   reporter=shelf_ui.ApplyReporter(),
 
3820
                                   diff_writer=writer(sys.stdout))
 
3821
        try:
 
3822
            shelver.run()
 
3823
        finally:
 
3824
            shelver.finalize()
 
3825
 
3221
3826
    def sanity_check_merger(self, merger):
3222
3827
        if (merger.show_base and
3223
3828
            not merger.merge_type is _mod_merge.Merge3Merger):
3258
3863
            base_branch, base_path = Branch.open_containing(base_loc,
3259
3864
                possible_transports)
3260
3865
        # Find the revision ids
3261
 
        if revision is None or len(revision) < 1 or revision[-1] is None:
 
3866
        other_revision_id = None
 
3867
        base_revision_id = None
 
3868
        if revision is not None:
 
3869
            if len(revision) >= 1:
 
3870
                other_revision_id = revision[-1].as_revision_id(other_branch)
 
3871
            if len(revision) == 2:
 
3872
                base_revision_id = revision[0].as_revision_id(base_branch)
 
3873
        if other_revision_id is None:
3262
3874
            other_revision_id = _mod_revision.ensure_null(
3263
3875
                other_branch.last_revision())
3264
 
        else:
3265
 
            other_revision_id = revision[-1].as_revision_id(other_branch)
3266
 
        if (revision is not None and len(revision) == 2
3267
 
            and revision[0] is not None):
3268
 
            base_revision_id = revision[0].as_revision_id(base_branch)
3269
 
        else:
3270
 
            base_revision_id = None
3271
3876
        # Remember where we merge from
3272
3877
        if ((remember or tree.branch.get_submit_branch() is None) and
3273
3878
             user_location is not None):
3282
3887
            allow_pending = True
3283
3888
        return merger, allow_pending
3284
3889
 
 
3890
    def get_merger_from_uncommitted(self, tree, location, pb):
 
3891
        """Get a merger for uncommitted changes.
 
3892
 
 
3893
        :param tree: The tree the merger should apply to.
 
3894
        :param location: The location containing uncommitted changes.
 
3895
        :param pb: The progress bar to use for showing progress.
 
3896
        """
 
3897
        location = self._select_branch_location(tree, location)[0]
 
3898
        other_tree, other_path = WorkingTree.open_containing(location)
 
3899
        merger = _mod_merge.Merger.from_uncommitted(tree, other_tree, pb)
 
3900
        if other_path != '':
 
3901
            merger.interesting_files = [other_path]
 
3902
        return merger
 
3903
 
3285
3904
    def _select_branch_location(self, tree, user_location, revision=None,
3286
3905
                                index=None):
3287
3906
        """Select a branch location, according to possible inputs.
3334
3953
    """Redo a merge.
3335
3954
 
3336
3955
    Use this if you want to try a different merge technique while resolving
3337
 
    conflicts.  Some merge techniques are better than others, and remerge 
 
3956
    conflicts.  Some merge techniques are better than others, and remerge
3338
3957
    lets you try different ones on different files.
3339
3958
 
3340
3959
    The options for remerge have the same meaning and defaults as the ones for
3344
3963
    :Examples:
3345
3964
        Re-do the merge of all conflicted files, and show the base text in
3346
3965
        conflict regions, in addition to the usual THIS and OTHER texts::
3347
 
      
 
3966
 
3348
3967
            bzr remerge --show-base
3349
3968
 
3350
3969
        Re-do the merge of "foobar", using the weave merge algorithm, with
3351
3970
        additional processing to reduce the size of conflict regions::
3352
 
      
 
3971
 
3353
3972
            bzr remerge --merge-type weave --reprocess foobar
3354
3973
    """
3355
3974
    takes_args = ['file*']
3366
3985
            merge_type = _mod_merge.Merge3Merger
3367
3986
        tree, file_list = tree_files(file_list)
3368
3987
        tree.lock_write()
 
3988
        self.add_cleanup(tree.unlock)
 
3989
        parents = tree.get_parent_ids()
 
3990
        if len(parents) != 2:
 
3991
            raise errors.BzrCommandError("Sorry, remerge only works after normal"
 
3992
                                         " merges.  Not cherrypicking or"
 
3993
                                         " multi-merges.")
 
3994
        repository = tree.branch.repository
 
3995
        interesting_ids = None
 
3996
        new_conflicts = []
 
3997
        conflicts = tree.conflicts()
 
3998
        if file_list is not None:
 
3999
            interesting_ids = set()
 
4000
            for filename in file_list:
 
4001
                file_id = tree.path2id(filename)
 
4002
                if file_id is None:
 
4003
                    raise errors.NotVersionedError(filename)
 
4004
                interesting_ids.add(file_id)
 
4005
                if tree.kind(file_id) != "directory":
 
4006
                    continue
 
4007
 
 
4008
                for name, ie in tree.inventory.iter_entries(file_id):
 
4009
                    interesting_ids.add(ie.file_id)
 
4010
            new_conflicts = conflicts.select_conflicts(tree, file_list)[0]
 
4011
        else:
 
4012
            # Remerge only supports resolving contents conflicts
 
4013
            allowed_conflicts = ('text conflict', 'contents conflict')
 
4014
            restore_files = [c.path for c in conflicts
 
4015
                             if c.typestring in allowed_conflicts]
 
4016
        _mod_merge.transform_tree(tree, tree.basis_tree(), interesting_ids)
 
4017
        tree.set_conflicts(ConflictList(new_conflicts))
 
4018
        if file_list is not None:
 
4019
            restore_files = file_list
 
4020
        for filename in restore_files:
 
4021
            try:
 
4022
                restore(tree.abspath(filename))
 
4023
            except errors.NotConflicted:
 
4024
                pass
 
4025
        # Disable pending merges, because the file texts we are remerging
 
4026
        # have not had those merges performed.  If we use the wrong parents
 
4027
        # list, we imply that the working tree text has seen and rejected
 
4028
        # all the changes from the other tree, when in fact those changes
 
4029
        # have not yet been seen.
 
4030
        pb = ui.ui_factory.nested_progress_bar()
 
4031
        tree.set_parent_ids(parents[:1])
3369
4032
        try:
3370
 
            parents = tree.get_parent_ids()
3371
 
            if len(parents) != 2:
3372
 
                raise errors.BzrCommandError("Sorry, remerge only works after normal"
3373
 
                                             " merges.  Not cherrypicking or"
3374
 
                                             " multi-merges.")
3375
 
            repository = tree.branch.repository
3376
 
            interesting_ids = None
3377
 
            new_conflicts = []
3378
 
            conflicts = tree.conflicts()
3379
 
            if file_list is not None:
3380
 
                interesting_ids = set()
3381
 
                for filename in file_list:
3382
 
                    file_id = tree.path2id(filename)
3383
 
                    if file_id is None:
3384
 
                        raise errors.NotVersionedError(filename)
3385
 
                    interesting_ids.add(file_id)
3386
 
                    if tree.kind(file_id) != "directory":
3387
 
                        continue
3388
 
                    
3389
 
                    for name, ie in tree.inventory.iter_entries(file_id):
3390
 
                        interesting_ids.add(ie.file_id)
3391
 
                new_conflicts = conflicts.select_conflicts(tree, file_list)[0]
3392
 
            else:
3393
 
                # Remerge only supports resolving contents conflicts
3394
 
                allowed_conflicts = ('text conflict', 'contents conflict')
3395
 
                restore_files = [c.path for c in conflicts
3396
 
                                 if c.typestring in allowed_conflicts]
3397
 
            _mod_merge.transform_tree(tree, tree.basis_tree(), interesting_ids)
3398
 
            tree.set_conflicts(ConflictList(new_conflicts))
3399
 
            if file_list is not None:
3400
 
                restore_files = file_list
3401
 
            for filename in restore_files:
3402
 
                try:
3403
 
                    restore(tree.abspath(filename))
3404
 
                except errors.NotConflicted:
3405
 
                    pass
3406
 
            # Disable pending merges, because the file texts we are remerging
3407
 
            # have not had those merges performed.  If we use the wrong parents
3408
 
            # list, we imply that the working tree text has seen and rejected
3409
 
            # all the changes from the other tree, when in fact those changes
3410
 
            # have not yet been seen.
3411
 
            pb = ui.ui_factory.nested_progress_bar()
3412
 
            tree.set_parent_ids(parents[:1])
3413
 
            try:
3414
 
                merger = _mod_merge.Merger.from_revision_ids(pb,
3415
 
                                                             tree, parents[1])
3416
 
                merger.interesting_ids = interesting_ids
3417
 
                merger.merge_type = merge_type
3418
 
                merger.show_base = show_base
3419
 
                merger.reprocess = reprocess
3420
 
                conflicts = merger.do_merge()
3421
 
            finally:
3422
 
                tree.set_parent_ids(parents)
3423
 
                pb.finished()
 
4033
            merger = _mod_merge.Merger.from_revision_ids(pb,
 
4034
                                                         tree, parents[1])
 
4035
            merger.interesting_ids = interesting_ids
 
4036
            merger.merge_type = merge_type
 
4037
            merger.show_base = show_base
 
4038
            merger.reprocess = reprocess
 
4039
            conflicts = merger.do_merge()
3424
4040
        finally:
3425
 
            tree.unlock()
 
4041
            tree.set_parent_ids(parents)
 
4042
            pb.finished()
3426
4043
        if conflicts > 0:
3427
4044
            return 1
3428
4045
        else:
3440
4057
    merge instead.  For example, "merge . --revision -2..-3" will remove the
3441
4058
    changes introduced by -2, without affecting the changes introduced by -1.
3442
4059
    Or to remove certain changes on a hunk-by-hunk basis, see the Shelf plugin.
3443
 
    
 
4060
 
3444
4061
    By default, any files that have been manually changed will be backed up
3445
4062
    first.  (Files changed only by merge are not backed up.)  Backup files have
3446
4063
    '.~#~' appended to their name, where # is a number.
3450
4067
    name.  If you name a directory, all the contents of that directory will be
3451
4068
    reverted.
3452
4069
 
3453
 
    Any files that have been newly added since that revision will be deleted,
3454
 
    with a backup kept if appropriate.  Directories containing unknown files
3455
 
    will not be deleted.
 
4070
    If you have newly added files since the target revision, they will be
 
4071
    removed.  If the files to be removed have been changed, backups will be
 
4072
    created as above.  Directories containing unknown files will not be
 
4073
    deleted.
3456
4074
 
3457
4075
    The working tree contains a list of pending merged revisions, which will
3458
4076
    be included as parents in the next commit.  Normally, revert clears that
3461
4079
    revert ." in the tree root to revert all files but keep the merge record,
3462
4080
    and "bzr revert --forget-merges" to clear the pending merge list without
3463
4081
    reverting any files.
 
4082
 
 
4083
    Using "bzr revert --forget-merges", it is possible to apply the changes
 
4084
    from an arbitrary merge as a single revision.  To do this, perform the
 
4085
    merge as desired.  Then doing revert with the "--forget-merges" option will
 
4086
    keep the content of the tree as it was, but it will clear the list of
 
4087
    pending merges.  The next commit will then contain all of the changes that
 
4088
    would have been in the merge, but without any mention of the other parent
 
4089
    revisions.  Because this technique forgets where these changes originated,
 
4090
    it may cause additional conflicts on later merges involving the source and
 
4091
    target branches.
3464
4092
    """
3465
4093
 
3466
4094
    _see_also = ['cat', 'export']
3476
4104
            forget_merges=None):
3477
4105
        tree, file_list = tree_files(file_list)
3478
4106
        tree.lock_write()
3479
 
        try:
3480
 
            if forget_merges:
3481
 
                tree.set_parent_ids(tree.get_parent_ids()[:1])
3482
 
            else:
3483
 
                self._revert_tree_to_revision(tree, revision, file_list, no_backup)
3484
 
        finally:
3485
 
            tree.unlock()
 
4107
        self.add_cleanup(tree.unlock)
 
4108
        if forget_merges:
 
4109
            tree.set_parent_ids(tree.get_parent_ids()[:1])
 
4110
        else:
 
4111
            self._revert_tree_to_revision(tree, revision, file_list, no_backup)
3486
4112
 
3487
4113
    @staticmethod
3488
4114
    def _revert_tree_to_revision(tree, revision, file_list, no_backup):
3515
4141
            ]
3516
4142
    takes_args = ['topic?']
3517
4143
    aliases = ['?', '--help', '-?', '-h']
3518
 
    
 
4144
 
3519
4145
    @display_command
3520
4146
    def run(self, topic=None, long=False):
3521
4147
        import bzrlib.help
3532
4158
    takes_args = ['context?']
3533
4159
    aliases = ['s-c']
3534
4160
    hidden = True
3535
 
    
 
4161
 
3536
4162
    @display_command
3537
4163
    def run(self, context=None):
3538
4164
        import shellcomplete
3544
4170
 
3545
4171
    OTHER_BRANCH may be local or remote.
3546
4172
 
3547
 
    To filter on a range of revirions, you can use the command -r begin..end
 
4173
    To filter on a range of revisions, you can use the command -r begin..end
3548
4174
    -r revision requests a specific revision, -r ..end or -r begin.. are
3549
4175
    also valid.
 
4176
            
 
4177
    :Exit values:
 
4178
        1 - some missing revisions
 
4179
        0 - no missing revisions
3550
4180
 
3551
4181
    :Examples:
3552
4182
 
3590
4220
            type=_parse_revision_str,
3591
4221
            help='Filter on local branch revisions (inclusive). '
3592
4222
                'See "help revisionspec" for details.'),
3593
 
        Option('include-merges', 'Show merged revisions.'),
 
4223
        Option('include-merges',
 
4224
               'Show all revisions in addition to the mainline ones.'),
3594
4225
        ]
3595
4226
    encoding_type = 'replace'
3596
4227
 
3634
4265
        if remote_branch.base == local_branch.base:
3635
4266
            remote_branch = local_branch
3636
4267
 
 
4268
        local_branch.lock_read()
 
4269
        self.add_cleanup(local_branch.unlock)
3637
4270
        local_revid_range = _revision_range_to_revid_range(
3638
4271
            _get_revision_range(my_revision, local_branch,
3639
4272
                self.name()))
3640
4273
 
 
4274
        remote_branch.lock_read()
 
4275
        self.add_cleanup(remote_branch.unlock)
3641
4276
        remote_revid_range = _revision_range_to_revid_range(
3642
4277
            _get_revision_range(revision,
3643
4278
                remote_branch, self.name()))
3644
4279
 
3645
 
        local_branch.lock_read()
3646
 
        try:
3647
 
            remote_branch.lock_read()
3648
 
            try:
3649
 
                local_extra, remote_extra = find_unmerged(
3650
 
                    local_branch, remote_branch, restrict,
3651
 
                    backward=not reverse,
3652
 
                    include_merges=include_merges,
3653
 
                    local_revid_range=local_revid_range,
3654
 
                    remote_revid_range=remote_revid_range)
3655
 
 
3656
 
                if log_format is None:
3657
 
                    registry = log.log_formatter_registry
3658
 
                    log_format = registry.get_default(local_branch)
3659
 
                lf = log_format(to_file=self.outf,
3660
 
                                show_ids=show_ids,
3661
 
                                show_timezone='original')
3662
 
 
3663
 
                status_code = 0
3664
 
                if local_extra and not theirs_only:
3665
 
                    message("You have %d extra revision(s):\n" %
3666
 
                        len(local_extra))
3667
 
                    for revision in iter_log_revisions(local_extra,
3668
 
                                        local_branch.repository,
3669
 
                                        verbose):
3670
 
                        lf.log_revision(revision)
3671
 
                    printed_local = True
3672
 
                    status_code = 1
3673
 
                else:
3674
 
                    printed_local = False
3675
 
 
3676
 
                if remote_extra and not mine_only:
3677
 
                    if printed_local is True:
3678
 
                        message("\n\n\n")
3679
 
                    message("You are missing %d revision(s):\n" %
3680
 
                        len(remote_extra))
3681
 
                    for revision in iter_log_revisions(remote_extra,
3682
 
                                        remote_branch.repository,
3683
 
                                        verbose):
3684
 
                        lf.log_revision(revision)
3685
 
                    status_code = 1
3686
 
 
3687
 
                if mine_only and not local_extra:
3688
 
                    # We checked local, and found nothing extra
3689
 
                    message('This branch is up to date.\n')
3690
 
                elif theirs_only and not remote_extra:
3691
 
                    # We checked remote, and found nothing extra
3692
 
                    message('Other branch is up to date.\n')
3693
 
                elif not (mine_only or theirs_only or local_extra or
3694
 
                          remote_extra):
3695
 
                    # We checked both branches, and neither one had extra
3696
 
                    # revisions
3697
 
                    message("Branches are up to date.\n")
3698
 
            finally:
3699
 
                remote_branch.unlock()
3700
 
        finally:
3701
 
            local_branch.unlock()
 
4280
        local_extra, remote_extra = find_unmerged(
 
4281
            local_branch, remote_branch, restrict,
 
4282
            backward=not reverse,
 
4283
            include_merges=include_merges,
 
4284
            local_revid_range=local_revid_range,
 
4285
            remote_revid_range=remote_revid_range)
 
4286
 
 
4287
        if log_format is None:
 
4288
            registry = log.log_formatter_registry
 
4289
            log_format = registry.get_default(local_branch)
 
4290
        lf = log_format(to_file=self.outf,
 
4291
                        show_ids=show_ids,
 
4292
                        show_timezone='original')
 
4293
 
 
4294
        status_code = 0
 
4295
        if local_extra and not theirs_only:
 
4296
            message("You have %d extra revision(s):\n" %
 
4297
                len(local_extra))
 
4298
            for revision in iter_log_revisions(local_extra,
 
4299
                                local_branch.repository,
 
4300
                                verbose):
 
4301
                lf.log_revision(revision)
 
4302
            printed_local = True
 
4303
            status_code = 1
 
4304
        else:
 
4305
            printed_local = False
 
4306
 
 
4307
        if remote_extra and not mine_only:
 
4308
            if printed_local is True:
 
4309
                message("\n\n\n")
 
4310
            message("You are missing %d revision(s):\n" %
 
4311
                len(remote_extra))
 
4312
            for revision in iter_log_revisions(remote_extra,
 
4313
                                remote_branch.repository,
 
4314
                                verbose):
 
4315
                lf.log_revision(revision)
 
4316
            status_code = 1
 
4317
 
 
4318
        if mine_only and not local_extra:
 
4319
            # We checked local, and found nothing extra
 
4320
            message('This branch is up to date.\n')
 
4321
        elif theirs_only and not remote_extra:
 
4322
            # We checked remote, and found nothing extra
 
4323
            message('Other branch is up to date.\n')
 
4324
        elif not (mine_only or theirs_only or local_extra or
 
4325
                  remote_extra):
 
4326
            # We checked both branches, and neither one had extra
 
4327
            # revisions
 
4328
            message("Branches are up to date.\n")
 
4329
        self.cleanup_now()
3702
4330
        if not status_code and parent is None and other_branch is not None:
3703
4331
            local_branch.lock_write()
3704
 
            try:
3705
 
                # handle race conditions - a parent might be set while we run.
3706
 
                if local_branch.get_parent() is None:
3707
 
                    local_branch.set_parent(remote_branch.base)
3708
 
            finally:
3709
 
                local_branch.unlock()
 
4332
            self.add_cleanup(local_branch.unlock)
 
4333
            # handle race conditions - a parent might be set while we run.
 
4334
            if local_branch.get_parent() is None:
 
4335
                local_branch.set_parent(remote_branch.base)
3710
4336
        return status_code
3711
4337
 
3712
4338
 
3728
4354
 
3729
4355
class cmd_plugins(Command):
3730
4356
    """List the installed plugins.
3731
 
    
 
4357
 
3732
4358
    This command displays the list of installed plugins including
3733
4359
    version of plugin and a short description of each.
3734
4360
 
3791
4417
        else:
3792
4418
            b = Branch.open(branch)
3793
4419
        b.lock_read()
3794
 
        try:
3795
 
            if revision is None:
3796
 
                rev_id = b.last_revision()
3797
 
            else:
3798
 
                rev_id = revision[0].as_revision_id(b)
3799
 
            t = testament_class.from_revision(b.repository, rev_id)
3800
 
            if long:
3801
 
                sys.stdout.writelines(t.as_text_lines())
3802
 
            else:
3803
 
                sys.stdout.write(t.as_short_text())
3804
 
        finally:
3805
 
            b.unlock()
 
4420
        self.add_cleanup(b.unlock)
 
4421
        if revision is None:
 
4422
            rev_id = b.last_revision()
 
4423
        else:
 
4424
            rev_id = revision[0].as_revision_id(b)
 
4425
        t = testament_class.from_revision(b.repository, rev_id)
 
4426
        if long:
 
4427
            sys.stdout.writelines(t.as_text_lines())
 
4428
        else:
 
4429
            sys.stdout.write(t.as_short_text())
3806
4430
 
3807
4431
 
3808
4432
class cmd_annotate(Command):
3811
4435
    This prints out the given file with an annotation on the left side
3812
4436
    indicating which revision, author and date introduced the change.
3813
4437
 
3814
 
    If the origin is the same for a run of consecutive lines, it is 
 
4438
    If the origin is the same for a run of consecutive lines, it is
3815
4439
    shown only at the top, unless the --all option is given.
3816
4440
    """
3817
4441
    # TODO: annotate directories; showing when each file was last changed
3818
 
    # TODO: if the working copy is modified, show annotations on that 
 
4442
    # TODO: if the working copy is modified, show annotations on that
3819
4443
    #       with new uncommitted lines marked
3820
4444
    aliases = ['ann', 'blame', 'praise']
3821
4445
    takes_args = ['filename']
3834
4458
            bzrdir.BzrDir.open_containing_tree_or_branch(filename)
3835
4459
        if wt is not None:
3836
4460
            wt.lock_read()
 
4461
            self.add_cleanup(wt.unlock)
3837
4462
        else:
3838
4463
            branch.lock_read()
3839
 
        try:
3840
 
            tree = _get_one_revision_tree('annotate', revision, branch=branch)
3841
 
            if wt is not None:
3842
 
                file_id = wt.path2id(relpath)
3843
 
            else:
3844
 
                file_id = tree.path2id(relpath)
3845
 
            if file_id is None:
3846
 
                raise errors.NotVersionedError(filename)
3847
 
            file_version = tree.inventory[file_id].revision
3848
 
            if wt is not None and revision is None:
3849
 
                # If there is a tree and we're not annotating historical
3850
 
                # versions, annotate the working tree's content.
3851
 
                annotate_file_tree(wt, file_id, self.outf, long, all,
3852
 
                    show_ids=show_ids)
3853
 
            else:
3854
 
                annotate_file(branch, file_version, file_id, long, all, self.outf,
3855
 
                              show_ids=show_ids)
3856
 
        finally:
3857
 
            if wt is not None:
3858
 
                wt.unlock()
3859
 
            else:
3860
 
                branch.unlock()
 
4464
            self.add_cleanup(branch.unlock)
 
4465
        tree = _get_one_revision_tree('annotate', revision, branch=branch)
 
4466
        tree.lock_read()
 
4467
        self.add_cleanup(tree.unlock)
 
4468
        if wt is not None:
 
4469
            file_id = wt.path2id(relpath)
 
4470
        else:
 
4471
            file_id = tree.path2id(relpath)
 
4472
        if file_id is None:
 
4473
            raise errors.NotVersionedError(filename)
 
4474
        file_version = tree.inventory[file_id].revision
 
4475
        if wt is not None and revision is None:
 
4476
            # If there is a tree and we're not annotating historical
 
4477
            # versions, annotate the working tree's content.
 
4478
            annotate_file_tree(wt, file_id, self.outf, long, all,
 
4479
                show_ids=show_ids)
 
4480
        else:
 
4481
            annotate_file(branch, file_version, file_id, long, all, self.outf,
 
4482
                          show_ids=show_ids)
3861
4483
 
3862
4484
 
3863
4485
class cmd_re_sign(Command):
3867
4489
    hidden = True # is this right ?
3868
4490
    takes_args = ['revision_id*']
3869
4491
    takes_options = ['revision']
3870
 
    
 
4492
 
3871
4493
    def run(self, revision_id_list=None, revision=None):
3872
4494
        if revision_id_list is not None and revision is not None:
3873
4495
            raise errors.BzrCommandError('You can only supply one of revision_id or --revision')
3875
4497
            raise errors.BzrCommandError('You must supply either --revision or a revision_id')
3876
4498
        b = WorkingTree.open_containing(u'.')[0].branch
3877
4499
        b.lock_write()
3878
 
        try:
3879
 
            return self._run(b, revision_id_list, revision)
3880
 
        finally:
3881
 
            b.unlock()
 
4500
        self.add_cleanup(b.unlock)
 
4501
        return self._run(b, revision_id_list, revision)
3882
4502
 
3883
4503
    def _run(self, b, revision_id_list, revision):
3884
4504
        import bzrlib.gpg as gpg
3935
4555
    before they will be applied to the local branch.
3936
4556
 
3937
4557
    Bound branches use the nickname of its master branch unless it is set
3938
 
    locally, in which case binding will update the the local nickname to be
 
4558
    locally, in which case binding will update the local nickname to be
3939
4559
    that of the master.
3940
4560
    """
3941
4561
 
4030
4650
 
4031
4651
        if tree is not None:
4032
4652
            tree.lock_write()
 
4653
            self.add_cleanup(tree.unlock)
4033
4654
        else:
4034
4655
            b.lock_write()
4035
 
        try:
4036
 
            return self._run(b, tree, dry_run, verbose, revision, force,
4037
 
                             local=local)
4038
 
        finally:
4039
 
            if tree is not None:
4040
 
                tree.unlock()
4041
 
            else:
4042
 
                b.unlock()
 
4656
            self.add_cleanup(b.unlock)
 
4657
        return self._run(b, tree, dry_run, verbose, revision, force, local=local)
4043
4658
 
4044
4659
    def _run(self, b, tree, dry_run, verbose, revision, force, local=False):
4045
4660
        from bzrlib.log import log_formatter, show_log
4103
4718
    holding the lock has been stopped.
4104
4719
 
4105
4720
    You can get information on what locks are open via the 'bzr info' command.
4106
 
    
 
4721
 
4107
4722
    :Examples:
4108
4723
        bzr break-lock
4109
4724
    """
4117
4732
            control.break_lock()
4118
4733
        except NotImplementedError:
4119
4734
            pass
4120
 
        
 
4735
 
4121
4736
 
4122
4737
class cmd_wait_until_signalled(Command):
4123
4738
    """Test helper for test_start_and_stop_bzr_subprocess_send_signal.
4141
4756
    takes_options = [
4142
4757
        Option('inet',
4143
4758
               help='Serve on stdin/out for use from inetd or sshd.'),
 
4759
        RegistryOption('protocol',
 
4760
               help="Protocol to serve.",
 
4761
               lazy_registry=('bzrlib.transport', 'transport_server_registry'),
 
4762
               value_switches=True),
4144
4763
        Option('port',
4145
4764
               help='Listen for connections on nominated port of the form '
4146
4765
                    '[hostname:]portnumber.  Passing 0 as the port number will '
4147
 
                    'result in a dynamically allocated port.  The default port is '
4148
 
                    '4155.',
 
4766
                    'result in a dynamically allocated port.  The default port '
 
4767
                    'depends on the protocol.',
4149
4768
               type=str),
4150
4769
        Option('directory',
4151
4770
               help='Serve contents of this directory.',
4153
4772
        Option('allow-writes',
4154
4773
               help='By default the server is a readonly server.  Supplying '
4155
4774
                    '--allow-writes enables write access to the contents of '
4156
 
                    'the served directory and below.'
 
4775
                    'the served directory and below.  Note that ``bzr serve`` '
 
4776
                    'does not perform authentication, so unless some form of '
 
4777
                    'external authentication is arranged supplying this '
 
4778
                    'option leads to global uncontrolled write access to your '
 
4779
                    'file system.'
4157
4780
                ),
4158
4781
        ]
4159
4782
 
4160
 
    def run_smart_server(self, smart_server):
4161
 
        """Run 'smart_server' forever, with no UI output at all."""
4162
 
        # For the duration of this server, no UI output is permitted. note
4163
 
        # that this may cause problems with blackbox tests. This should be
4164
 
        # changed with care though, as we dont want to use bandwidth sending
4165
 
        # progress over stderr to smart server clients!
4166
 
        from bzrlib import lockdir
4167
 
        old_factory = ui.ui_factory
4168
 
        old_lockdir_timeout = lockdir._DEFAULT_TIMEOUT_SECONDS
4169
 
        try:
4170
 
            ui.ui_factory = ui.SilentUIFactory()
4171
 
            lockdir._DEFAULT_TIMEOUT_SECONDS = 0
4172
 
            smart_server.serve()
4173
 
        finally:
4174
 
            ui.ui_factory = old_factory
4175
 
            lockdir._DEFAULT_TIMEOUT_SECONDS = old_lockdir_timeout
4176
 
 
4177
4783
    def get_host_and_port(self, port):
4178
4784
        """Return the host and port to run the smart server on.
4179
4785
 
4180
 
        If 'port' is None, the default host (`medium.BZR_DEFAULT_INTERFACE`)
4181
 
        and port (`medium.BZR_DEFAULT_PORT`) will be used.
 
4786
        If 'port' is None, None will be returned for the host and port.
4182
4787
 
4183
4788
        If 'port' has a colon in it, the string before the colon will be
4184
4789
        interpreted as the host.
4187
4792
        :return: A tuple of (host, port), where 'host' is a host name or IP,
4188
4793
            and port is an integer TCP/IP port.
4189
4794
        """
4190
 
        from bzrlib.smart import medium
4191
 
        host = medium.BZR_DEFAULT_INTERFACE
4192
 
        if port is None:
4193
 
            port = medium.BZR_DEFAULT_PORT
4194
 
        else:
 
4795
        host = None
 
4796
        if port is not None:
4195
4797
            if ':' in port:
4196
4798
                host, port = port.split(':')
4197
4799
            port = int(port)
4198
4800
        return host, port
4199
4801
 
4200
 
    def get_smart_server(self, transport, inet, port):
4201
 
        """Construct a smart server.
4202
 
 
4203
 
        :param transport: The base transport from which branches will be
4204
 
            served.
4205
 
        :param inet: If True, serve over stdin and stdout. Used for running
4206
 
            from inet.
4207
 
        :param port: The port to listen on. By default, it's `
4208
 
            medium.BZR_DEFAULT_PORT`. See `get_host_and_port` for more
4209
 
            information.
4210
 
        :return: A smart server.
4211
 
        """
4212
 
        from bzrlib.smart import medium, server
4213
 
        if inet:
4214
 
            smart_server = medium.SmartServerPipeStreamMedium(
4215
 
                sys.stdin, sys.stdout, transport)
4216
 
        else:
4217
 
            host, port = self.get_host_and_port(port)
4218
 
            smart_server = server.SmartTCPServer(
4219
 
                transport, host=host, port=port)
4220
 
            note('listening on port: %s' % smart_server.port)
4221
 
        return smart_server
4222
 
 
4223
 
    def run(self, port=None, inet=False, directory=None, allow_writes=False):
4224
 
        from bzrlib.transport import get_transport
4225
 
        from bzrlib.transport.chroot import ChrootServer
 
4802
    def run(self, port=None, inet=False, directory=None, allow_writes=False,
 
4803
            protocol=None):
 
4804
        from bzrlib.transport import get_transport, transport_server_registry
4226
4805
        if directory is None:
4227
4806
            directory = os.getcwd()
 
4807
        if protocol is None:
 
4808
            protocol = transport_server_registry.get()
 
4809
        host, port = self.get_host_and_port(port)
4228
4810
        url = urlutils.local_path_to_url(directory)
4229
4811
        if not allow_writes:
4230
4812
            url = 'readonly+' + url
4231
 
        chroot_server = ChrootServer(get_transport(url))
4232
 
        chroot_server.setUp()
4233
 
        t = get_transport(chroot_server.get_url())
4234
 
        smart_server = self.get_smart_server(t, inet, port)
4235
 
        self.run_smart_server(smart_server)
 
4813
        transport = get_transport(url)
 
4814
        protocol(transport, host, port, inet)
4236
4815
 
4237
4816
 
4238
4817
class cmd_join(Command):
4239
 
    """Combine a subtree into its containing tree.
4240
 
    
4241
 
    This command is for experimental use only.  It requires the target tree
4242
 
    to be in dirstate-with-subtree format, which cannot be converted into
4243
 
    earlier formats.
 
4818
    """Combine a tree into its containing tree.
 
4819
 
 
4820
    This command requires the target tree to be in a rich-root format.
4244
4821
 
4245
4822
    The TREE argument should be an independent tree, inside another tree, but
4246
4823
    not part of it.  (Such trees can be produced by "bzr split", but also by
4249
4826
    The result is a combined tree, with the subtree no longer an independant
4250
4827
    part.  This is marked as a merge of the subtree into the containing tree,
4251
4828
    and all history is preserved.
4252
 
 
4253
 
    If --reference is specified, the subtree retains its independence.  It can
4254
 
    be branched by itself, and can be part of multiple projects at the same
4255
 
    time.  But operations performed in the containing tree, such as commit
4256
 
    and merge, will recurse into the subtree.
4257
4829
    """
4258
4830
 
4259
4831
    _see_also = ['split']
4260
4832
    takes_args = ['tree']
4261
4833
    takes_options = [
4262
 
            Option('reference', help='Join by reference.'),
 
4834
            Option('reference', help='Join by reference.', hidden=True),
4263
4835
            ]
4264
 
    hidden = True
4265
4836
 
4266
4837
    def run(self, tree, reference=False):
4267
4838
        sub_tree = WorkingTree.open(tree)
4285
4856
            try:
4286
4857
                containing_tree.subsume(sub_tree)
4287
4858
            except errors.BadSubsumeSource, e:
4288
 
                raise errors.BzrCommandError("Cannot join %s.  %s" % 
 
4859
                raise errors.BzrCommandError("Cannot join %s.  %s" %
4289
4860
                                             (tree, e.reason))
4290
4861
 
4291
4862
 
4301
4872
    branch.  Commits in the top-level tree will not apply to the new subtree.
4302
4873
    """
4303
4874
 
4304
 
    # join is not un-hidden yet
4305
 
    #_see_also = ['join']
 
4875
    _see_also = ['join']
4306
4876
    takes_args = ['tree']
4307
4877
 
4308
4878
    def run(self, tree):
4313
4883
        try:
4314
4884
            containing_tree.extract(sub_id)
4315
4885
        except errors.RootNotRich:
4316
 
            raise errors.UpgradeRequired(containing_tree.branch.base)
 
4886
            raise errors.RichRootUpgradeRequired(containing_tree.branch.base)
4317
4887
 
4318
4888
 
4319
4889
class cmd_merge_directive(Command):
4444
5014
    Mail is sent using your preferred mail program.  This should be transparent
4445
5015
    on Windows (it uses MAPI).  On Linux, it requires the xdg-email utility.
4446
5016
    If the preferred client can't be found (or used), your editor will be used.
4447
 
    
 
5017
 
4448
5018
    To use a specific mail program, set the mail_client configuration option.
4449
5019
    (For Thunderbird 1.5, this works around some bugs.)  Supported values for
4450
 
    specific clients are "claws", "evolution", "kmail", "mutt", and
4451
 
    "thunderbird"; generic options are "default", "editor", "emacsclient",
4452
 
    "mapi", and "xdg-email".  Plugins may also add supported clients.
 
5020
    specific clients are "claws", "evolution", "kmail", "mail.app" (MacOS X's
 
5021
    Mail.app), "mutt", and "thunderbird"; generic options are "default",
 
5022
    "editor", "emacsclient", "mapi", and "xdg-email".  Plugins may also add
 
5023
    supported clients.
4453
5024
 
4454
5025
    If mail is being sent, a to address is required.  This can be supplied
4455
5026
    either on the commandline, by setting the submit_to configuration
4456
 
    option in the branch itself or the child_submit_to configuration option 
 
5027
    option in the branch itself or the child_submit_to configuration option
4457
5028
    in the submit branch.
4458
5029
 
4459
5030
    Two formats are currently supported: "4" uses revision bundle format 4 and
4461
5032
    older formats.  It is compatible with Bazaar 0.19 and later.  It is the
4462
5033
    default.  "0.9" uses revision bundle format 0.9 and merge directive
4463
5034
    format 1.  It is compatible with Bazaar 0.12 - 0.18.
4464
 
    
4465
 
    Merge directives are applied using the merge command or the pull command.
 
5035
 
 
5036
    The merge directives created by bzr send may be applied using bzr merge or
 
5037
    bzr pull by specifying a file containing a merge directive as the location.
4466
5038
    """
4467
5039
 
4468
5040
    encoding_type = 'exact'
4487
5059
               help='Write merge directive to this file; '
4488
5060
                    'use - for stdout.',
4489
5061
               type=unicode),
 
5062
        Option('strict',
 
5063
               help='Refuse to send if there are uncommitted changes in'
 
5064
               ' the working tree, --no-strict disables the check.'),
4490
5065
        Option('mail-to', help='Mail the request to this address.',
4491
5066
               type=unicode),
4492
5067
        'revision',
4493
5068
        'message',
4494
 
        RegistryOption.from_kwargs('format',
4495
 
        'Use the specified output format.',
4496
 
        **{'4': 'Bundle format 4, Merge Directive 2 (default)',
4497
 
           '0.9': 'Bundle format 0.9, Merge Directive 1',})
 
5069
        Option('body', help='Body for the email.', type=unicode),
 
5070
        RegistryOption('format',
 
5071
                       help='Use the specified output format.',
 
5072
                       lazy_registry=('bzrlib.send', 'format_registry')),
4498
5073
        ]
4499
5074
 
4500
5075
    def run(self, submit_branch=None, public_branch=None, no_bundle=False,
4501
5076
            no_patch=False, revision=None, remember=False, output=None,
4502
 
            format='4', mail_to=None, message=None, **kwargs):
4503
 
        return self._run(submit_branch, revision, public_branch, remember,
4504
 
                         format, no_bundle, no_patch, output,
4505
 
                         kwargs.get('from', '.'), mail_to, message)
4506
 
 
4507
 
    def _run(self, submit_branch, revision, public_branch, remember, format,
4508
 
             no_bundle, no_patch, output, from_, mail_to, message):
4509
 
        from bzrlib.revision import NULL_REVISION
4510
 
        branch = Branch.open_containing(from_)[0]
4511
 
        if output is None:
4512
 
            outfile = cStringIO.StringIO()
4513
 
        elif output == '-':
4514
 
            outfile = self.outf
4515
 
        else:
4516
 
            outfile = open(output, 'wb')
4517
 
        # we may need to write data into branch's repository to calculate
4518
 
        # the data to send.
4519
 
        branch.lock_write()
4520
 
        try:
4521
 
            if output is None:
4522
 
                config = branch.get_config()
4523
 
                if mail_to is None:
4524
 
                    mail_to = config.get_user_option('submit_to')
4525
 
                mail_client = config.get_mail_client()
4526
 
            if remember and submit_branch is None:
4527
 
                raise errors.BzrCommandError(
4528
 
                    '--remember requires a branch to be specified.')
4529
 
            stored_submit_branch = branch.get_submit_branch()
4530
 
            remembered_submit_branch = None
4531
 
            if submit_branch is None:
4532
 
                submit_branch = stored_submit_branch
4533
 
                remembered_submit_branch = "submit"
4534
 
            else:
4535
 
                if stored_submit_branch is None or remember:
4536
 
                    branch.set_submit_branch(submit_branch)
4537
 
            if submit_branch is None:
4538
 
                submit_branch = branch.get_parent()
4539
 
                remembered_submit_branch = "parent"
4540
 
            if submit_branch is None:
4541
 
                raise errors.BzrCommandError('No submit branch known or'
4542
 
                                             ' specified')
4543
 
            if remembered_submit_branch is not None:
4544
 
                note('Using saved %s location "%s" to determine what '
4545
 
                        'changes to submit.', remembered_submit_branch,
4546
 
                        submit_branch)
4547
 
 
4548
 
            if mail_to is None:
4549
 
                submit_config = Branch.open(submit_branch).get_config()
4550
 
                mail_to = submit_config.get_user_option("child_submit_to")
4551
 
 
4552
 
            stored_public_branch = branch.get_public_branch()
4553
 
            if public_branch is None:
4554
 
                public_branch = stored_public_branch
4555
 
            elif stored_public_branch is None or remember:
4556
 
                branch.set_public_branch(public_branch)
4557
 
            if no_bundle and public_branch is None:
4558
 
                raise errors.BzrCommandError('No public branch specified or'
4559
 
                                             ' known')
4560
 
            base_revision_id = None
4561
 
            revision_id = None
4562
 
            if revision is not None:
4563
 
                if len(revision) > 2:
4564
 
                    raise errors.BzrCommandError('bzr send takes '
4565
 
                        'at most two one revision identifiers')
4566
 
                revision_id = revision[-1].as_revision_id(branch)
4567
 
                if len(revision) == 2:
4568
 
                    base_revision_id = revision[0].as_revision_id(branch)
4569
 
            if revision_id is None:
4570
 
                revision_id = branch.last_revision()
4571
 
            if revision_id == NULL_REVISION:
4572
 
                raise errors.BzrCommandError('No revisions to submit.')
4573
 
            if format == '4':
4574
 
                directive = merge_directive.MergeDirective2.from_objects(
4575
 
                    branch.repository, revision_id, time.time(),
4576
 
                    osutils.local_time_offset(), submit_branch,
4577
 
                    public_branch=public_branch, include_patch=not no_patch,
4578
 
                    include_bundle=not no_bundle, message=message,
4579
 
                    base_revision_id=base_revision_id)
4580
 
            elif format == '0.9':
4581
 
                if not no_bundle:
4582
 
                    if not no_patch:
4583
 
                        patch_type = 'bundle'
4584
 
                    else:
4585
 
                        raise errors.BzrCommandError('Format 0.9 does not'
4586
 
                            ' permit bundle with no patch')
4587
 
                else:
4588
 
                    if not no_patch:
4589
 
                        patch_type = 'diff'
4590
 
                    else:
4591
 
                        patch_type = None
4592
 
                directive = merge_directive.MergeDirective.from_objects(
4593
 
                    branch.repository, revision_id, time.time(),
4594
 
                    osutils.local_time_offset(), submit_branch,
4595
 
                    public_branch=public_branch, patch_type=patch_type,
4596
 
                    message=message)
4597
 
 
4598
 
            outfile.writelines(directive.to_lines())
4599
 
            if output is None:
4600
 
                subject = '[MERGE] '
4601
 
                if message is not None:
4602
 
                    subject += message
4603
 
                else:
4604
 
                    revision = branch.repository.get_revision(revision_id)
4605
 
                    subject += revision.get_summary()
4606
 
                basename = directive.get_disk_name(branch)
4607
 
                mail_client.compose_merge_request(mail_to, subject,
4608
 
                                                  outfile.getvalue(), basename)
4609
 
        finally:
4610
 
            if output != '-':
4611
 
                outfile.close()
4612
 
            branch.unlock()
 
5077
            format=None, mail_to=None, message=None, body=None,
 
5078
            strict=None, **kwargs):
 
5079
        from bzrlib.send import send
 
5080
        return send(submit_branch, revision, public_branch, remember,
 
5081
                    format, no_bundle, no_patch, output,
 
5082
                    kwargs.get('from', '.'), mail_to, message, body,
 
5083
                    self.outf,
 
5084
                    strict=strict)
4613
5085
 
4614
5086
 
4615
5087
class cmd_bundle_revisions(cmd_send):
4616
 
 
4617
5088
    """Create a merge-directive for submitting changes.
4618
5089
 
4619
5090
    A merge directive provides many things needed for requesting merges:
4660
5131
               type=unicode),
4661
5132
        Option('output', short_name='o', help='Write directive to this file.',
4662
5133
               type=unicode),
 
5134
        Option('strict',
 
5135
               help='Refuse to bundle revisions if there are uncommitted'
 
5136
               ' changes in the working tree, --no-strict disables the check.'),
4663
5137
        'revision',
4664
 
        RegistryOption.from_kwargs('format',
4665
 
        'Use the specified output format.',
4666
 
        **{'4': 'Bundle format 4, Merge Directive 2 (default)',
4667
 
           '0.9': 'Bundle format 0.9, Merge Directive 1',})
 
5138
        RegistryOption('format',
 
5139
                       help='Use the specified output format.',
 
5140
                       lazy_registry=('bzrlib.send', 'format_registry')),
4668
5141
        ]
4669
5142
    aliases = ['bundle']
4670
5143
 
4674
5147
 
4675
5148
    def run(self, submit_branch=None, public_branch=None, no_bundle=False,
4676
5149
            no_patch=False, revision=None, remember=False, output=None,
4677
 
            format='4', **kwargs):
 
5150
            format=None, strict=None, **kwargs):
4678
5151
        if output is None:
4679
5152
            output = '-'
4680
 
        return self._run(submit_branch, revision, public_branch, remember,
 
5153
        from bzrlib.send import send
 
5154
        return send(submit_branch, revision, public_branch, remember,
4681
5155
                         format, no_bundle, no_patch, output,
4682
 
                         kwargs.get('from', '.'), None, None)
 
5156
                         kwargs.get('from', '.'), None, None, None,
 
5157
                         self.outf, strict=strict)
4683
5158
 
4684
5159
 
4685
5160
class cmd_tag(Command):
4686
5161
    """Create, remove or modify a tag naming a revision.
4687
 
    
 
5162
 
4688
5163
    Tags give human-meaningful names to revisions.  Commands that take a -r
4689
5164
    (--revision) option can be given -rtag:X, where X is any previously
4690
5165
    created tag.
4692
5167
    Tags are stored in the branch.  Tags are copied from one branch to another
4693
5168
    along when you branch, push, pull or merge.
4694
5169
 
4695
 
    It is an error to give a tag name that already exists unless you pass 
 
5170
    It is an error to give a tag name that already exists unless you pass
4696
5171
    --force, in which case the tag is moved to point to the new revision.
4697
5172
 
4698
5173
    To rename a tag (change the name but keep it on the same revsion), run ``bzr
4724
5199
            ):
4725
5200
        branch, relpath = Branch.open_containing(directory)
4726
5201
        branch.lock_write()
4727
 
        try:
4728
 
            if delete:
4729
 
                branch.tags.delete_tag(tag_name)
4730
 
                self.outf.write('Deleted tag %s.\n' % tag_name)
 
5202
        self.add_cleanup(branch.unlock)
 
5203
        if delete:
 
5204
            branch.tags.delete_tag(tag_name)
 
5205
            self.outf.write('Deleted tag %s.\n' % tag_name)
 
5206
        else:
 
5207
            if revision:
 
5208
                if len(revision) != 1:
 
5209
                    raise errors.BzrCommandError(
 
5210
                        "Tags can only be placed on a single revision, "
 
5211
                        "not on a range")
 
5212
                revision_id = revision[0].as_revision_id(branch)
4731
5213
            else:
4732
 
                if revision:
4733
 
                    if len(revision) != 1:
4734
 
                        raise errors.BzrCommandError(
4735
 
                            "Tags can only be placed on a single revision, "
4736
 
                            "not on a range")
4737
 
                    revision_id = revision[0].as_revision_id(branch)
4738
 
                else:
4739
 
                    revision_id = branch.last_revision()
4740
 
                if (not force) and branch.tags.has_tag(tag_name):
4741
 
                    raise errors.TagAlreadyExists(tag_name)
4742
 
                branch.tags.set_tag(tag_name, revision_id)
4743
 
                self.outf.write('Created tag %s.\n' % tag_name)
4744
 
        finally:
4745
 
            branch.unlock()
 
5214
                revision_id = branch.last_revision()
 
5215
            if (not force) and branch.tags.has_tag(tag_name):
 
5216
                raise errors.TagAlreadyExists(tag_name)
 
5217
            branch.tags.set_tag(tag_name, revision_id)
 
5218
            self.outf.write('Created tag %s.\n' % tag_name)
4746
5219
 
4747
5220
 
4748
5221
class cmd_tags(Command):
4780
5253
        if not tags:
4781
5254
            return
4782
5255
 
 
5256
        branch.lock_read()
 
5257
        self.add_cleanup(branch.unlock)
4783
5258
        if revision:
4784
 
            branch.lock_read()
4785
 
            try:
4786
 
                graph = branch.repository.get_graph()
4787
 
                rev1, rev2 = _get_revision_range(revision, branch, self.name())
4788
 
                revid1, revid2 = rev1.rev_id, rev2.rev_id
4789
 
                # only show revisions between revid1 and revid2 (inclusive)
4790
 
                tags = [(tag, revid) for tag, revid in tags if
4791
 
                    graph.is_between(revid, revid1, revid2)]
4792
 
            finally:
4793
 
                branch.unlock()
 
5259
            graph = branch.repository.get_graph()
 
5260
            rev1, rev2 = _get_revision_range(revision, branch, self.name())
 
5261
            revid1, revid2 = rev1.rev_id, rev2.rev_id
 
5262
            # only show revisions between revid1 and revid2 (inclusive)
 
5263
            tags = [(tag, revid) for tag, revid in tags if
 
5264
                graph.is_between(revid, revid1, revid2)]
4794
5265
        if sort == 'alpha':
4795
5266
            tags.sort()
4796
5267
        elif sort == 'time':
4806
5277
            tags.sort(key=lambda x: timestamps[x[1]])
4807
5278
        if not show_ids:
4808
5279
            # [ (tag, revid), ... ] -> [ (tag, dotted_revno), ... ]
4809
 
            revno_map = branch.get_revision_id_to_revno_map()
4810
 
            tags = [ (tag, '.'.join(map(str, revno_map.get(revid, ('?',)))))
4811
 
                        for tag, revid in tags ]
 
5280
            for index, (tag, revid) in enumerate(tags):
 
5281
                try:
 
5282
                    revno = branch.revision_id_to_dotted_revno(revid)
 
5283
                    if isinstance(revno, tuple):
 
5284
                        revno = '.'.join(map(str, revno))
 
5285
                except errors.NoSuchRevision:
 
5286
                    # Bad tag data/merges can lead to tagged revisions
 
5287
                    # which are not in this branch. Fail gracefully ...
 
5288
                    revno = '?'
 
5289
                tags[index] = (tag, revno)
 
5290
        self.cleanup_now()
4812
5291
        for tag, revspec in tags:
4813
5292
            self.outf.write('%-20s %s\n' % (tag, revspec))
4814
5293
 
4829
5308
 
4830
5309
    _see_also = ['branches', 'checkouts', 'standalone-trees', 'working-trees']
4831
5310
    takes_args = ['location?']
4832
 
    takes_options = [RegistryOption.from_kwargs('target_type',
4833
 
                     title='Target type',
4834
 
                     help='The type to reconfigure the directory to.',
4835
 
                     value_switches=True, enum_switch=False,
4836
 
                     branch='Reconfigure to be an unbound branch '
4837
 
                        'with no working tree.',
4838
 
                     tree='Reconfigure to be an unbound branch '
4839
 
                        'with a working tree.',
4840
 
                     checkout='Reconfigure to be a bound branch '
4841
 
                        'with a working tree.',
4842
 
                     lightweight_checkout='Reconfigure to be a lightweight'
4843
 
                     ' checkout (with no local history).',
4844
 
                     standalone='Reconfigure to be a standalone branch '
4845
 
                        '(i.e. stop using shared repository).',
4846
 
                     use_shared='Reconfigure to use a shared repository.'),
4847
 
                     Option('bind-to', help='Branch to bind checkout to.',
4848
 
                            type=str),
4849
 
                     Option('force',
4850
 
                        help='Perform reconfiguration even if local changes'
4851
 
                        ' will be lost.')
4852
 
                     ]
 
5311
    takes_options = [
 
5312
        RegistryOption.from_kwargs(
 
5313
            'target_type',
 
5314
            title='Target type',
 
5315
            help='The type to reconfigure the directory to.',
 
5316
            value_switches=True, enum_switch=False,
 
5317
            branch='Reconfigure to be an unbound branch with no working tree.',
 
5318
            tree='Reconfigure to be an unbound branch with a working tree.',
 
5319
            checkout='Reconfigure to be a bound branch with a working tree.',
 
5320
            lightweight_checkout='Reconfigure to be a lightweight'
 
5321
                ' checkout (with no local history).',
 
5322
            standalone='Reconfigure to be a standalone branch '
 
5323
                '(i.e. stop using shared repository).',
 
5324
            use_shared='Reconfigure to use a shared repository.',
 
5325
            with_trees='Reconfigure repository to create '
 
5326
                'working trees on branches by default.',
 
5327
            with_no_trees='Reconfigure repository to not create '
 
5328
                'working trees on branches by default.'
 
5329
            ),
 
5330
        Option('bind-to', help='Branch to bind checkout to.', type=str),
 
5331
        Option('force',
 
5332
            help='Perform reconfiguration even if local changes'
 
5333
            ' will be lost.'),
 
5334
        Option('stacked-on',
 
5335
            help='Reconfigure a branch to be stacked on another branch.',
 
5336
            type=unicode,
 
5337
            ),
 
5338
        Option('unstacked',
 
5339
            help='Reconfigure a branch to be unstacked.  This '
 
5340
                'may require copying substantial data into it.',
 
5341
            ),
 
5342
        ]
4853
5343
 
4854
 
    def run(self, location=None, target_type=None, bind_to=None, force=False):
 
5344
    def run(self, location=None, target_type=None, bind_to=None, force=False,
 
5345
            stacked_on=None,
 
5346
            unstacked=None):
4855
5347
        directory = bzrdir.BzrDir.open(location)
 
5348
        if stacked_on and unstacked:
 
5349
            raise BzrCommandError("Can't use both --stacked-on and --unstacked")
 
5350
        elif stacked_on is not None:
 
5351
            reconfigure.ReconfigureStackedOn().apply(directory, stacked_on)
 
5352
        elif unstacked:
 
5353
            reconfigure.ReconfigureUnstacked().apply(directory)
 
5354
        # At the moment you can use --stacked-on and a different
 
5355
        # reconfiguration shape at the same time; there seems no good reason
 
5356
        # to ban it.
4856
5357
        if target_type is None:
4857
 
            raise errors.BzrCommandError('No target configuration specified')
 
5358
            if stacked_on or unstacked:
 
5359
                return
 
5360
            else:
 
5361
                raise errors.BzrCommandError('No target configuration '
 
5362
                    'specified')
4858
5363
        elif target_type == 'branch':
4859
5364
            reconfiguration = reconfigure.Reconfigure.to_branch(directory)
4860
5365
        elif target_type == 'tree':
4861
5366
            reconfiguration = reconfigure.Reconfigure.to_tree(directory)
4862
5367
        elif target_type == 'checkout':
4863
 
            reconfiguration = reconfigure.Reconfigure.to_checkout(directory,
4864
 
                                                                  bind_to)
 
5368
            reconfiguration = reconfigure.Reconfigure.to_checkout(
 
5369
                directory, bind_to)
4865
5370
        elif target_type == 'lightweight-checkout':
4866
5371
            reconfiguration = reconfigure.Reconfigure.to_lightweight_checkout(
4867
5372
                directory, bind_to)
4869
5374
            reconfiguration = reconfigure.Reconfigure.to_use_shared(directory)
4870
5375
        elif target_type == 'standalone':
4871
5376
            reconfiguration = reconfigure.Reconfigure.to_standalone(directory)
 
5377
        elif target_type == 'with-trees':
 
5378
            reconfiguration = reconfigure.Reconfigure.set_repository_trees(
 
5379
                directory, True)
 
5380
        elif target_type == 'with-no-trees':
 
5381
            reconfiguration = reconfigure.Reconfigure.set_repository_trees(
 
5382
                directory, False)
4872
5383
        reconfiguration.apply(force)
4873
5384
 
4874
5385
 
4875
5386
class cmd_switch(Command):
4876
5387
    """Set the branch of a checkout and update.
4877
 
    
 
5388
 
4878
5389
    For lightweight checkouts, this changes the branch being referenced.
4879
5390
    For heavyweight checkouts, this checks that there are no local commits
4880
5391
    versus the current bound branch, then it makes the local branch a mirror
4891
5402
    /path/to/newbranch.
4892
5403
 
4893
5404
    Bound branches use the nickname of its master branch unless it is set
4894
 
    locally, in which case switching will update the the local nickname to be
 
5405
    locally, in which case switching will update the local nickname to be
4895
5406
    that of the master.
4896
5407
    """
4897
5408
 
4898
5409
    takes_args = ['to_location?']
4899
5410
    takes_options = [Option('force',
4900
5411
                        help='Switch even if local commits will be lost.'),
4901
 
                     'revision'
4902
 
                     ]
 
5412
                     'revision',
 
5413
                     Option('create-branch', short_name='b',
 
5414
                        help='Create the target branch from this one before'
 
5415
                             ' switching to it.'),
 
5416
                    ]
4903
5417
 
4904
 
    def run(self, to_location=None, force=False, revision=None):
 
5418
    def run(self, to_location=None, force=False, create_branch=False,
 
5419
            revision=None):
4905
5420
        from bzrlib import switch
4906
5421
        tree_location = '.'
4907
5422
        revision = _get_one_revision('switch', revision)
4908
5423
        control_dir = bzrdir.BzrDir.open_containing(tree_location)[0]
4909
 
        branch = control_dir.open_branch()
4910
5424
        if to_location is None:
4911
5425
            if revision is None:
4912
5426
                raise errors.BzrCommandError('You must supply either a'
4913
5427
                                             ' revision or a location')
4914
5428
            to_location = '.'
4915
5429
        try:
4916
 
            to_branch = Branch.open(to_location)
 
5430
            branch = control_dir.open_branch()
 
5431
            had_explicit_nick = branch.get_config().has_explicit_nickname()
4917
5432
        except errors.NotBranchError:
4918
 
            this_branch = control_dir.open_branch()
4919
 
            # This may be a heavy checkout, where we want the master branch
4920
 
            this_url = this_branch.get_bound_location()
4921
 
            # If not, use a local sibling
4922
 
            if this_url is None:
4923
 
                this_url = this_branch.base
4924
 
            to_branch = Branch.open(
4925
 
                urlutils.join(this_url, '..', to_location))
 
5433
            branch = None
 
5434
            had_explicit_nick = False
 
5435
        if create_branch:
 
5436
            if branch is None:
 
5437
                raise errors.BzrCommandError('cannot create branch without'
 
5438
                                             ' source branch')
 
5439
            to_location = directory_service.directories.dereference(
 
5440
                              to_location)
 
5441
            if '/' not in to_location and '\\' not in to_location:
 
5442
                # This path is meant to be relative to the existing branch
 
5443
                this_url = self._get_branch_location(control_dir)
 
5444
                to_location = urlutils.join(this_url, '..', to_location)
 
5445
            to_branch = branch.bzrdir.sprout(to_location,
 
5446
                                 possible_transports=[branch.bzrdir.root_transport],
 
5447
                                 source_branch=branch).open_branch()
 
5448
            # try:
 
5449
            #     from_branch = control_dir.open_branch()
 
5450
            # except errors.NotBranchError:
 
5451
            #     raise BzrCommandError('Cannot create a branch from this'
 
5452
            #         ' location when we cannot open this branch')
 
5453
            # from_branch.bzrdir.sprout(
 
5454
            pass
 
5455
        else:
 
5456
            try:
 
5457
                to_branch = Branch.open(to_location)
 
5458
            except errors.NotBranchError:
 
5459
                this_url = self._get_branch_location(control_dir)
 
5460
                to_branch = Branch.open(
 
5461
                    urlutils.join(this_url, '..', to_location))
4926
5462
        if revision is not None:
4927
5463
            revision = revision.as_revision_id(to_branch)
4928
 
        switch.switch(control_dir, to_branch, force, revision)
4929
 
        if branch.get_config().has_explicit_nickname():
 
5464
        switch.switch(control_dir, to_branch, force, revision_id=revision)
 
5465
        if had_explicit_nick:
4930
5466
            branch = control_dir.open_branch() #get the new branch!
4931
5467
            branch.nick = to_branch.nick
4932
5468
        note('Switched to branch: %s',
4933
5469
            urlutils.unescape_for_display(to_branch.base, 'utf-8'))
4934
5470
 
 
5471
    def _get_branch_location(self, control_dir):
 
5472
        """Return location of branch for this control dir."""
 
5473
        try:
 
5474
            this_branch = control_dir.open_branch()
 
5475
            # This may be a heavy checkout, where we want the master branch
 
5476
            master_location = this_branch.get_bound_location()
 
5477
            if master_location is not None:
 
5478
                return master_location
 
5479
            # If not, use a local sibling
 
5480
            return this_branch.base
 
5481
        except errors.NotBranchError:
 
5482
            format = control_dir.find_branch_format()
 
5483
            if getattr(format, 'get_reference', None) is not None:
 
5484
                return format.get_reference(control_dir)
 
5485
            else:
 
5486
                return control_dir.root_transport.base
 
5487
 
 
5488
 
 
5489
class cmd_view(Command):
 
5490
    """Manage filtered views.
 
5491
 
 
5492
    Views provide a mask over the tree so that users can focus on
 
5493
    a subset of a tree when doing their work. After creating a view,
 
5494
    commands that support a list of files - status, diff, commit, etc -
 
5495
    effectively have that list of files implicitly given each time.
 
5496
    An explicit list of files can still be given but those files
 
5497
    must be within the current view.
 
5498
 
 
5499
    In most cases, a view has a short life-span: it is created to make
 
5500
    a selected change and is deleted once that change is committed.
 
5501
    At other times, you may wish to create one or more named views
 
5502
    and switch between them.
 
5503
 
 
5504
    To disable the current view without deleting it, you can switch to
 
5505
    the pseudo view called ``off``. This can be useful when you need
 
5506
    to see the whole tree for an operation or two (e.g. merge) but
 
5507
    want to switch back to your view after that.
 
5508
 
 
5509
    :Examples:
 
5510
      To define the current view::
 
5511
 
 
5512
        bzr view file1 dir1 ...
 
5513
 
 
5514
      To list the current view::
 
5515
 
 
5516
        bzr view
 
5517
 
 
5518
      To delete the current view::
 
5519
 
 
5520
        bzr view --delete
 
5521
 
 
5522
      To disable the current view without deleting it::
 
5523
 
 
5524
        bzr view --switch off
 
5525
 
 
5526
      To define a named view and switch to it::
 
5527
 
 
5528
        bzr view --name view-name file1 dir1 ...
 
5529
 
 
5530
      To list a named view::
 
5531
 
 
5532
        bzr view --name view-name
 
5533
 
 
5534
      To delete a named view::
 
5535
 
 
5536
        bzr view --name view-name --delete
 
5537
 
 
5538
      To switch to a named view::
 
5539
 
 
5540
        bzr view --switch view-name
 
5541
 
 
5542
      To list all views defined::
 
5543
 
 
5544
        bzr view --all
 
5545
 
 
5546
      To delete all views::
 
5547
 
 
5548
        bzr view --delete --all
 
5549
    """
 
5550
 
 
5551
    _see_also = []
 
5552
    takes_args = ['file*']
 
5553
    takes_options = [
 
5554
        Option('all',
 
5555
            help='Apply list or delete action to all views.',
 
5556
            ),
 
5557
        Option('delete',
 
5558
            help='Delete the view.',
 
5559
            ),
 
5560
        Option('name',
 
5561
            help='Name of the view to define, list or delete.',
 
5562
            type=unicode,
 
5563
            ),
 
5564
        Option('switch',
 
5565
            help='Name of the view to switch to.',
 
5566
            type=unicode,
 
5567
            ),
 
5568
        ]
 
5569
 
 
5570
    def run(self, file_list,
 
5571
            all=False,
 
5572
            delete=False,
 
5573
            name=None,
 
5574
            switch=None,
 
5575
            ):
 
5576
        tree, file_list = tree_files(file_list, apply_view=False)
 
5577
        current_view, view_dict = tree.views.get_view_info()
 
5578
        if name is None:
 
5579
            name = current_view
 
5580
        if delete:
 
5581
            if file_list:
 
5582
                raise errors.BzrCommandError(
 
5583
                    "Both --delete and a file list specified")
 
5584
            elif switch:
 
5585
                raise errors.BzrCommandError(
 
5586
                    "Both --delete and --switch specified")
 
5587
            elif all:
 
5588
                tree.views.set_view_info(None, {})
 
5589
                self.outf.write("Deleted all views.\n")
 
5590
            elif name is None:
 
5591
                raise errors.BzrCommandError("No current view to delete")
 
5592
            else:
 
5593
                tree.views.delete_view(name)
 
5594
                self.outf.write("Deleted '%s' view.\n" % name)
 
5595
        elif switch:
 
5596
            if file_list:
 
5597
                raise errors.BzrCommandError(
 
5598
                    "Both --switch and a file list specified")
 
5599
            elif all:
 
5600
                raise errors.BzrCommandError(
 
5601
                    "Both --switch and --all specified")
 
5602
            elif switch == 'off':
 
5603
                if current_view is None:
 
5604
                    raise errors.BzrCommandError("No current view to disable")
 
5605
                tree.views.set_view_info(None, view_dict)
 
5606
                self.outf.write("Disabled '%s' view.\n" % (current_view))
 
5607
            else:
 
5608
                tree.views.set_view_info(switch, view_dict)
 
5609
                view_str = views.view_display_str(tree.views.lookup_view())
 
5610
                self.outf.write("Using '%s' view: %s\n" % (switch, view_str))
 
5611
        elif all:
 
5612
            if view_dict:
 
5613
                self.outf.write('Views defined:\n')
 
5614
                for view in sorted(view_dict):
 
5615
                    if view == current_view:
 
5616
                        active = "=>"
 
5617
                    else:
 
5618
                        active = "  "
 
5619
                    view_str = views.view_display_str(view_dict[view])
 
5620
                    self.outf.write('%s %-20s %s\n' % (active, view, view_str))
 
5621
            else:
 
5622
                self.outf.write('No views defined.\n')
 
5623
        elif file_list:
 
5624
            if name is None:
 
5625
                # No name given and no current view set
 
5626
                name = 'my'
 
5627
            elif name == 'off':
 
5628
                raise errors.BzrCommandError(
 
5629
                    "Cannot change the 'off' pseudo view")
 
5630
            tree.views.set_view(name, sorted(file_list))
 
5631
            view_str = views.view_display_str(tree.views.lookup_view())
 
5632
            self.outf.write("Using '%s' view: %s\n" % (name, view_str))
 
5633
        else:
 
5634
            # list the files
 
5635
            if name is None:
 
5636
                # No name given and no current view set
 
5637
                self.outf.write('No current view.\n')
 
5638
            else:
 
5639
                view_str = views.view_display_str(tree.views.lookup_view(name))
 
5640
                self.outf.write("'%s' view is: %s\n" % (name, view_str))
 
5641
 
4935
5642
 
4936
5643
class cmd_hooks(Command):
4937
 
    """Show a branch's currently registered hooks.
4938
 
    """
 
5644
    """Show hooks."""
4939
5645
 
4940
5646
    hidden = True
4941
 
    takes_args = ['path?']
4942
5647
 
4943
 
    def run(self, path=None):
4944
 
        if path is None:
4945
 
            path = '.'
4946
 
        branch_hooks = Branch.open(path).hooks
4947
 
        for hook_type in branch_hooks:
4948
 
            hooks = branch_hooks[hook_type]
4949
 
            self.outf.write("%s:\n" % (hook_type,))
4950
 
            if hooks:
4951
 
                for hook in hooks:
4952
 
                    self.outf.write("  %s\n" %
4953
 
                                    (branch_hooks.get_hook_name(hook),))
4954
 
            else:
4955
 
                self.outf.write("  <no hooks installed>\n")
 
5648
    def run(self):
 
5649
        for hook_key in sorted(hooks.known_hooks.keys()):
 
5650
            some_hooks = hooks.known_hooks_key_to_object(hook_key)
 
5651
            self.outf.write("%s:\n" % type(some_hooks).__name__)
 
5652
            for hook_name, hook_point in sorted(some_hooks.items()):
 
5653
                self.outf.write("  %s:\n" % (hook_name,))
 
5654
                found_hooks = list(hook_point)
 
5655
                if found_hooks:
 
5656
                    for hook in found_hooks:
 
5657
                        self.outf.write("    %s\n" %
 
5658
                                        (some_hooks.get_hook_name(hook),))
 
5659
                else:
 
5660
                    self.outf.write("    <no hooks installed>\n")
4956
5661
 
4957
5662
 
4958
5663
class cmd_shelve(Command):
4960
5665
 
4961
5666
    Shelve allows you to temporarily put changes you've made "on the shelf",
4962
5667
    ie. out of the way, until a later time when you can bring them back from
4963
 
    the shelf with the 'unshelve' command.
 
5668
    the shelf with the 'unshelve' command.  The changes are stored alongside
 
5669
    your working tree, and so they aren't propagated along with your branch nor
 
5670
    will they survive its deletion.
4964
5671
 
4965
5672
    If shelve --list is specified, previously-shelved changes are listed.
4966
5673
 
4989
5696
                       value_switches=True, enum_switch=False),
4990
5697
 
4991
5698
        Option('list', help='List shelved changes.'),
 
5699
        Option('destroy',
 
5700
               help='Destroy removed changes instead of shelving them.'),
4992
5701
    ]
4993
5702
    _see_also = ['unshelve']
4994
5703
 
4995
5704
    def run(self, revision=None, all=False, file_list=None, message=None,
4996
 
            writer=None, list=False):
 
5705
            writer=None, list=False, destroy=False):
4997
5706
        if list:
4998
5707
            return self.run_for_list()
4999
5708
        from bzrlib.shelf_ui import Shelver
5000
5709
        if writer is None:
5001
5710
            writer = bzrlib.option.diff_writer_registry.get()
5002
5711
        try:
5003
 
            Shelver.from_args(writer(sys.stdout), revision, all, file_list,
5004
 
                              message).run()
 
5712
            shelver = Shelver.from_args(writer(sys.stdout), revision, all,
 
5713
                file_list, message, destroy=destroy)
 
5714
            try:
 
5715
                shelver.run()
 
5716
            finally:
 
5717
                shelver.finalize()
5005
5718
        except errors.UserAbort:
5006
5719
            return 0
5007
5720
 
5008
5721
    def run_for_list(self):
5009
5722
        tree = WorkingTree.open_containing('.')[0]
5010
5723
        tree.lock_read()
5011
 
        try:
5012
 
            manager = tree.get_shelf_manager()
5013
 
            shelves = manager.active_shelves()
5014
 
            if len(shelves) == 0:
5015
 
                note('No shelved changes.')
5016
 
                return 0
5017
 
            for shelf_id in reversed(shelves):
5018
 
                message = manager.get_metadata(shelf_id).get('message')
5019
 
                if message is None:
5020
 
                    message = '<no message>'
5021
 
                self.outf.write('%3d: %s\n' % (shelf_id, message))
5022
 
            return 1
5023
 
        finally:
5024
 
            tree.unlock()
 
5724
        self.add_cleanup(tree.unlock)
 
5725
        manager = tree.get_shelf_manager()
 
5726
        shelves = manager.active_shelves()
 
5727
        if len(shelves) == 0:
 
5728
            note('No shelved changes.')
 
5729
            return 0
 
5730
        for shelf_id in reversed(shelves):
 
5731
            message = manager.get_metadata(shelf_id).get('message')
 
5732
            if message is None:
 
5733
                message = '<no message>'
 
5734
            self.outf.write('%3d: %s\n' % (shelf_id, message))
 
5735
        return 1
5025
5736
 
5026
5737
 
5027
5738
class cmd_unshelve(Command):
5028
5739
    """Restore shelved changes.
5029
5740
 
5030
5741
    By default, the most recently shelved changes are restored. However if you
5031
 
    specify a patch by name those changes will be restored instead.  This
5032
 
    works best when the changes don't depend on each other.
 
5742
    specify a shelf by id those changes will be restored instead.  This works
 
5743
    best when the changes don't depend on each other.
5033
5744
    """
5034
5745
 
5035
5746
    takes_args = ['shelf_id?']
5039
5750
            enum_switch=False, value_switches=True,
5040
5751
            apply="Apply changes and remove from the shelf.",
5041
5752
            dry_run="Show changes, but do not apply or remove them.",
5042
 
            delete_only="Delete changes without applying them."
 
5753
            delete_only="Delete changes without applying them.",
 
5754
            keep="Apply changes but don't delete them.",
5043
5755
        )
5044
5756
    ]
5045
5757
    _see_also = ['shelve']
5046
5758
 
5047
5759
    def run(self, shelf_id=None, action='apply'):
5048
5760
        from bzrlib.shelf_ui import Unshelver
5049
 
        Unshelver.from_args(shelf_id, action).run()
5050
 
 
5051
 
 
5052
 
def _create_prefix(cur_transport):
5053
 
    needed = [cur_transport]
5054
 
    # Recurse upwards until we can create a directory successfully
5055
 
    while True:
5056
 
        new_transport = cur_transport.clone('..')
5057
 
        if new_transport.base == cur_transport.base:
5058
 
            raise errors.BzrCommandError(
5059
 
                "Failed to create path prefix for %s."
5060
 
                % cur_transport.base)
 
5761
        unshelver = Unshelver.from_args(shelf_id, action)
5061
5762
        try:
5062
 
            new_transport.mkdir('.')
5063
 
        except errors.NoSuchFile:
5064
 
            needed.append(new_transport)
5065
 
            cur_transport = new_transport
 
5763
            unshelver.run()
 
5764
        finally:
 
5765
            unshelver.tree.unlock()
 
5766
 
 
5767
 
 
5768
class cmd_clean_tree(Command):
 
5769
    """Remove unwanted files from working tree.
 
5770
 
 
5771
    By default, only unknown files, not ignored files, are deleted.  Versioned
 
5772
    files are never deleted.
 
5773
 
 
5774
    Another class is 'detritus', which includes files emitted by bzr during
 
5775
    normal operations and selftests.  (The value of these files decreases with
 
5776
    time.)
 
5777
 
 
5778
    If no options are specified, unknown files are deleted.  Otherwise, option
 
5779
    flags are respected, and may be combined.
 
5780
 
 
5781
    To check what clean-tree will do, use --dry-run.
 
5782
    """
 
5783
    takes_options = [Option('ignored', help='Delete all ignored files.'),
 
5784
                     Option('detritus', help='Delete conflict files, merge'
 
5785
                            ' backups, and failed selftest dirs.'),
 
5786
                     Option('unknown',
 
5787
                            help='Delete files unknown to bzr (default).'),
 
5788
                     Option('dry-run', help='Show files to delete instead of'
 
5789
                            ' deleting them.'),
 
5790
                     Option('force', help='Do not prompt before deleting.')]
 
5791
    def run(self, unknown=False, ignored=False, detritus=False, dry_run=False,
 
5792
            force=False):
 
5793
        from bzrlib.clean_tree import clean_tree
 
5794
        if not (unknown or ignored or detritus):
 
5795
            unknown = True
 
5796
        if dry_run:
 
5797
            force = True
 
5798
        clean_tree('.', unknown=unknown, ignored=ignored, detritus=detritus,
 
5799
                   dry_run=dry_run, no_prompt=force)
 
5800
 
 
5801
 
 
5802
class cmd_reference(Command):
 
5803
    """list, view and set branch locations for nested trees.
 
5804
 
 
5805
    If no arguments are provided, lists the branch locations for nested trees.
 
5806
    If one argument is provided, display the branch location for that tree.
 
5807
    If two arguments are provided, set the branch location for that tree.
 
5808
    """
 
5809
 
 
5810
    hidden = True
 
5811
 
 
5812
    takes_args = ['path?', 'location?']
 
5813
 
 
5814
    def run(self, path=None, location=None):
 
5815
        branchdir = '.'
 
5816
        if path is not None:
 
5817
            branchdir = path
 
5818
        tree, branch, relpath =(
 
5819
            bzrdir.BzrDir.open_containing_tree_or_branch(branchdir))
 
5820
        if path is not None:
 
5821
            path = relpath
 
5822
        if tree is None:
 
5823
            tree = branch.basis_tree()
 
5824
        if path is None:
 
5825
            info = branch._get_all_reference_info().iteritems()
 
5826
            self._display_reference_info(tree, branch, info)
5066
5827
        else:
5067
 
            break
5068
 
    # Now we only need to create child directories
5069
 
    while needed:
5070
 
        cur_transport = needed.pop()
5071
 
        cur_transport.ensure_base()
 
5828
            file_id = tree.path2id(path)
 
5829
            if file_id is None:
 
5830
                raise errors.NotVersionedError(path)
 
5831
            if location is None:
 
5832
                info = [(file_id, branch.get_reference_info(file_id))]
 
5833
                self._display_reference_info(tree, branch, info)
 
5834
            else:
 
5835
                branch.set_reference_info(file_id, path, location)
 
5836
 
 
5837
    def _display_reference_info(self, tree, branch, info):
 
5838
        ref_list = []
 
5839
        for file_id, (path, location) in info:
 
5840
            try:
 
5841
                path = tree.id2path(file_id)
 
5842
            except errors.NoSuchId:
 
5843
                pass
 
5844
            ref_list.append((path, location))
 
5845
        for path, location in sorted(ref_list):
 
5846
            self.outf.write('%s %s\n' % (path, location))
5072
5847
 
5073
5848
 
5074
5849
# these get imported and then picked up by the scan for cmd_*
5075
5850
# TODO: Some more consistent way to split command definitions across files;
5076
 
# we do need to load at least some information about them to know of 
 
5851
# we do need to load at least some information about them to know of
5077
5852
# aliases.  ideally we would avoid loading the implementation until the
5078
5853
# details were needed.
5079
5854
from bzrlib.cmd_version_info import cmd_version_info
5081
5856
from bzrlib.bundle.commands import (
5082
5857
    cmd_bundle_info,
5083
5858
    )
 
5859
from bzrlib.foreign import cmd_dpush
5084
5860
from bzrlib.sign_my_commits import cmd_sign_my_commits
5085
5861
from bzrlib.weave_commands import cmd_versionedfile_list, \
5086
5862
        cmd_weave_plan_merge, cmd_weave_merge_text