~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/builtins.py

  • Committer: Canonical.com Patch Queue Manager
  • Date: 2009-04-09 20:23:07 UTC
  • mfrom: (4265.1.4 bbc-merge)
  • Revision ID: pqm@pqm.ubuntu.com-20090409202307-n0depb16qepoe21o
(jam) Change _fetch_uses_deltas = False for CHK repos until we can
        write a better fix.

Show diffs side-by-side

added added

removed removed

Lines of Context:
45
45
    revision as _mod_revision,
46
46
    symbol_versioning,
47
47
    transport,
 
48
    tree as _mod_tree,
48
49
    ui,
49
50
    urlutils,
50
51
    views,
78
79
 
79
80
 
80
81
def tree_files_for_add(file_list):
81
 
    """
82
 
    Return a tree and list of absolute paths from a file list.
83
 
 
84
 
    Similar to tree_files, but add handles files a bit differently, so it a
85
 
    custom implementation.  In particular, MutableTreeTree.smart_add expects
86
 
    absolute paths, which it immediately converts to relative paths.
87
 
    """
88
 
    # FIXME Would be nice to just return the relative paths like
89
 
    # internal_tree_files does, but there are a large number of unit tests
90
 
    # that assume the current interface to mutabletree.smart_add
 
82
    """Add handles files a bit differently so it a custom implementation."""
91
83
    if file_list:
92
 
        tree, relpath = WorkingTree.open_containing(file_list[0])
 
84
        tree = WorkingTree.open_containing(file_list[0])[0]
93
85
        if tree.supports_views():
94
86
            view_files = tree.views.lookup_view()
95
87
            if view_files:
96
88
                for filename in file_list:
97
89
                    if not osutils.is_inside_any(view_files, filename):
98
90
                        raise errors.FileOutsideView(filename, view_files)
99
 
        file_list = file_list[:]
100
 
        file_list[0] = tree.abspath(relpath)
101
91
    else:
102
92
        tree = WorkingTree.open_containing(u'.')[0]
103
93
        if tree.supports_views():
449
439
        except errors.NoWorkingTree:
450
440
            raise errors.BzrCommandError("No working tree to remove")
451
441
        except errors.NotLocalUrl:
452
 
            raise errors.BzrCommandError("You cannot remove the working tree"
453
 
                                         " of a remote path")
 
442
            raise errors.BzrCommandError("You cannot remove the working tree of a "
 
443
                                         "remote path")
454
444
        if not force:
455
 
            # XXX: What about pending merges ? -- vila 20090629
456
 
            if working.has_changes(working.basis_tree()):
 
445
            changes = working.changes_from(working.basis_tree())
 
446
            if changes.has_changed():
457
447
                raise errors.UncommittedChanges(working)
458
448
 
459
449
        working_path = working.bzrdir.root_transport.base
460
450
        branch_path = working.branch.bzrdir.root_transport.base
461
451
        if working_path != branch_path:
462
 
            raise errors.BzrCommandError("You cannot remove the working tree"
463
 
                                         " from a lightweight checkout")
 
452
            raise errors.BzrCommandError("You cannot remove the working tree from "
 
453
                                         "a lightweight checkout")
464
454
 
465
455
        d.destroy_workingtree()
466
456
 
473
463
 
474
464
    _see_also = ['info']
475
465
    takes_args = ['location?']
476
 
    takes_options = [
477
 
        Option('tree', help='Show revno of working tree'),
478
 
        ]
479
466
 
480
467
    @display_command
481
 
    def run(self, tree=False, location=u'.'):
482
 
        if tree:
483
 
            try:
484
 
                wt = WorkingTree.open_containing(location)[0]
485
 
                wt.lock_read()
486
 
            except (errors.NoWorkingTree, errors.NotLocalUrl):
487
 
                raise errors.NoWorkingTree(location)
488
 
            try:
489
 
                revid = wt.last_revision()
490
 
                try:
491
 
                    revno_t = wt.branch.revision_id_to_dotted_revno(revid)
492
 
                except errors.NoSuchRevision:
493
 
                    revno_t = ('???',)
494
 
                revno = ".".join(str(n) for n in revno_t)
495
 
            finally:
496
 
                wt.unlock()
497
 
        else:
498
 
            b = Branch.open_containing(location)[0]
499
 
            b.lock_read()
500
 
            try:
501
 
                revno = b.revno()
502
 
            finally:
503
 
                b.unlock()
504
 
 
505
 
        self.outf.write(str(revno) + '\n')
 
468
    def run(self, location=u'.'):
 
469
        self.outf.write(str(Branch.open_containing(location)[0].revno()))
 
470
        self.outf.write('\n')
506
471
 
507
472
 
508
473
class cmd_revision_info(Command):
518
483
            short_name='d',
519
484
            type=unicode,
520
485
            ),
521
 
        Option('tree', help='Show revno of working tree'),
522
486
        ]
523
487
 
524
488
    @display_command
525
 
    def run(self, revision=None, directory=u'.', tree=False,
526
 
            revision_info_list=[]):
527
 
 
528
 
        try:
529
 
            wt = WorkingTree.open_containing(directory)[0]
530
 
            b = wt.branch
531
 
            wt.lock_read()
532
 
        except (errors.NoWorkingTree, errors.NotLocalUrl):
533
 
            wt = None
534
 
            b = Branch.open_containing(directory)[0]
535
 
            b.lock_read()
536
 
        try:
537
 
            revision_ids = []
538
 
            if revision is not None:
539
 
                revision_ids.extend(rev.as_revision_id(b) for rev in revision)
540
 
            if revision_info_list is not None:
541
 
                for rev_str in revision_info_list:
542
 
                    rev_spec = RevisionSpec.from_string(rev_str)
543
 
                    revision_ids.append(rev_spec.as_revision_id(b))
544
 
            # No arguments supplied, default to the last revision
545
 
            if len(revision_ids) == 0:
546
 
                if tree:
547
 
                    if wt is None:
548
 
                        raise errors.NoWorkingTree(directory)
549
 
                    revision_ids.append(wt.last_revision())
550
 
                else:
551
 
                    revision_ids.append(b.last_revision())
552
 
 
553
 
            revinfos = []
554
 
            maxlen = 0
555
 
            for revision_id in revision_ids:
556
 
                try:
557
 
                    dotted_revno = b.revision_id_to_dotted_revno(revision_id)
558
 
                    revno = '.'.join(str(i) for i in dotted_revno)
559
 
                except errors.NoSuchRevision:
560
 
                    revno = '???'
561
 
                maxlen = max(maxlen, len(revno))
562
 
                revinfos.append([revno, revision_id])
563
 
        finally:
564
 
            if wt is None:
565
 
                b.unlock()
566
 
            else:
567
 
                wt.unlock()
568
 
 
569
 
        for ri in revinfos:
570
 
            self.outf.write('%*s %s\n' % (maxlen, ri[0], ri[1]))
 
489
    def run(self, revision=None, directory=u'.', revision_info_list=[]):
 
490
 
 
491
        revs = []
 
492
        if revision is not None:
 
493
            revs.extend(revision)
 
494
        if revision_info_list is not None:
 
495
            for rev in revision_info_list:
 
496
                revs.append(RevisionSpec.from_string(rev))
 
497
 
 
498
        b = Branch.open_containing(directory)[0]
 
499
 
 
500
        if len(revs) == 0:
 
501
            revs.append(RevisionSpec.from_string('-1'))
 
502
 
 
503
        for rev in revs:
 
504
            revision_id = rev.as_revision_id(b)
 
505
            try:
 
506
                revno = '%4d' % (b.revision_id_to_revno(revision_id))
 
507
            except errors.NoSuchRevision:
 
508
                dotted_map = b.get_revision_id_to_revno_map()
 
509
                revno = '.'.join(str(i) for i in dotted_map[revision_id])
 
510
            print '%s %s' % (revno, revision_id)
571
511
 
572
512
 
573
513
class cmd_add(Command):
603
543
    branches that will be merged later (without showing the two different
604
544
    adds as a conflict). It is also useful when merging another project
605
545
    into a subdirectory of this one.
606
 
    
607
 
    Any files matching patterns in the ignore list will not be added
608
 
    unless they are explicitly mentioned.
609
546
    """
610
547
    takes_args = ['file*']
611
548
    takes_options = [
619
556
               help='Lookup file ids from this tree.'),
620
557
        ]
621
558
    encoding_type = 'replace'
622
 
    _see_also = ['remove', 'ignore']
 
559
    _see_also = ['remove']
623
560
 
624
561
    def run(self, file_list, no_recurse=False, dry_run=False, verbose=False,
625
562
            file_ids_from=None):
657
594
                    for path in ignored[glob]:
658
595
                        self.outf.write("ignored %s matching \"%s\"\n"
659
596
                                        % (path, glob))
 
597
            else:
 
598
                match_len = 0
 
599
                for glob, paths in ignored.items():
 
600
                    match_len += len(paths)
 
601
                self.outf.write("ignored %d file(s).\n" % match_len)
 
602
            self.outf.write("If you wish to add some of these files,"
 
603
                            " please add them by name.\n")
660
604
 
661
605
 
662
606
class cmd_mkdir(Command):
794
738
        if len(names_list) < 2:
795
739
            raise errors.BzrCommandError("missing file argument")
796
740
        tree, rel_names = tree_files(names_list, canonicalize=False)
797
 
        tree.lock_tree_write()
 
741
        tree.lock_write()
798
742
        try:
799
743
            self._run(tree, names_list, rel_names, after)
800
744
        finally:
808
752
            raise errors.BzrCommandError('--after cannot be specified with'
809
753
                                         ' --auto.')
810
754
        work_tree, file_list = tree_files(names_list, default_branch='.')
811
 
        work_tree.lock_tree_write()
 
755
        work_tree.lock_write()
812
756
        try:
813
757
            rename_map.RenameMap.guess_renames(work_tree, dry_run)
814
758
        finally:
927
871
            short_name='d',
928
872
            type=unicode,
929
873
            ),
930
 
        Option('local',
931
 
            help="Perform a local pull in a bound "
932
 
                 "branch.  Local pulls are not applied to "
933
 
                 "the master branch."
934
 
            ),
935
874
        ]
936
875
    takes_args = ['location?']
937
876
    encoding_type = 'replace'
938
877
 
939
878
    def run(self, location=None, remember=False, overwrite=False,
940
879
            revision=None, verbose=False,
941
 
            directory=None, local=False):
 
880
            directory=None):
942
881
        # FIXME: too much stuff is in the command class
943
882
        revision_id = None
944
883
        mergeable = None
950
889
        except errors.NoWorkingTree:
951
890
            tree_to = None
952
891
            branch_to = Branch.open_containing(directory)[0]
953
 
        
954
 
        if local and not branch_to.get_bound_location():
955
 
            raise errors.LocalRequiresBoundBranch()
956
892
 
957
893
        possible_transports = []
958
894
        if location is not None:
990
926
            if branch_to.get_parent() is None or remember:
991
927
                branch_to.set_parent(branch_from.base)
992
928
 
993
 
        if branch_from is not branch_to:
994
 
            branch_from.lock_read()
 
929
        if revision is not None:
 
930
            revision_id = revision.as_revision_id(branch_from)
 
931
 
 
932
        branch_to.lock_write()
995
933
        try:
996
 
            if revision is not None:
997
 
                revision_id = revision.as_revision_id(branch_from)
998
 
 
999
 
            branch_to.lock_write()
1000
 
            try:
1001
 
                if tree_to is not None:
1002
 
                    view_info = _get_view_info_for_change_reporter(tree_to)
1003
 
                    change_reporter = delta._ChangeReporter(
1004
 
                        unversioned_filter=tree_to.is_ignored,
1005
 
                        view_info=view_info)
1006
 
                    result = tree_to.pull(
1007
 
                        branch_from, overwrite, revision_id, change_reporter,
1008
 
                        possible_transports=possible_transports, local=local)
1009
 
                else:
1010
 
                    result = branch_to.pull(
1011
 
                        branch_from, overwrite, revision_id, local=local)
1012
 
 
1013
 
                result.report(self.outf)
1014
 
                if verbose and result.old_revid != result.new_revid:
1015
 
                    log.show_branch_change(
1016
 
                        branch_to, self.outf, result.old_revno,
1017
 
                        result.old_revid)
1018
 
            finally:
1019
 
                branch_to.unlock()
 
934
            if tree_to is not None:
 
935
                view_info = _get_view_info_for_change_reporter(tree_to)
 
936
                change_reporter = delta._ChangeReporter(
 
937
                    unversioned_filter=tree_to.is_ignored, view_info=view_info)
 
938
                result = tree_to.pull(branch_from, overwrite, revision_id,
 
939
                                      change_reporter,
 
940
                                      possible_transports=possible_transports)
 
941
            else:
 
942
                result = branch_to.pull(branch_from, overwrite, revision_id)
 
943
 
 
944
            result.report(self.outf)
 
945
            if verbose and result.old_revid != result.new_revid:
 
946
                log.show_branch_change(branch_to, self.outf, result.old_revno,
 
947
                                       result.old_revid)
1020
948
        finally:
1021
 
            if branch_from is not branch_to:
1022
 
                branch_from.unlock()
 
949
            branch_to.unlock()
1023
950
 
1024
951
 
1025
952
class cmd_push(Command):
1072
999
                'for the commit history. Only the work not present in the '
1073
1000
                'referenced branch is included in the branch created.',
1074
1001
            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.'),
1078
1002
        ]
1079
1003
    takes_args = ['location?']
1080
1004
    encoding_type = 'replace'
1082
1006
    def run(self, location=None, remember=False, overwrite=False,
1083
1007
        create_prefix=False, verbose=False, revision=None,
1084
1008
        use_existing_dir=False, directory=None, stacked_on=None,
1085
 
        stacked=False, strict=None):
 
1009
        stacked=False):
1086
1010
        from bzrlib.push import _show_push_branch
1087
1011
 
 
1012
        # Get the source branch and revision_id
1088
1013
        if directory is None:
1089
1014
            directory = '.'
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
 
1015
        br_from = Branch.open_containing(directory)[0]
1097
1016
        revision = _get_one_revision('push', revision)
1098
1017
        if revision is not None:
1099
1018
            revision_id = revision.in_history(br_from).rev_id
1100
1019
        else:
1101
 
            revision_id = None
1102
 
        if strict and tree is not None and revision_id is None:
1103
 
            if (tree.has_changes(tree.basis_tree())
1104
 
                or len(tree.get_parent_ids()) > 1):
1105
 
                raise errors.UncommittedChanges(
1106
 
                    tree, more='Use --no-strict to force the push.')
1107
 
            if tree.last_revision() != tree.branch.last_revision():
1108
 
                # The tree has lost sync with its branch, there is little
1109
 
                # chance that the user is aware of it but he can still force
1110
 
                # the push with --no-strict
1111
 
                raise errors.OutOfDateTree(
1112
 
                    tree, more='Use --no-strict to force the push.')
 
1020
            revision_id = br_from.last_revision()
1113
1021
 
1114
1022
        # Get the stacked_on branch, if any
1115
1023
        if stacked_on is not None:
1148
1056
 
1149
1057
 
1150
1058
class cmd_branch(Command):
1151
 
    """Create a new branch that is a copy of an existing branch.
 
1059
    """Create a new copy of a branch.
1152
1060
 
1153
1061
    If the TO_LOCATION is omitted, the last component of the FROM_LOCATION will
1154
1062
    be used.  In other words, "branch ../foo/bar" will attempt to create ./bar.
1173
1081
                'branch for all operations.'),
1174
1082
        Option('standalone',
1175
1083
               help='Do not use a shared repository, even if available.'),
1176
 
        Option('use-existing-dir',
1177
 
               help='By default branch will fail if the target'
1178
 
                    ' directory exists, but does not already'
1179
 
                    ' have a control directory.  This flag will'
1180
 
                    ' allow branch to proceed.'),
1181
1084
        ]
1182
1085
    aliases = ['get', 'clone']
1183
1086
 
1184
1087
    def run(self, from_location, to_location=None, revision=None,
1185
 
            hardlink=False, stacked=False, standalone=False, no_tree=False,
1186
 
            use_existing_dir=False):
 
1088
            hardlink=False, stacked=False, standalone=False, no_tree=False):
1187
1089
        from bzrlib.tag import _merge_tags_if_possible
1188
1090
 
1189
1091
        accelerator_tree, br_from = bzrdir.BzrDir.open_tree_or_branch(
1190
1092
            from_location)
1191
 
        if (accelerator_tree is not None and
1192
 
            accelerator_tree.supports_content_filtering()):
1193
 
            accelerator_tree = None
1194
1093
        revision = _get_one_revision('branch', revision)
1195
1094
        br_from.lock_read()
1196
1095
        try:
1207
1106
            try:
1208
1107
                to_transport.mkdir('.')
1209
1108
            except errors.FileExists:
1210
 
                if not use_existing_dir:
1211
 
                    raise errors.BzrCommandError('Target directory "%s" '
1212
 
                        'already exists.' % to_location)
1213
 
                else:
1214
 
                    try:
1215
 
                        bzrdir.BzrDir.open_from_transport(to_transport)
1216
 
                    except errors.NotBranchError:
1217
 
                        pass
1218
 
                    else:
1219
 
                        raise errors.AlreadyBranchError(to_location)
 
1109
                raise errors.BzrCommandError('Target directory "%s" already'
 
1110
                                             ' exists.' % to_location)
1220
1111
            except errors.NoSuchFile:
1221
1112
                raise errors.BzrCommandError('Parent of "%s" does not exist.'
1222
1113
                                             % to_location)
1467
1358
            title='Deletion Strategy', value_switches=True, enum_switch=False,
1468
1359
            safe='Only delete files if they can be'
1469
1360
                 ' safely recovered (default).',
1470
 
            keep='Delete from bzr but leave the working copy.',
 
1361
            keep="Don't delete any files.",
1471
1362
            force='Delete all the specified files, even if they can not be '
1472
1363
                'recovered and even if they are non-empty directories.')]
1473
1364
    aliases = ['rm', 'del']
1684
1575
                    "\nYou may supply --create-prefix to create all"
1685
1576
                    " leading parent directories."
1686
1577
                    % location)
1687
 
            to_transport.create_prefix()
 
1578
            _create_prefix(to_transport)
1688
1579
 
1689
1580
        try:
1690
1581
            a_bzrdir = bzrdir.BzrDir.open_from_transport(to_transport)
1708
1599
                branch.set_append_revisions_only(True)
1709
1600
            except errors.UpgradeRequired:
1710
1601
                raise errors.BzrCommandError('This branch format cannot be set'
1711
 
                    ' to append-revisions-only.  Try --default.')
 
1602
                    ' to append-revisions-only.  Try --experimental-branch6')
1712
1603
        if not is_quiet():
1713
1604
            from bzrlib.info import describe_layout, describe_format
1714
1605
            try:
2177
2068
 
2178
2069
      When exploring non-mainline history on large projects with deep
2179
2070
      history, the performance of log can be greatly improved by installing
2180
 
      the historycache plugin. This plugin buffers historical information
 
2071
      the revnocache plugin. This plugin buffers historical information
2181
2072
      trading disk space for faster speed.
2182
2073
    """
2183
2074
    takes_args = ['file*']
2214
2105
            Option('show-diff',
2215
2106
                   short_name='p',
2216
2107
                   help='Show changes made in each revision as a patch.'),
2217
 
            Option('include-merges',
2218
 
                   help='Show merged revisions like --levels 0 does.'),
2219
2108
            ]
2220
2109
    encoding_type = 'replace'
2221
2110
 
2230
2119
            levels=None,
2231
2120
            message=None,
2232
2121
            limit=None,
2233
 
            show_diff=False,
2234
 
            include_merges=False):
 
2122
            show_diff=False):
2235
2123
        from bzrlib.log import (
2236
2124
            Logger,
2237
2125
            make_log_request_dict,
2238
2126
            _get_info_for_log_files,
2239
2127
            )
2240
2128
        direction = (forward and 'forward') or 'reverse'
2241
 
        if include_merges:
2242
 
            if levels is None:
2243
 
                levels = 0
2244
 
            else:
2245
 
                raise errors.BzrCommandError(
2246
 
                    '--levels and --include-merges are mutually exclusive')
2247
2129
 
2248
2130
        if change is not None:
2249
2131
            if len(change) > 1:
2306
2188
            lf = log_format(show_ids=show_ids, to_file=self.outf,
2307
2189
                            show_timezone=timezone,
2308
2190
                            delta_format=get_verbosity_level(),
2309
 
                            levels=levels,
2310
 
                            show_advice=levels is None)
 
2191
                            levels=levels)
2311
2192
 
2312
2193
            # Choose the algorithm for doing the logging. It's annoying
2313
2194
            # having multiple code paths like this but necessary until
2453
2334
 
2454
2335
        if path is None:
2455
2336
            fs_path = '.'
 
2337
            prefix = ''
2456
2338
        else:
2457
2339
            if from_root:
2458
2340
                raise errors.BzrCommandError('cannot specify both --from-root'
2459
2341
                                             ' and PATH')
2460
2342
            fs_path = path
 
2343
            prefix = path
2461
2344
        tree, branch, relpath = bzrdir.BzrDir.open_containing_tree_or_branch(
2462
2345
            fs_path)
2463
 
 
2464
 
        # Calculate the prefix to use
2465
 
        prefix = None
2466
2346
        if from_root:
2467
 
            if relpath:
2468
 
                prefix = relpath + '/'
2469
 
        elif fs_path != '.':
2470
 
            prefix = fs_path + '/'
2471
 
 
 
2347
            relpath = u''
 
2348
        elif relpath:
 
2349
            relpath += '/'
2472
2350
        if revision is not None or tree is None:
2473
2351
            tree = _get_one_revision_tree('ls', revision, branch=branch)
2474
2352
 
2482
2360
 
2483
2361
        tree.lock_read()
2484
2362
        try:
2485
 
            for fp, fc, fkind, fid, entry in tree.list_files(include_root=False,
2486
 
                from_dir=relpath, recursive=recursive):
2487
 
                # Apply additional masking
2488
 
                if not all and not selection[fc]:
2489
 
                    continue
2490
 
                if kind is not None and fkind != kind:
2491
 
                    continue
2492
 
                if apply_view:
2493
 
                    try:
2494
 
                        if relpath:
2495
 
                            fullpath = osutils.pathjoin(relpath, fp)
2496
 
                        else:
2497
 
                            fullpath = fp
2498
 
                        views.check_path_in_view(tree, fullpath)
2499
 
                    except errors.FileOutsideView:
2500
 
                        continue
2501
 
 
2502
 
                # Output the entry
2503
 
                if prefix:
2504
 
                    fp = osutils.pathjoin(prefix, fp)
2505
 
                kindch = entry.kind_character()
2506
 
                outstring = fp + kindch
2507
 
                ui.ui_factory.clear_term()
2508
 
                if verbose:
2509
 
                    outstring = '%-8s %s' % (fc, outstring)
2510
 
                    if show_ids and fid is not None:
2511
 
                        outstring = "%-50s %s" % (outstring, fid)
2512
 
                    self.outf.write(outstring + '\n')
2513
 
                elif null:
2514
 
                    self.outf.write(fp + '\0')
2515
 
                    if show_ids:
2516
 
                        if fid is not None:
2517
 
                            self.outf.write(fid)
2518
 
                        self.outf.write('\0')
2519
 
                    self.outf.flush()
2520
 
                else:
2521
 
                    if show_ids:
 
2363
            for fp, fc, fkind, fid, entry in tree.list_files(include_root=False):
 
2364
                if fp.startswith(relpath):
 
2365
                    rp = fp[len(relpath):]
 
2366
                    fp = osutils.pathjoin(prefix, rp)
 
2367
                    if not recursive and '/' in rp:
 
2368
                        continue
 
2369
                    if not all and not selection[fc]:
 
2370
                        continue
 
2371
                    if kind is not None and fkind != kind:
 
2372
                        continue
 
2373
                    if apply_view:
 
2374
                        try:
 
2375
                            views.check_path_in_view(tree, fp)
 
2376
                        except errors.FileOutsideView:
 
2377
                            continue
 
2378
                    kindch = entry.kind_character()
 
2379
                    outstring = fp + kindch
 
2380
                    if verbose:
 
2381
                        outstring = '%-8s %s' % (fc, outstring)
 
2382
                        if show_ids and fid is not None:
 
2383
                            outstring = "%-50s %s" % (outstring, fid)
 
2384
                        self.outf.write(outstring + '\n')
 
2385
                    elif null:
 
2386
                        self.outf.write(fp + '\0')
 
2387
                        if show_ids:
 
2388
                            if fid is not None:
 
2389
                                self.outf.write(fid)
 
2390
                            self.outf.write('\0')
 
2391
                        self.outf.flush()
 
2392
                    else:
2522
2393
                        if fid is not None:
2523
2394
                            my_id = fid
2524
2395
                        else:
2525
2396
                            my_id = ''
2526
 
                        self.outf.write('%-50s %s\n' % (outstring, my_id))
2527
 
                    else:
2528
 
                        self.outf.write(outstring + '\n')
 
2397
                        if show_ids:
 
2398
                            self.outf.write('%-50s %s\n' % (outstring, my_id))
 
2399
                        else:
 
2400
                            self.outf.write(outstring + '\n')
2529
2401
        finally:
2530
2402
            tree.unlock()
2531
2403
 
2824
2696
class cmd_commit(Command):
2825
2697
    """Commit changes into a new revision.
2826
2698
 
2827
 
    An explanatory message needs to be given for each commit. This is
2828
 
    often done by using the --message option (getting the message from the
2829
 
    command line) or by using the --file option (getting the message from
2830
 
    a file). If neither of these options is given, an editor is opened for
2831
 
    the user to enter the message. To see the changed files in the
2832
 
    boilerplate text loaded into the editor, use the --show-diff option.
2833
 
 
2834
 
    By default, the entire tree is committed and the person doing the
2835
 
    commit is assumed to be the author. These defaults can be overridden
2836
 
    as explained below.
2837
 
 
2838
 
    :Selective commits:
2839
 
 
2840
 
      If selected files are specified, only changes to those files are
2841
 
      committed.  If a directory is specified then the directory and
2842
 
      everything within it is committed.
2843
 
  
2844
 
      When excludes are given, they take precedence over selected files.
2845
 
      For example, to commit only changes within foo, but not changes
2846
 
      within foo/bar::
2847
 
  
2848
 
        bzr commit foo -x foo/bar
2849
 
  
2850
 
      A selective commit after a merge is not yet supported.
2851
 
 
2852
 
    :Custom authors:
2853
 
 
2854
 
      If the author of the change is not the same person as the committer,
2855
 
      you can specify the author's name using the --author option. The
2856
 
      name should be in the same format as a committer-id, e.g.
2857
 
      "John Doe <jdoe@example.com>". If there is more than one author of
2858
 
      the change you can specify the option multiple times, once for each
2859
 
      author.
2860
 
  
2861
 
    :Checks:
2862
 
 
2863
 
      A common mistake is to forget to add a new file or directory before
2864
 
      running the commit command. The --strict option checks for unknown
2865
 
      files and aborts the commit if any are found. More advanced pre-commit
2866
 
      checks can be implemented by defining hooks. See ``bzr help hooks``
2867
 
      for details.
2868
 
 
2869
 
    :Things to note:
2870
 
 
2871
 
      If you accidentially commit the wrong changes or make a spelling
2872
 
      mistake in the commit message say, you can use the uncommit command
2873
 
      to undo it. See ``bzr help uncommit`` for details.
2874
 
 
2875
 
      Hooks can also be configured to run after a commit. This allows you
2876
 
      to trigger updates to external systems like bug trackers. The --fixes
2877
 
      option can be used to record the association between a revision and
2878
 
      one or more bugs. See ``bzr help bugs`` for details.
2879
 
 
2880
 
      A selective commit may fail in some cases where the committed
2881
 
      tree would be invalid. Consider::
2882
 
  
2883
 
        bzr init foo
2884
 
        mkdir foo/bar
2885
 
        bzr add foo/bar
2886
 
        bzr commit foo -m "committing foo"
2887
 
        bzr mv foo/bar foo/baz
2888
 
        mkdir foo/bar
2889
 
        bzr add foo/bar
2890
 
        bzr commit foo/bar -m "committing bar but not baz"
2891
 
  
2892
 
      In the example above, the last commit will fail by design. This gives
2893
 
      the user the opportunity to decide whether they want to commit the
2894
 
      rename at the same time, separately first, or not at all. (As a general
2895
 
      rule, when in doubt, Bazaar has a policy of Doing the Safe Thing.)
 
2699
    If no arguments are given, the entire tree is committed.
 
2700
 
 
2701
    If selected files are specified, only changes to those files are
 
2702
    committed.  If a directory is specified then the directory and everything
 
2703
    within it is committed.
 
2704
 
 
2705
    When excludes are given, they take precedence over selected files.
 
2706
    For example, too commit only changes within foo, but not changes within
 
2707
    foo/bar::
 
2708
 
 
2709
      bzr commit foo -x foo/bar
 
2710
 
 
2711
    If author of the change is not the same person as the committer, you can
 
2712
    specify the author's name using the --author option. The name should be
 
2713
    in the same format as a committer-id, e.g. "John Doe <jdoe@example.com>".
 
2714
    If there is more than one author of the change you can specify the option
 
2715
    multiple times, once for each author.
 
2716
 
 
2717
    A selected-file commit may fail in some cases where the committed
 
2718
    tree would be invalid. Consider::
 
2719
 
 
2720
      bzr init foo
 
2721
      mkdir foo/bar
 
2722
      bzr add foo/bar
 
2723
      bzr commit foo -m "committing foo"
 
2724
      bzr mv foo/bar foo/baz
 
2725
      mkdir foo/bar
 
2726
      bzr add foo/bar
 
2727
      bzr commit foo/bar -m "committing bar but not baz"
 
2728
 
 
2729
    In the example above, the last commit will fail by design. This gives
 
2730
    the user the opportunity to decide whether they want to commit the
 
2731
    rename at the same time, separately first, or not at all. (As a general
 
2732
    rule, when in doubt, Bazaar has a policy of Doing the Safe Thing.)
 
2733
 
 
2734
    Note: A selected-file commit after a merge is not yet supported.
2896
2735
    """
2897
2736
    # TODO: Run hooks on tree to-be-committed, and after commit.
2898
2737
 
2903
2742
 
2904
2743
    # XXX: verbose currently does nothing
2905
2744
 
2906
 
    _see_also = ['add', 'bugs', 'hooks', 'uncommit']
 
2745
    _see_also = ['bugs', 'uncommit']
2907
2746
    takes_args = ['selected*']
2908
2747
    takes_options = [
2909
2748
            ListOption('exclude', type=str, short_name='x',
3030
2869
        except PointlessCommit:
3031
2870
            # FIXME: This should really happen before the file is read in;
3032
2871
            # perhaps prepare the commit; get the message; then actually commit
3033
 
            raise errors.BzrCommandError("No changes to commit."
3034
 
                              " Use --unchanged to commit anyhow.")
 
2872
            raise errors.BzrCommandError("no changes to commit."
 
2873
                              " use --unchanged to commit anyhow")
3035
2874
        except ConflictsInTree:
3036
2875
            raise errors.BzrCommandError('Conflicts detected in working '
3037
2876
                'tree.  Use "bzr conflicts" to list, "bzr resolve FILE" to'
3055
2894
    The working tree and branch checks will only give output if a problem is
3056
2895
    detected. The output fields of the repository check are:
3057
2896
 
3058
 
    revisions
3059
 
        This is just the number of revisions checked.  It doesn't
3060
 
        indicate a problem.
3061
 
 
3062
 
    versionedfiles
3063
 
        This is just the number of versionedfiles checked.  It
3064
 
        doesn't indicate a problem.
3065
 
 
3066
 
    unreferenced ancestors
3067
 
        Texts that are ancestors of other texts, but
3068
 
        are not properly referenced by the revision ancestry.  This is a
3069
 
        subtle problem that Bazaar can work around.
3070
 
 
3071
 
    unique file texts
3072
 
        This is the total number of unique file contents
3073
 
        seen in the checked revisions.  It does not indicate a problem.
3074
 
 
3075
 
    repeated file texts
3076
 
        This is the total number of repeated texts seen
3077
 
        in the checked revisions.  Texts can be repeated when their file
3078
 
        entries are modified, but the file contents are not.  It does not
3079
 
        indicate a problem.
 
2897
        revisions: This is just the number of revisions checked.  It doesn't
 
2898
            indicate a problem.
 
2899
        versionedfiles: This is just the number of versionedfiles checked.  It
 
2900
            doesn't indicate a problem.
 
2901
        unreferenced ancestors: Texts that are ancestors of other texts, but
 
2902
            are not properly referenced by the revision ancestry.  This is a
 
2903
            subtle problem that Bazaar can work around.
 
2904
        unique file texts: This is the total number of unique file contents
 
2905
            seen in the checked revisions.  It does not indicate a problem.
 
2906
        repeated file texts: This is the total number of repeated texts seen
 
2907
            in the checked revisions.  Texts can be repeated when their file
 
2908
            entries are modified, but the file contents are not.  It does not
 
2909
            indicate a problem.
3080
2910
 
3081
2911
    If no restrictions are specified, all Bazaar data that is found at the given
3082
2912
    location will be checked.
3559
3389
    merge refuses to run if there are any uncommitted changes, unless
3560
3390
    --force is given.
3561
3391
 
3562
 
    To select only some changes to merge, use "merge -i", which will prompt
3563
 
    you to apply each diff hunk and file change, similar to "shelve".
3564
 
 
3565
3392
    :Examples:
3566
3393
        To merge the latest revision from bzr.dev::
3567
3394
 
3605
3432
               short_name='d',
3606
3433
               type=unicode,
3607
3434
               ),
3608
 
        Option('preview', help='Instead of merging, show a diff of the'
3609
 
               ' merge.'),
3610
 
        Option('interactive', help='Select changes interactively.',
3611
 
            short_name='i')
 
3435
        Option('preview', help='Instead of merging, show a diff of the merge.')
3612
3436
    ]
3613
3437
 
3614
3438
    def run(self, location=None, revision=None, force=False,
3616
3440
            uncommitted=False, pull=False,
3617
3441
            directory=None,
3618
3442
            preview=False,
3619
 
            interactive=False,
3620
3443
            ):
3621
3444
        if merge_type is None:
3622
3445
            merge_type = _mod_merge.Merge3Merger
3634
3457
        except errors.NoSuchRevision:
3635
3458
            basis_tree = tree.basis_tree()
3636
3459
        if not force:
3637
 
            if tree.has_changes(basis_tree):
 
3460
            changes = tree.changes_from(basis_tree)
 
3461
            if changes.has_changed():
3638
3462
                raise errors.UncommittedChanges(tree)
3639
3463
 
3640
3464
        view_info = _get_view_info_for_change_reporter(tree)
3667
3491
                if revision is not None and len(revision) > 0:
3668
3492
                    raise errors.BzrCommandError('Cannot use --uncommitted and'
3669
3493
                        ' --revision at the same time.')
3670
 
                merger = self.get_merger_from_uncommitted(tree, location, pb,
3671
 
                                                          cleanups)
 
3494
                location = self._select_branch_location(tree, location)[0]
 
3495
                other_tree, other_path = WorkingTree.open_containing(location)
 
3496
                merger = _mod_merge.Merger.from_uncommitted(tree, other_tree,
 
3497
                    pb)
3672
3498
                allow_pending = False
 
3499
                if other_path != '':
 
3500
                    merger.interesting_files = [other_path]
3673
3501
 
3674
3502
            if merger is None:
3675
3503
                merger, allow_pending = self._get_merger_from_branch(tree,
3693
3521
                    return 0
3694
3522
            merger.check_basis(False)
3695
3523
            if preview:
3696
 
                return self._do_preview(merger, cleanups)
3697
 
            elif interactive:
3698
 
                return self._do_interactive(merger, cleanups)
 
3524
                return self._do_preview(merger)
3699
3525
            else:
3700
3526
                return self._do_merge(merger, change_reporter, allow_pending,
3701
3527
                                      verified)
3703
3529
            for cleanup in reversed(cleanups):
3704
3530
                cleanup()
3705
3531
 
3706
 
    def _get_preview(self, merger, cleanups):
 
3532
    def _do_preview(self, merger):
 
3533
        from bzrlib.diff import show_diff_trees
3707
3534
        tree_merger = merger.make_merger()
3708
3535
        tt = tree_merger.make_preview_transform()
3709
 
        cleanups.append(tt.finalize)
3710
 
        result_tree = tt.get_preview_tree()
3711
 
        return result_tree
3712
 
 
3713
 
    def _do_preview(self, merger, cleanups):
3714
 
        from bzrlib.diff import show_diff_trees
3715
 
        result_tree = self._get_preview(merger, cleanups)
3716
 
        show_diff_trees(merger.this_tree, result_tree, self.outf,
3717
 
                        old_label='', new_label='')
 
3536
        try:
 
3537
            result_tree = tt.get_preview_tree()
 
3538
            show_diff_trees(merger.this_tree, result_tree, self.outf,
 
3539
                            old_label='', new_label='')
 
3540
        finally:
 
3541
            tt.finalize()
3718
3542
 
3719
3543
    def _do_merge(self, merger, change_reporter, allow_pending, verified):
3720
3544
        merger.change_reporter = change_reporter
3728
3552
        else:
3729
3553
            return 0
3730
3554
 
3731
 
    def _do_interactive(self, merger, cleanups):
3732
 
        """Perform an interactive merge.
3733
 
 
3734
 
        This works by generating a preview tree of the merge, then using
3735
 
        Shelver to selectively remove the differences between the working tree
3736
 
        and the preview tree.
3737
 
        """
3738
 
        from bzrlib import shelf_ui
3739
 
        result_tree = self._get_preview(merger, cleanups)
3740
 
        writer = bzrlib.option.diff_writer_registry.get()
3741
 
        shelver = shelf_ui.Shelver(merger.this_tree, result_tree, destroy=True,
3742
 
                                   reporter=shelf_ui.ApplyReporter(),
3743
 
                                   diff_writer=writer(sys.stdout))
3744
 
        shelver.run()
3745
 
 
3746
3555
    def sanity_check_merger(self, merger):
3747
3556
        if (merger.show_base and
3748
3557
            not merger.merge_type is _mod_merge.Merge3Merger):
3783
3592
            base_branch, base_path = Branch.open_containing(base_loc,
3784
3593
                possible_transports)
3785
3594
        # Find the revision ids
3786
 
        other_revision_id = None
3787
 
        base_revision_id = None
3788
 
        if revision is not None:
3789
 
            if len(revision) >= 1:
3790
 
                other_revision_id = revision[-1].as_revision_id(other_branch)
3791
 
            if len(revision) == 2:
3792
 
                base_revision_id = revision[0].as_revision_id(base_branch)
3793
 
        if other_revision_id is None:
 
3595
        if revision is None or len(revision) < 1 or revision[-1] is None:
3794
3596
            other_revision_id = _mod_revision.ensure_null(
3795
3597
                other_branch.last_revision())
 
3598
        else:
 
3599
            other_revision_id = revision[-1].as_revision_id(other_branch)
 
3600
        if (revision is not None and len(revision) == 2
 
3601
            and revision[0] is not None):
 
3602
            base_revision_id = revision[0].as_revision_id(base_branch)
 
3603
        else:
 
3604
            base_revision_id = None
3796
3605
        # Remember where we merge from
3797
3606
        if ((remember or tree.branch.get_submit_branch() is None) and
3798
3607
             user_location is not None):
3807
3616
            allow_pending = True
3808
3617
        return merger, allow_pending
3809
3618
 
3810
 
    def get_merger_from_uncommitted(self, tree, location, pb, cleanups):
3811
 
        """Get a merger for uncommitted changes.
3812
 
 
3813
 
        :param tree: The tree the merger should apply to.
3814
 
        :param location: The location containing uncommitted changes.
3815
 
        :param pb: The progress bar to use for showing progress.
3816
 
        :param cleanups: A list of operations to perform to clean up the
3817
 
            temporary directories, unfinalized objects, etc.
3818
 
        """
3819
 
        location = self._select_branch_location(tree, location)[0]
3820
 
        other_tree, other_path = WorkingTree.open_containing(location)
3821
 
        merger = _mod_merge.Merger.from_uncommitted(tree, other_tree, pb)
3822
 
        if other_path != '':
3823
 
            merger.interesting_files = [other_path]
3824
 
        return merger
3825
 
 
3826
3619
    def _select_branch_location(self, tree, user_location, revision=None,
3827
3620
                                index=None):
3828
3621
        """Select a branch location, according to possible inputs.
4683
4476
    takes_options = [
4684
4477
        Option('inet',
4685
4478
               help='Serve on stdin/out for use from inetd or sshd.'),
4686
 
        RegistryOption('protocol', 
4687
 
               help="Protocol to serve.", 
4688
 
               lazy_registry=('bzrlib.transport', 'transport_server_registry'),
4689
 
               value_switches=True),
4690
4479
        Option('port',
4691
4480
               help='Listen for connections on nominated port of the form '
4692
4481
                    '[hostname:]portnumber.  Passing 0 as the port number will '
4693
 
                    'result in a dynamically allocated port.  The default port '
4694
 
                    'depends on the protocol.',
 
4482
                    'result in a dynamically allocated port.  The default port is '
 
4483
                    '4155.',
4695
4484
               type=str),
4696
4485
        Option('directory',
4697
4486
               help='Serve contents of this directory.',
4703
4492
                ),
4704
4493
        ]
4705
4494
 
 
4495
    def run_smart_server(self, smart_server):
 
4496
        """Run 'smart_server' forever, with no UI output at all."""
 
4497
        # For the duration of this server, no UI output is permitted. note
 
4498
        # that this may cause problems with blackbox tests. This should be
 
4499
        # changed with care though, as we dont want to use bandwidth sending
 
4500
        # progress over stderr to smart server clients!
 
4501
        from bzrlib import lockdir
 
4502
        old_factory = ui.ui_factory
 
4503
        old_lockdir_timeout = lockdir._DEFAULT_TIMEOUT_SECONDS
 
4504
        try:
 
4505
            ui.ui_factory = ui.SilentUIFactory()
 
4506
            lockdir._DEFAULT_TIMEOUT_SECONDS = 0
 
4507
            smart_server.serve()
 
4508
        finally:
 
4509
            ui.ui_factory = old_factory
 
4510
            lockdir._DEFAULT_TIMEOUT_SECONDS = old_lockdir_timeout
 
4511
 
4706
4512
    def get_host_and_port(self, port):
4707
4513
        """Return the host and port to run the smart server on.
4708
4514
 
4709
 
        If 'port' is None, None will be returned for the host and port.
 
4515
        If 'port' is None, the default host (`medium.BZR_DEFAULT_INTERFACE`)
 
4516
        and port (`medium.BZR_DEFAULT_PORT`) will be used.
4710
4517
 
4711
4518
        If 'port' has a colon in it, the string before the colon will be
4712
4519
        interpreted as the host.
4715
4522
        :return: A tuple of (host, port), where 'host' is a host name or IP,
4716
4523
            and port is an integer TCP/IP port.
4717
4524
        """
4718
 
        host = None
4719
 
        if port is not None:
 
4525
        from bzrlib.smart import medium
 
4526
        host = medium.BZR_DEFAULT_INTERFACE
 
4527
        if port is None:
 
4528
            port = medium.BZR_DEFAULT_PORT
 
4529
        else:
4720
4530
            if ':' in port:
4721
4531
                host, port = port.split(':')
4722
4532
            port = int(port)
4723
4533
        return host, port
4724
4534
 
4725
 
    def run(self, port=None, inet=False, directory=None, allow_writes=False,
4726
 
            protocol=None):
4727
 
        from bzrlib.transport import get_transport, transport_server_registry
 
4535
    def get_smart_server(self, transport, inet, port):
 
4536
        """Construct a smart server.
 
4537
 
 
4538
        :param transport: The base transport from which branches will be
 
4539
            served.
 
4540
        :param inet: If True, serve over stdin and stdout. Used for running
 
4541
            from inet.
 
4542
        :param port: The port to listen on. By default, it's `
 
4543
            medium.BZR_DEFAULT_PORT`. See `get_host_and_port` for more
 
4544
            information.
 
4545
        :return: A smart server.
 
4546
        """
 
4547
        from bzrlib.smart import medium, server
 
4548
        if inet:
 
4549
            smart_server = medium.SmartServerPipeStreamMedium(
 
4550
                sys.stdin, sys.stdout, transport)
 
4551
        else:
 
4552
            host, port = self.get_host_and_port(port)
 
4553
            smart_server = server.SmartTCPServer(
 
4554
                transport, host=host, port=port)
 
4555
            note('listening on port: %s' % smart_server.port)
 
4556
        return smart_server
 
4557
 
 
4558
    def run(self, port=None, inet=False, directory=None, allow_writes=False):
 
4559
        from bzrlib.transport import get_transport
 
4560
        from bzrlib.transport.chroot import ChrootServer
4728
4561
        if directory is None:
4729
4562
            directory = os.getcwd()
4730
 
        if protocol is None:
4731
 
            protocol = transport_server_registry.get()
4732
 
        host, port = self.get_host_and_port(port)
4733
4563
        url = urlutils.local_path_to_url(directory)
4734
4564
        if not allow_writes:
4735
4565
            url = 'readonly+' + url
4736
 
        transport = get_transport(url)
4737
 
        protocol(transport, host, port, inet)
 
4566
        chroot_server = ChrootServer(get_transport(url))
 
4567
        chroot_server.setUp()
 
4568
        t = get_transport(chroot_server.get_url())
 
4569
        smart_server = self.get_smart_server(t, inet, port)
 
4570
        self.run_smart_server(smart_server)
4738
4571
 
4739
4572
 
4740
4573
class cmd_join(Command):
4806
4639
        try:
4807
4640
            containing_tree.extract(sub_id)
4808
4641
        except errors.RootNotRich:
4809
 
            raise errors.RichRootUpgradeRequired(containing_tree.branch.base)
 
4642
            raise errors.UpgradeRequired(containing_tree.branch.base)
4810
4643
 
4811
4644
 
4812
4645
class cmd_merge_directive(Command):
4981
4814
               help='Write merge directive to this file; '
4982
4815
                    'use - for stdout.',
4983
4816
               type=unicode),
4984
 
        Option('strict',
4985
 
               help='Refuse to send if there are uncommitted changes in'
4986
 
               ' the working tree, --no-strict disables the check.'),
4987
4817
        Option('mail-to', help='Mail the request to this address.',
4988
4818
               type=unicode),
4989
4819
        'revision',
4990
4820
        'message',
4991
4821
        Option('body', help='Body for the email.', type=unicode),
4992
 
        RegistryOption('format',
4993
 
                       help='Use the specified output format.',
4994
 
                       lazy_registry=('bzrlib.send', 'format_registry')),
 
4822
        RegistryOption.from_kwargs('format',
 
4823
        'Use the specified output format.',
 
4824
        **{'4': 'Bundle format 4, Merge Directive 2 (default)',
 
4825
           '0.9': 'Bundle format 0.9, Merge Directive 1',})
4995
4826
        ]
4996
4827
 
4997
4828
    def run(self, submit_branch=None, public_branch=None, no_bundle=False,
4998
4829
            no_patch=False, revision=None, remember=False, output=None,
4999
 
            format=None, mail_to=None, message=None, body=None,
5000
 
            strict=None, **kwargs):
5001
 
        from bzrlib.send import send
5002
 
        return send(submit_branch, revision, public_branch, remember,
5003
 
                    format, no_bundle, no_patch, output,
5004
 
                    kwargs.get('from', '.'), mail_to, message, body,
5005
 
                    self.outf,
5006
 
                    strict=strict)
 
4830
            format='4', mail_to=None, message=None, body=None, **kwargs):
 
4831
        return self._run(submit_branch, revision, public_branch, remember,
 
4832
                         format, no_bundle, no_patch, output,
 
4833
                         kwargs.get('from', '.'), mail_to, message, body)
 
4834
 
 
4835
    def _run(self, submit_branch, revision, public_branch, remember, format,
 
4836
             no_bundle, no_patch, output, from_, mail_to, message, body):
 
4837
        from bzrlib.revision import NULL_REVISION
 
4838
        branch = Branch.open_containing(from_)[0]
 
4839
        if output is None:
 
4840
            outfile = cStringIO.StringIO()
 
4841
        elif output == '-':
 
4842
            outfile = self.outf
 
4843
        else:
 
4844
            outfile = open(output, 'wb')
 
4845
        # we may need to write data into branch's repository to calculate
 
4846
        # the data to send.
 
4847
        branch.lock_write()
 
4848
        try:
 
4849
            if output is None:
 
4850
                config = branch.get_config()
 
4851
                if mail_to is None:
 
4852
                    mail_to = config.get_user_option('submit_to')
 
4853
                mail_client = config.get_mail_client()
 
4854
                if (not getattr(mail_client, 'supports_body', False)
 
4855
                    and body is not None):
 
4856
                    raise errors.BzrCommandError(
 
4857
                        'Mail client "%s" does not support specifying body' %
 
4858
                        mail_client.__class__.__name__)
 
4859
            if remember and submit_branch is None:
 
4860
                raise errors.BzrCommandError(
 
4861
                    '--remember requires a branch to be specified.')
 
4862
            stored_submit_branch = branch.get_submit_branch()
 
4863
            remembered_submit_branch = None
 
4864
            if submit_branch is None:
 
4865
                submit_branch = stored_submit_branch
 
4866
                remembered_submit_branch = "submit"
 
4867
            else:
 
4868
                if stored_submit_branch is None or remember:
 
4869
                    branch.set_submit_branch(submit_branch)
 
4870
            if submit_branch is None:
 
4871
                submit_branch = branch.get_parent()
 
4872
                remembered_submit_branch = "parent"
 
4873
            if submit_branch is None:
 
4874
                raise errors.BzrCommandError('No submit branch known or'
 
4875
                                             ' specified')
 
4876
            if remembered_submit_branch is not None:
 
4877
                note('Using saved %s location "%s" to determine what '
 
4878
                        'changes to submit.', remembered_submit_branch,
 
4879
                        submit_branch)
 
4880
 
 
4881
            if mail_to is None:
 
4882
                submit_config = Branch.open(submit_branch).get_config()
 
4883
                mail_to = submit_config.get_user_option("child_submit_to")
 
4884
 
 
4885
            stored_public_branch = branch.get_public_branch()
 
4886
            if public_branch is None:
 
4887
                public_branch = stored_public_branch
 
4888
            elif stored_public_branch is None or remember:
 
4889
                branch.set_public_branch(public_branch)
 
4890
            if no_bundle and public_branch is None:
 
4891
                raise errors.BzrCommandError('No public branch specified or'
 
4892
                                             ' known')
 
4893
            base_revision_id = None
 
4894
            revision_id = None
 
4895
            if revision is not None:
 
4896
                if len(revision) > 2:
 
4897
                    raise errors.BzrCommandError('bzr send takes '
 
4898
                        'at most two one revision identifiers')
 
4899
                revision_id = revision[-1].as_revision_id(branch)
 
4900
                if len(revision) == 2:
 
4901
                    base_revision_id = revision[0].as_revision_id(branch)
 
4902
            if revision_id is None:
 
4903
                revision_id = branch.last_revision()
 
4904
            if revision_id == NULL_REVISION:
 
4905
                raise errors.BzrCommandError('No revisions to submit.')
 
4906
            if format == '4':
 
4907
                directive = merge_directive.MergeDirective2.from_objects(
 
4908
                    branch.repository, revision_id, time.time(),
 
4909
                    osutils.local_time_offset(), submit_branch,
 
4910
                    public_branch=public_branch, include_patch=not no_patch,
 
4911
                    include_bundle=not no_bundle, message=message,
 
4912
                    base_revision_id=base_revision_id)
 
4913
            elif format == '0.9':
 
4914
                if not no_bundle:
 
4915
                    if not no_patch:
 
4916
                        patch_type = 'bundle'
 
4917
                    else:
 
4918
                        raise errors.BzrCommandError('Format 0.9 does not'
 
4919
                            ' permit bundle with no patch')
 
4920
                else:
 
4921
                    if not no_patch:
 
4922
                        patch_type = 'diff'
 
4923
                    else:
 
4924
                        patch_type = None
 
4925
                directive = merge_directive.MergeDirective.from_objects(
 
4926
                    branch.repository, revision_id, time.time(),
 
4927
                    osutils.local_time_offset(), submit_branch,
 
4928
                    public_branch=public_branch, patch_type=patch_type,
 
4929
                    message=message)
 
4930
 
 
4931
            outfile.writelines(directive.to_lines())
 
4932
            if output is None:
 
4933
                subject = '[MERGE] '
 
4934
                if message is not None:
 
4935
                    subject += message
 
4936
                else:
 
4937
                    revision = branch.repository.get_revision(revision_id)
 
4938
                    subject += revision.get_summary()
 
4939
                basename = directive.get_disk_name(branch)
 
4940
                mail_client.compose_merge_request(mail_to, subject,
 
4941
                                                  outfile.getvalue(),
 
4942
                                                  basename, body)
 
4943
        finally:
 
4944
            if output != '-':
 
4945
                outfile.close()
 
4946
            branch.unlock()
5007
4947
 
5008
4948
 
5009
4949
class cmd_bundle_revisions(cmd_send):
 
4950
 
5010
4951
    """Create a merge-directive for submitting changes.
5011
4952
 
5012
4953
    A merge directive provides many things needed for requesting merges:
5053
4994
               type=unicode),
5054
4995
        Option('output', short_name='o', help='Write directive to this file.',
5055
4996
               type=unicode),
5056
 
        Option('strict',
5057
 
               help='Refuse to bundle revisions if there are uncommitted'
5058
 
               ' changes in the working tree, --no-strict disables the check.'),
5059
4997
        'revision',
5060
 
        RegistryOption('format',
5061
 
                       help='Use the specified output format.',
5062
 
                       lazy_registry=('bzrlib.send', 'format_registry')),
 
4998
        RegistryOption.from_kwargs('format',
 
4999
        'Use the specified output format.',
 
5000
        **{'4': 'Bundle format 4, Merge Directive 2 (default)',
 
5001
           '0.9': 'Bundle format 0.9, Merge Directive 1',})
5063
5002
        ]
5064
5003
    aliases = ['bundle']
5065
5004
 
5069
5008
 
5070
5009
    def run(self, submit_branch=None, public_branch=None, no_bundle=False,
5071
5010
            no_patch=False, revision=None, remember=False, output=None,
5072
 
            format=None, strict=None, **kwargs):
 
5011
            format='4', **kwargs):
5073
5012
        if output is None:
5074
5013
            output = '-'
5075
 
        from bzrlib.send import send
5076
 
        return send(submit_branch, revision, public_branch, remember,
 
5014
        return self._run(submit_branch, revision, public_branch, remember,
5077
5015
                         format, no_bundle, no_patch, output,
5078
 
                         kwargs.get('from', '.'), None, None, None,
5079
 
                         self.outf, strict=strict)
 
5016
                         kwargs.get('from', '.'), None, None, None)
5080
5017
 
5081
5018
 
5082
5019
class cmd_tag(Command):
5177
5114
        if not tags:
5178
5115
            return
5179
5116
 
5180
 
        branch.lock_read()
5181
 
        try:
5182
 
            if revision:
 
5117
        if revision:
 
5118
            branch.lock_read()
 
5119
            try:
5183
5120
                graph = branch.repository.get_graph()
5184
5121
                rev1, rev2 = _get_revision_range(revision, branch, self.name())
5185
5122
                revid1, revid2 = rev1.rev_id, rev2.rev_id
5186
5123
                # only show revisions between revid1 and revid2 (inclusive)
5187
5124
                tags = [(tag, revid) for tag, revid in tags if
5188
5125
                    graph.is_between(revid, revid1, revid2)]
5189
 
            if sort == 'alpha':
5190
 
                tags.sort()
5191
 
            elif sort == 'time':
5192
 
                timestamps = {}
5193
 
                for tag, revid in tags:
5194
 
                    try:
5195
 
                        revobj = branch.repository.get_revision(revid)
5196
 
                    except errors.NoSuchRevision:
5197
 
                        timestamp = sys.maxint # place them at the end
5198
 
                    else:
5199
 
                        timestamp = revobj.timestamp
5200
 
                    timestamps[revid] = timestamp
5201
 
                tags.sort(key=lambda x: timestamps[x[1]])
5202
 
            if not show_ids:
5203
 
                # [ (tag, revid), ... ] -> [ (tag, dotted_revno), ... ]
5204
 
                for index, (tag, revid) in enumerate(tags):
5205
 
                    try:
5206
 
                        revno = branch.revision_id_to_dotted_revno(revid)
5207
 
                        if isinstance(revno, tuple):
5208
 
                            revno = '.'.join(map(str, revno))
5209
 
                    except errors.NoSuchRevision:
5210
 
                        # Bad tag data/merges can lead to tagged revisions
5211
 
                        # which are not in this branch. Fail gracefully ...
5212
 
                        revno = '?'
5213
 
                    tags[index] = (tag, revno)
5214
 
        finally:
5215
 
            branch.unlock()
 
5126
            finally:
 
5127
                branch.unlock()
 
5128
        if sort == 'alpha':
 
5129
            tags.sort()
 
5130
        elif sort == 'time':
 
5131
            timestamps = {}
 
5132
            for tag, revid in tags:
 
5133
                try:
 
5134
                    revobj = branch.repository.get_revision(revid)
 
5135
                except errors.NoSuchRevision:
 
5136
                    timestamp = sys.maxint # place them at the end
 
5137
                else:
 
5138
                    timestamp = revobj.timestamp
 
5139
                timestamps[revid] = timestamp
 
5140
            tags.sort(key=lambda x: timestamps[x[1]])
 
5141
        if not show_ids:
 
5142
            # [ (tag, revid), ... ] -> [ (tag, dotted_revno), ... ]
 
5143
            revno_map = branch.get_revision_id_to_revno_map()
 
5144
            tags = [ (tag, '.'.join(map(str, revno_map.get(revid, ('?',)))))
 
5145
                        for tag, revid in tags ]
5216
5146
        for tag, revspec in tags:
5217
5147
            self.outf.write('%-20s %s\n' % (tag, revspec))
5218
5148
 
5254
5184
            ),
5255
5185
        Option('bind-to', help='Branch to bind checkout to.', type=str),
5256
5186
        Option('force',
5257
 
            help='Perform reconfiguration even if local changes'
5258
 
            ' will be lost.'),
5259
 
        Option('stacked-on',
5260
 
            help='Reconfigure a branch to be stacked on another branch.',
5261
 
            type=unicode,
5262
 
            ),
5263
 
        Option('unstacked',
5264
 
            help='Reconfigure a branch to be unstacked.  This '
5265
 
                'may require copying substantial data into it.',
5266
 
            ),
 
5187
               help='Perform reconfiguration even if local changes'
 
5188
               ' will be lost.')
5267
5189
        ]
5268
5190
 
5269
 
    def run(self, location=None, target_type=None, bind_to=None, force=False,
5270
 
            stacked_on=None,
5271
 
            unstacked=None):
 
5191
    def run(self, location=None, target_type=None, bind_to=None, force=False):
5272
5192
        directory = bzrdir.BzrDir.open(location)
5273
 
        if stacked_on and unstacked:
5274
 
            raise BzrCommandError("Can't use both --stacked-on and --unstacked")
5275
 
        elif stacked_on is not None:
5276
 
            reconfigure.ReconfigureStackedOn().apply(directory, stacked_on)
5277
 
        elif unstacked:
5278
 
            reconfigure.ReconfigureUnstacked().apply(directory)
5279
 
        # At the moment you can use --stacked-on and a different
5280
 
        # reconfiguration shape at the same time; there seems no good reason
5281
 
        # to ban it.
5282
5193
        if target_type is None:
5283
 
            if stacked_on or unstacked:
5284
 
                return
5285
 
            else:
5286
 
                raise errors.BzrCommandError('No target configuration '
5287
 
                    'specified')
 
5194
            raise errors.BzrCommandError('No target configuration specified')
5288
5195
        elif target_type == 'branch':
5289
5196
            reconfiguration = reconfigure.Reconfigure.to_branch(directory)
5290
5197
        elif target_type == 'tree':
5333
5240
 
5334
5241
    takes_args = ['to_location']
5335
5242
    takes_options = [Option('force',
5336
 
                        help='Switch even if local commits will be lost.'),
5337
 
                     Option('create-branch', short_name='b',
5338
 
                        help='Create the target branch from this one before'
5339
 
                             ' switching to it.'),
 
5243
                        help='Switch even if local commits will be lost.')
5340
5244
                     ]
5341
5245
 
5342
 
    def run(self, to_location, force=False, create_branch=False):
 
5246
    def run(self, to_location, force=False):
5343
5247
        from bzrlib import switch
5344
5248
        tree_location = '.'
5345
5249
        control_dir = bzrdir.BzrDir.open_containing(tree_location)[0]
 
5250
        branch = control_dir.open_branch()
5346
5251
        try:
5347
 
            branch = control_dir.open_branch()
5348
 
            had_explicit_nick = branch.get_config().has_explicit_nickname()
 
5252
            to_branch = Branch.open(to_location)
5349
5253
        except errors.NotBranchError:
5350
 
            branch = None
5351
 
            had_explicit_nick = False
5352
 
        if create_branch:
5353
 
            if branch is None:
5354
 
                raise errors.BzrCommandError('cannot create branch without'
5355
 
                                             ' source branch')
5356
 
            if '/' not in to_location and '\\' not in to_location:
5357
 
                # This path is meant to be relative to the existing branch
5358
 
                this_url = self._get_branch_location(control_dir)
5359
 
                to_location = urlutils.join(this_url, '..', to_location)
5360
 
            to_branch = branch.bzrdir.sprout(to_location,
5361
 
                                 possible_transports=[branch.bzrdir.root_transport],
5362
 
                                 source_branch=branch).open_branch()
5363
 
            # try:
5364
 
            #     from_branch = control_dir.open_branch()
5365
 
            # except errors.NotBranchError:
5366
 
            #     raise BzrCommandError('Cannot create a branch from this'
5367
 
            #         ' location when we cannot open this branch')
5368
 
            # from_branch.bzrdir.sprout(
5369
 
            pass
5370
 
        else:
5371
 
            try:
5372
 
                to_branch = Branch.open(to_location)
5373
 
            except errors.NotBranchError:
5374
 
                this_url = self._get_branch_location(control_dir)
5375
 
                to_branch = Branch.open(
5376
 
                    urlutils.join(this_url, '..', to_location))
 
5254
            this_branch = control_dir.open_branch()
 
5255
            # This may be a heavy checkout, where we want the master branch
 
5256
            this_url = this_branch.get_bound_location()
 
5257
            # If not, use a local sibling
 
5258
            if this_url is None:
 
5259
                this_url = this_branch.base
 
5260
            to_branch = Branch.open(
 
5261
                urlutils.join(this_url, '..', to_location))
5377
5262
        switch.switch(control_dir, to_branch, force)
5378
 
        if had_explicit_nick:
 
5263
        if branch.get_config().has_explicit_nickname():
5379
5264
            branch = control_dir.open_branch() #get the new branch!
5380
5265
            branch.nick = to_branch.nick
5381
5266
        note('Switched to branch: %s',
5382
5267
            urlutils.unescape_for_display(to_branch.base, 'utf-8'))
5383
5268
 
5384
 
    def _get_branch_location(self, control_dir):
5385
 
        """Return location of branch for this control dir."""
5386
 
        try:
5387
 
            this_branch = control_dir.open_branch()
5388
 
            # This may be a heavy checkout, where we want the master branch
5389
 
            master_location = this_branch.get_bound_location()
5390
 
            if master_location is not None:
5391
 
                return master_location
5392
 
            # If not, use a local sibling
5393
 
            return this_branch.base
5394
 
        except errors.NotBranchError:
5395
 
            format = control_dir.find_branch_format()
5396
 
            if getattr(format, 'get_reference', None) is not None:
5397
 
                return format.get_reference(control_dir)
5398
 
            else:
5399
 
                return control_dir.root_transport.base
5400
 
 
5401
5269
 
5402
5270
class cmd_view(Command):
5403
5271
    """Manage filtered views.
5705
5573
                   dry_run=dry_run, no_prompt=force)
5706
5574
 
5707
5575
 
5708
 
class cmd_reference(Command):
5709
 
    """list, view and set branch locations for nested trees.
5710
 
 
5711
 
    If no arguments are provided, lists the branch locations for nested trees.
5712
 
    If one argument is provided, display the branch location for that tree.
5713
 
    If two arguments are provided, set the branch location for that tree.
5714
 
    """
5715
 
 
5716
 
    hidden = True
5717
 
 
5718
 
    takes_args = ['path?', 'location?']
5719
 
 
5720
 
    def run(self, path=None, location=None):
5721
 
        branchdir = '.'
5722
 
        if path is not None:
5723
 
            branchdir = path
5724
 
        tree, branch, relpath =(
5725
 
            bzrdir.BzrDir.open_containing_tree_or_branch(branchdir))
5726
 
        if path is not None:
5727
 
            path = relpath
5728
 
        if tree is None:
5729
 
            tree = branch.basis_tree()
5730
 
        if path is None:
5731
 
            info = branch._get_all_reference_info().iteritems()
5732
 
            self._display_reference_info(tree, branch, info)
 
5576
def _create_prefix(cur_transport):
 
5577
    needed = [cur_transport]
 
5578
    # Recurse upwards until we can create a directory successfully
 
5579
    while True:
 
5580
        new_transport = cur_transport.clone('..')
 
5581
        if new_transport.base == cur_transport.base:
 
5582
            raise errors.BzrCommandError(
 
5583
                "Failed to create path prefix for %s."
 
5584
                % cur_transport.base)
 
5585
        try:
 
5586
            new_transport.mkdir('.')
 
5587
        except errors.NoSuchFile:
 
5588
            needed.append(new_transport)
 
5589
            cur_transport = new_transport
5733
5590
        else:
5734
 
            file_id = tree.path2id(path)
5735
 
            if file_id is None:
5736
 
                raise errors.NotVersionedError(path)
5737
 
            if location is None:
5738
 
                info = [(file_id, branch.get_reference_info(file_id))]
5739
 
                self._display_reference_info(tree, branch, info)
5740
 
            else:
5741
 
                branch.set_reference_info(file_id, path, location)
5742
 
 
5743
 
    def _display_reference_info(self, tree, branch, info):
5744
 
        ref_list = []
5745
 
        for file_id, (path, location) in info:
5746
 
            try:
5747
 
                path = tree.id2path(file_id)
5748
 
            except errors.NoSuchId:
5749
 
                pass
5750
 
            ref_list.append((path, location))
5751
 
        for path, location in sorted(ref_list):
5752
 
            self.outf.write('%s %s\n' % (path, location))
 
5591
            break
 
5592
    # Now we only need to create child directories
 
5593
    while needed:
 
5594
        cur_transport = needed.pop()
 
5595
        cur_transport.ensure_base()
5753
5596
 
5754
5597
 
5755
5598
# these get imported and then picked up by the scan for cmd_*
5762
5605
from bzrlib.bundle.commands import (
5763
5606
    cmd_bundle_info,
5764
5607
    )
5765
 
from bzrlib.foreign import cmd_dpush
5766
5608
from bzrlib.sign_my_commits import cmd_sign_my_commits
5767
5609
from bzrlib.weave_commands import cmd_versionedfile_list, \
5768
5610
        cmd_weave_plan_merge, cmd_weave_merge_text