~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/builtins.py

  • Committer: John Arbash Meinel
  • Date: 2009-10-12 21:44:27 UTC
  • mto: This revision was merged to the branch mainline in revision 4737.
  • Revision ID: john@arbash-meinel.com-20091012214427-zddi1kmc2jlf7v31
Py_ssize_t and its associated function typedefs are not available w/ python 2.4

So we define them in python-compat.h
Even further, gcc issued a warning for:
static int
_workaround_pyrex_096()
So we changed it to:
_workaround_pyrex_096(void)

Also, some python api funcs were incorrectly defined as 'char *' when they meant
'const char *'. Work around that with a (char *) cast, to avoid compiler warnings.

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,
49
48
    ui,
50
49
    urlutils,
51
50
    views,
121
120
 
122
121
 
123
122
def _get_one_revision_tree(command_name, revisions, branch=None, tree=None):
 
123
    """Get a revision tree. Not suitable for commands that change the tree.
 
124
    
 
125
    Specifically, the basis tree in dirstate trees is coupled to the dirstate
 
126
    and doing a commit/uncommit/pull will at best fail due to changing the
 
127
    basis revision data.
 
128
 
 
129
    If tree is passed in, it should be already locked, for lifetime management
 
130
    of the trees internal cached state.
 
131
    """
124
132
    if branch is None:
125
133
        branch = tree.branch
126
134
    if revisions is None:
450
458
        except errors.NoWorkingTree:
451
459
            raise errors.BzrCommandError("No working tree to remove")
452
460
        except errors.NotLocalUrl:
453
 
            raise errors.BzrCommandError("You cannot remove the working tree of a "
454
 
                                         "remote path")
 
461
            raise errors.BzrCommandError("You cannot remove the working tree"
 
462
                                         " of a remote path")
455
463
        if not force:
456
 
            changes = working.changes_from(working.basis_tree())
457
 
            if changes.has_changed():
 
464
            if (working.has_changes()):
458
465
                raise errors.UncommittedChanges(working)
459
466
 
460
467
        working_path = working.bzrdir.root_transport.base
461
468
        branch_path = working.branch.bzrdir.root_transport.base
462
469
        if working_path != branch_path:
463
 
            raise errors.BzrCommandError("You cannot remove the working tree from "
464
 
                                         "a lightweight checkout")
 
470
            raise errors.BzrCommandError("You cannot remove the working tree"
 
471
                                         " from a lightweight checkout")
465
472
 
466
473
        d.destroy_workingtree()
467
474
 
474
481
 
475
482
    _see_also = ['info']
476
483
    takes_args = ['location?']
 
484
    takes_options = [
 
485
        Option('tree', help='Show revno of working tree'),
 
486
        ]
477
487
 
478
488
    @display_command
479
 
    def run(self, location=u'.'):
480
 
        self.outf.write(str(Branch.open_containing(location)[0].revno()))
481
 
        self.outf.write('\n')
 
489
    def run(self, tree=False, location=u'.'):
 
490
        if tree:
 
491
            try:
 
492
                wt = WorkingTree.open_containing(location)[0]
 
493
                wt.lock_read()
 
494
            except (errors.NoWorkingTree, errors.NotLocalUrl):
 
495
                raise errors.NoWorkingTree(location)
 
496
            try:
 
497
                revid = wt.last_revision()
 
498
                try:
 
499
                    revno_t = wt.branch.revision_id_to_dotted_revno(revid)
 
500
                except errors.NoSuchRevision:
 
501
                    revno_t = ('???',)
 
502
                revno = ".".join(str(n) for n in revno_t)
 
503
            finally:
 
504
                wt.unlock()
 
505
        else:
 
506
            b = Branch.open_containing(location)[0]
 
507
            b.lock_read()
 
508
            try:
 
509
                revno = b.revno()
 
510
            finally:
 
511
                b.unlock()
 
512
 
 
513
        self.outf.write(str(revno) + '\n')
482
514
 
483
515
 
484
516
class cmd_revision_info(Command):
494
526
            short_name='d',
495
527
            type=unicode,
496
528
            ),
 
529
        Option('tree', help='Show revno of working tree'),
497
530
        ]
498
531
 
499
532
    @display_command
500
 
    def run(self, revision=None, directory=u'.', revision_info_list=[]):
501
 
 
502
 
        revs = []
503
 
        if revision is not None:
504
 
            revs.extend(revision)
505
 
        if revision_info_list is not None:
506
 
            for rev in revision_info_list:
507
 
                revs.append(RevisionSpec.from_string(rev))
508
 
 
509
 
        b = Branch.open_containing(directory)[0]
510
 
 
511
 
        if len(revs) == 0:
512
 
            revs.append(RevisionSpec.from_string('-1'))
513
 
 
514
 
        for rev in revs:
515
 
            revision_id = rev.as_revision_id(b)
516
 
            try:
517
 
                revno = '%4d' % (b.revision_id_to_revno(revision_id))
518
 
            except errors.NoSuchRevision:
519
 
                dotted_map = b.get_revision_id_to_revno_map()
520
 
                revno = '.'.join(str(i) for i in dotted_map[revision_id])
521
 
            print '%s %s' % (revno, revision_id)
 
533
    def run(self, revision=None, directory=u'.', tree=False,
 
534
            revision_info_list=[]):
 
535
 
 
536
        try:
 
537
            wt = WorkingTree.open_containing(directory)[0]
 
538
            b = wt.branch
 
539
            wt.lock_read()
 
540
        except (errors.NoWorkingTree, errors.NotLocalUrl):
 
541
            wt = None
 
542
            b = Branch.open_containing(directory)[0]
 
543
            b.lock_read()
 
544
        try:
 
545
            revision_ids = []
 
546
            if revision is not None:
 
547
                revision_ids.extend(rev.as_revision_id(b) for rev in revision)
 
548
            if revision_info_list is not None:
 
549
                for rev_str in revision_info_list:
 
550
                    rev_spec = RevisionSpec.from_string(rev_str)
 
551
                    revision_ids.append(rev_spec.as_revision_id(b))
 
552
            # No arguments supplied, default to the last revision
 
553
            if len(revision_ids) == 0:
 
554
                if tree:
 
555
                    if wt is None:
 
556
                        raise errors.NoWorkingTree(directory)
 
557
                    revision_ids.append(wt.last_revision())
 
558
                else:
 
559
                    revision_ids.append(b.last_revision())
 
560
 
 
561
            revinfos = []
 
562
            maxlen = 0
 
563
            for revision_id in revision_ids:
 
564
                try:
 
565
                    dotted_revno = b.revision_id_to_dotted_revno(revision_id)
 
566
                    revno = '.'.join(str(i) for i in dotted_revno)
 
567
                except errors.NoSuchRevision:
 
568
                    revno = '???'
 
569
                maxlen = max(maxlen, len(revno))
 
570
                revinfos.append([revno, revision_id])
 
571
        finally:
 
572
            if wt is None:
 
573
                b.unlock()
 
574
            else:
 
575
                wt.unlock()
 
576
 
 
577
        for ri in revinfos:
 
578
            self.outf.write('%*s %s\n' % (maxlen, ri[0], ri[1]))
522
579
 
523
580
 
524
581
class cmd_add(Command):
554
611
    branches that will be merged later (without showing the two different
555
612
    adds as a conflict). It is also useful when merging another project
556
613
    into a subdirectory of this one.
 
614
    
 
615
    Any files matching patterns in the ignore list will not be added
 
616
    unless they are explicitly mentioned.
557
617
    """
558
618
    takes_args = ['file*']
559
619
    takes_options = [
567
627
               help='Lookup file ids from this tree.'),
568
628
        ]
569
629
    encoding_type = 'replace'
570
 
    _see_also = ['remove']
 
630
    _see_also = ['remove', 'ignore']
571
631
 
572
632
    def run(self, file_list, no_recurse=False, dry_run=False, verbose=False,
573
633
            file_ids_from=None):
605
665
                    for path in ignored[glob]:
606
666
                        self.outf.write("ignored %s matching \"%s\"\n"
607
667
                                        % (path, glob))
608
 
            else:
609
 
                match_len = 0
610
 
                for glob, paths in ignored.items():
611
 
                    match_len += len(paths)
612
 
                self.outf.write("ignored %d file(s).\n" % match_len)
613
 
            self.outf.write("If you wish to add ignored files, "
614
 
                            "please add them explicitly by name. "
615
 
                            "(\"bzr ignored\" gives a list)\n")
616
668
 
617
669
 
618
670
class cmd_mkdir(Command):
750
802
        if len(names_list) < 2:
751
803
            raise errors.BzrCommandError("missing file argument")
752
804
        tree, rel_names = tree_files(names_list, canonicalize=False)
753
 
        tree.lock_write()
 
805
        tree.lock_tree_write()
754
806
        try:
755
807
            self._run(tree, names_list, rel_names, after)
756
808
        finally:
764
816
            raise errors.BzrCommandError('--after cannot be specified with'
765
817
                                         ' --auto.')
766
818
        work_tree, file_list = tree_files(names_list, default_branch='.')
767
 
        work_tree.lock_write()
 
819
        work_tree.lock_tree_write()
768
820
        try:
769
821
            rename_map.RenameMap.guess_renames(work_tree, dry_run)
770
822
        finally:
1030
1082
            type=unicode),
1031
1083
        Option('strict',
1032
1084
               help='Refuse to push if there are uncommitted changes in'
1033
 
               ' the working tree.'),
 
1085
               ' the working tree, --no-strict disables the check.'),
1034
1086
        ]
1035
1087
    takes_args = ['location?']
1036
1088
    encoding_type = 'replace'
1044
1096
        if directory is None:
1045
1097
            directory = '.'
1046
1098
        # Get the source branch
1047
 
        tree, br_from = bzrdir.BzrDir.open_tree_or_branch(directory)
 
1099
        (tree, br_from,
 
1100
         _unused) = bzrdir.BzrDir.open_containing_tree_or_branch(directory)
1048
1101
        if strict is None:
1049
 
            strict = br_from.get_config().get_user_option('push_strict')
1050
 
            if strict is not None:
1051
 
                # FIXME: This should be better supported by config
1052
 
                # -- vila 20090611
1053
 
                bools = dict(yes=True, no=False, on=True, off=False,
1054
 
                             true=True, false=False)
1055
 
                try:
1056
 
                    strict = bools[strict.lower()]
1057
 
                except KeyError:
1058
 
                    strict = None
1059
 
        if strict:
1060
 
            changes = tree.changes_from(tree.basis_tree())
1061
 
            if changes.has_changed():
1062
 
                raise errors.UncommittedChanges(tree)
 
1102
            strict = br_from.get_config().get_user_option_as_bool('push_strict')
 
1103
        if strict is None: strict = True # default value
1063
1104
        # Get the tip's revision_id
1064
1105
        revision = _get_one_revision('push', revision)
1065
1106
        if revision is not None:
1066
1107
            revision_id = revision.in_history(br_from).rev_id
1067
1108
        else:
1068
1109
            revision_id = None
 
1110
        if strict and tree is not None and revision_id is None:
 
1111
            if (tree.has_changes()):
 
1112
                raise errors.UncommittedChanges(
 
1113
                    tree, more='Use --no-strict to force the push.')
 
1114
            if tree.last_revision() != tree.branch.last_revision():
 
1115
                # The tree has lost sync with its branch, there is little
 
1116
                # chance that the user is aware of it but he can still force
 
1117
                # the push with --no-strict
 
1118
                raise errors.OutOfDateTree(
 
1119
                    tree, more='Use --no-strict to force the push.')
1069
1120
 
1070
1121
        # Get the stacked_on branch, if any
1071
1122
        if stacked_on is not None:
1123
1174
        help='Hard-link working tree files where possible.'),
1124
1175
        Option('no-tree',
1125
1176
            help="Create a branch without a working-tree."),
 
1177
        Option('switch',
 
1178
            help="Switch the checkout in the current directory "
 
1179
                 "to the new branch."),
1126
1180
        Option('stacked',
1127
1181
            help='Create a stacked branch referring to the source branch. '
1128
1182
                'The new branch will depend on the availability of the source '
1129
1183
                'branch for all operations.'),
1130
1184
        Option('standalone',
1131
1185
               help='Do not use a shared repository, even if available.'),
 
1186
        Option('use-existing-dir',
 
1187
               help='By default branch will fail if the target'
 
1188
                    ' directory exists, but does not already'
 
1189
                    ' have a control directory.  This flag will'
 
1190
                    ' allow branch to proceed.'),
1132
1191
        ]
1133
1192
    aliases = ['get', 'clone']
1134
1193
 
1135
1194
    def run(self, from_location, to_location=None, revision=None,
1136
 
            hardlink=False, stacked=False, standalone=False, no_tree=False):
 
1195
            hardlink=False, stacked=False, standalone=False, no_tree=False,
 
1196
            use_existing_dir=False, switch=False):
 
1197
        from bzrlib import switch as _mod_switch
1137
1198
        from bzrlib.tag import _merge_tags_if_possible
1138
 
 
1139
1199
        accelerator_tree, br_from = bzrdir.BzrDir.open_tree_or_branch(
1140
1200
            from_location)
1141
1201
        if (accelerator_tree is not None and
1157
1217
            try:
1158
1218
                to_transport.mkdir('.')
1159
1219
            except errors.FileExists:
1160
 
                raise errors.BzrCommandError('Target directory "%s" already'
1161
 
                                             ' exists.' % to_location)
 
1220
                if not use_existing_dir:
 
1221
                    raise errors.BzrCommandError('Target directory "%s" '
 
1222
                        'already exists.' % to_location)
 
1223
                else:
 
1224
                    try:
 
1225
                        bzrdir.BzrDir.open_from_transport(to_transport)
 
1226
                    except errors.NotBranchError:
 
1227
                        pass
 
1228
                    else:
 
1229
                        raise errors.AlreadyBranchError(to_location)
1162
1230
            except errors.NoSuchFile:
1163
1231
                raise errors.BzrCommandError('Parent of "%s" does not exist.'
1164
1232
                                             % to_location)
1187
1255
            except (errors.NotStacked, errors.UnstackableBranchFormat,
1188
1256
                errors.UnstackableRepositoryFormat), e:
1189
1257
                note('Branched %d revision(s).' % branch.revno())
 
1258
            if switch:
 
1259
                # Switch to the new branch
 
1260
                wt, _ = WorkingTree.open_containing('.')
 
1261
                _mod_switch.switch(wt.bzrdir, branch)
 
1262
                note('Switched to branch: %s',
 
1263
                    urlutils.unescape_for_display(branch.base, 'utf-8'))
1190
1264
        finally:
1191
1265
            br_from.unlock()
1192
1266
 
1409
1483
            title='Deletion Strategy', value_switches=True, enum_switch=False,
1410
1484
            safe='Only delete files if they can be'
1411
1485
                 ' safely recovered (default).',
1412
 
            keep="Don't delete any files.",
 
1486
            keep='Delete from bzr but leave the working copy.',
1413
1487
            force='Delete all the specified files, even if they can not be '
1414
1488
                'recovered and even if they are non-empty directories.')]
1415
1489
    aliases = ['rm', 'del']
1597
1671
                lazy_registry=('bzrlib.bzrdir', 'format_registry'),
1598
1672
                converter=lambda name: bzrdir.format_registry.make_bzrdir(name),
1599
1673
                value_switches=True,
1600
 
                title="Branch Format",
 
1674
                title="Branch format",
1601
1675
                ),
1602
1676
         Option('append-revisions-only',
1603
1677
                help='Never change revnos or the existing log.'
1811
1885
    @display_command
1812
1886
    def run(self, revision=None, file_list=None, diff_options=None,
1813
1887
            prefix=None, old=None, new=None, using=None):
1814
 
        from bzrlib.diff import _get_trees_to_diff, show_diff_trees
 
1888
        from bzrlib.diff import get_trees_and_branches_to_diff, show_diff_trees
1815
1889
 
1816
1890
        if (prefix is None) or (prefix == '0'):
1817
1891
            # diff -p0 format
1831
1905
            raise errors.BzrCommandError('bzr diff --revision takes exactly'
1832
1906
                                         ' one or two revision specifiers')
1833
1907
 
1834
 
        old_tree, new_tree, specific_files, extra_trees = \
1835
 
                _get_trees_to_diff(file_list, revision, old, new,
1836
 
                apply_view=True)
 
1908
        (old_tree, new_tree,
 
1909
         old_branch, new_branch,
 
1910
         specific_files, extra_trees) = get_trees_and_branches_to_diff(
 
1911
            file_list, revision, old, new, apply_view=True)
1837
1912
        return show_diff_trees(old_tree, new_tree, sys.stdout,
1838
1913
                               specific_files=specific_files,
1839
1914
                               external_diff_options=diff_options,
2395
2470
 
2396
2471
        if path is None:
2397
2472
            fs_path = '.'
2398
 
            prefix = ''
2399
2473
        else:
2400
2474
            if from_root:
2401
2475
                raise errors.BzrCommandError('cannot specify both --from-root'
2402
2476
                                             ' and PATH')
2403
2477
            fs_path = path
2404
 
            prefix = path
2405
2478
        tree, branch, relpath = bzrdir.BzrDir.open_containing_tree_or_branch(
2406
2479
            fs_path)
 
2480
 
 
2481
        # Calculate the prefix to use
 
2482
        prefix = None
2407
2483
        if from_root:
2408
 
            relpath = u''
2409
 
        elif relpath:
2410
 
            relpath += '/'
 
2484
            if relpath:
 
2485
                prefix = relpath + '/'
 
2486
        elif fs_path != '.':
 
2487
            prefix = fs_path + '/'
 
2488
 
2411
2489
        if revision is not None or tree is None:
2412
2490
            tree = _get_one_revision_tree('ls', revision, branch=branch)
2413
2491
 
2421
2499
 
2422
2500
        tree.lock_read()
2423
2501
        try:
2424
 
            for fp, fc, fkind, fid, entry in tree.list_files(include_root=False):
2425
 
                if fp.startswith(relpath):
2426
 
                    rp = fp[len(relpath):]
2427
 
                    fp = osutils.pathjoin(prefix, rp)
2428
 
                    if not recursive and '/' in rp:
2429
 
                        continue
2430
 
                    if not all and not selection[fc]:
2431
 
                        continue
2432
 
                    if kind is not None and fkind != kind:
2433
 
                        continue
2434
 
                    if apply_view:
2435
 
                        try:
2436
 
                            views.check_path_in_view(tree, fp)
2437
 
                        except errors.FileOutsideView:
2438
 
                            continue
2439
 
                    kindch = entry.kind_character()
2440
 
                    outstring = fp + kindch
2441
 
                    ui.ui_factory.clear_term()
2442
 
                    if verbose:
2443
 
                        outstring = '%-8s %s' % (fc, outstring)
2444
 
                        if show_ids and fid is not None:
2445
 
                            outstring = "%-50s %s" % (outstring, fid)
2446
 
                        self.outf.write(outstring + '\n')
2447
 
                    elif null:
2448
 
                        self.outf.write(fp + '\0')
2449
 
                        if show_ids:
2450
 
                            if fid is not None:
2451
 
                                self.outf.write(fid)
2452
 
                            self.outf.write('\0')
2453
 
                        self.outf.flush()
2454
 
                    else:
 
2502
            for fp, fc, fkind, fid, entry in tree.list_files(include_root=False,
 
2503
                from_dir=relpath, recursive=recursive):
 
2504
                # Apply additional masking
 
2505
                if not all and not selection[fc]:
 
2506
                    continue
 
2507
                if kind is not None and fkind != kind:
 
2508
                    continue
 
2509
                if apply_view:
 
2510
                    try:
 
2511
                        if relpath:
 
2512
                            fullpath = osutils.pathjoin(relpath, fp)
 
2513
                        else:
 
2514
                            fullpath = fp
 
2515
                        views.check_path_in_view(tree, fullpath)
 
2516
                    except errors.FileOutsideView:
 
2517
                        continue
 
2518
 
 
2519
                # Output the entry
 
2520
                if prefix:
 
2521
                    fp = osutils.pathjoin(prefix, fp)
 
2522
                kindch = entry.kind_character()
 
2523
                outstring = fp + kindch
 
2524
                ui.ui_factory.clear_term()
 
2525
                if verbose:
 
2526
                    outstring = '%-8s %s' % (fc, outstring)
 
2527
                    if show_ids and fid is not None:
 
2528
                        outstring = "%-50s %s" % (outstring, fid)
 
2529
                    self.outf.write(outstring + '\n')
 
2530
                elif null:
 
2531
                    self.outf.write(fp + '\0')
 
2532
                    if show_ids:
 
2533
                        if fid is not None:
 
2534
                            self.outf.write(fid)
 
2535
                        self.outf.write('\0')
 
2536
                    self.outf.flush()
 
2537
                else:
 
2538
                    if show_ids:
2455
2539
                        if fid is not None:
2456
2540
                            my_id = fid
2457
2541
                        else:
2458
2542
                            my_id = ''
2459
 
                        if show_ids:
2460
 
                            self.outf.write('%-50s %s\n' % (outstring, my_id))
2461
 
                        else:
2462
 
                            self.outf.write(outstring + '\n')
 
2543
                        self.outf.write('%-50s %s\n' % (outstring, my_id))
 
2544
                    else:
 
2545
                        self.outf.write(outstring + '\n')
2463
2546
        finally:
2464
2547
            tree.unlock()
2465
2548
 
2954
3037
                raise errors.BzrCommandError("empty commit message specified")
2955
3038
            return my_message
2956
3039
 
 
3040
        # The API permits a commit with a filter of [] to mean 'select nothing'
 
3041
        # but the command line should not do that.
 
3042
        if not selected_list:
 
3043
            selected_list = None
2957
3044
        try:
2958
3045
            tree.commit(message_callback=get_message,
2959
3046
                        specific_files=selected_list,
2989
3076
    The working tree and branch checks will only give output if a problem is
2990
3077
    detected. The output fields of the repository check are:
2991
3078
 
2992
 
        revisions: This is just the number of revisions checked.  It doesn't
2993
 
            indicate a problem.
2994
 
        versionedfiles: This is just the number of versionedfiles checked.  It
2995
 
            doesn't indicate a problem.
2996
 
        unreferenced ancestors: Texts that are ancestors of other texts, but
2997
 
            are not properly referenced by the revision ancestry.  This is a
2998
 
            subtle problem that Bazaar can work around.
2999
 
        unique file texts: This is the total number of unique file contents
3000
 
            seen in the checked revisions.  It does not indicate a problem.
3001
 
        repeated file texts: This is the total number of repeated texts seen
3002
 
            in the checked revisions.  Texts can be repeated when their file
3003
 
            entries are modified, but the file contents are not.  It does not
3004
 
            indicate a problem.
 
3079
    revisions
 
3080
        This is just the number of revisions checked.  It doesn't
 
3081
        indicate a problem.
 
3082
 
 
3083
    versionedfiles
 
3084
        This is just the number of versionedfiles checked.  It
 
3085
        doesn't indicate a problem.
 
3086
 
 
3087
    unreferenced ancestors
 
3088
        Texts that are ancestors of other texts, but
 
3089
        are not properly referenced by the revision ancestry.  This is a
 
3090
        subtle problem that Bazaar can work around.
 
3091
 
 
3092
    unique file texts
 
3093
        This is the total number of unique file contents
 
3094
        seen in the checked revisions.  It does not indicate a problem.
 
3095
 
 
3096
    repeated file texts
 
3097
        This is the total number of repeated texts seen
 
3098
        in the checked revisions.  Texts can be repeated when their file
 
3099
        entries are modified, but the file contents are not.  It does not
 
3100
        indicate a problem.
3005
3101
 
3006
3102
    If no restrictions are specified, all Bazaar data that is found at the given
3007
3103
    location will be checked.
3243
3339
    Tests that need working space on disk use a common temporary directory,
3244
3340
    typically inside $TMPDIR or /tmp.
3245
3341
 
 
3342
    If you set BZR_TEST_PDB=1 when running selftest, failing tests will drop
 
3343
    into a pdb postmortem session.
 
3344
 
3246
3345
    :Examples:
3247
3346
        Run only tests relating to 'ignore'::
3248
3347
 
3285
3384
                     Option('lsprof-timed',
3286
3385
                            help='Generate lsprof output for benchmarked'
3287
3386
                                 ' sections of code.'),
 
3387
                     Option('lsprof-tests',
 
3388
                            help='Generate lsprof output for each test.'),
3288
3389
                     Option('cache-dir', type=str,
3289
3390
                            help='Cache intermediate benchmark output in this '
3290
3391
                                 'directory.'),
3331
3432
            first=False, list_only=False,
3332
3433
            randomize=None, exclude=None, strict=False,
3333
3434
            load_list=None, debugflag=None, starting_with=None, subunit=False,
3334
 
            parallel=None):
 
3435
            parallel=None, lsprof_tests=False):
3335
3436
        from bzrlib.tests import selftest
3336
3437
        import bzrlib.benchmarks as benchmarks
3337
3438
        from bzrlib.benchmarks import tree_creator
3371
3472
                              "transport": transport,
3372
3473
                              "test_suite_factory": test_suite_factory,
3373
3474
                              "lsprof_timed": lsprof_timed,
 
3475
                              "lsprof_tests": lsprof_tests,
3374
3476
                              "bench_history": benchfile,
3375
3477
                              "matching_tests_first": first,
3376
3478
                              "list_only": list_only,
3484
3586
    merge refuses to run if there are any uncommitted changes, unless
3485
3587
    --force is given.
3486
3588
 
 
3589
    To select only some changes to merge, use "merge -i", which will prompt
 
3590
    you to apply each diff hunk and file change, similar to "shelve".
 
3591
 
3487
3592
    :Examples:
3488
3593
        To merge the latest revision from bzr.dev::
3489
3594
 
3527
3632
               short_name='d',
3528
3633
               type=unicode,
3529
3634
               ),
3530
 
        Option('preview', help='Instead of merging, show a diff of the merge.')
 
3635
        Option('preview', help='Instead of merging, show a diff of the'
 
3636
               ' merge.'),
 
3637
        Option('interactive', help='Select changes interactively.',
 
3638
            short_name='i')
3531
3639
    ]
3532
3640
 
3533
3641
    def run(self, location=None, revision=None, force=False,
3535
3643
            uncommitted=False, pull=False,
3536
3644
            directory=None,
3537
3645
            preview=False,
 
3646
            interactive=False,
3538
3647
            ):
3539
3648
        if merge_type is None:
3540
3649
            merge_type = _mod_merge.Merge3Merger
3546
3655
        verified = 'inapplicable'
3547
3656
        tree = WorkingTree.open_containing(directory)[0]
3548
3657
 
3549
 
        # die as quickly as possible if there are uncommitted changes
3550
3658
        try:
3551
3659
            basis_tree = tree.revision_tree(tree.last_revision())
3552
3660
        except errors.NoSuchRevision:
3553
3661
            basis_tree = tree.basis_tree()
 
3662
 
 
3663
        # die as quickly as possible if there are uncommitted changes
3554
3664
        if not force:
3555
 
            changes = tree.changes_from(basis_tree)
3556
 
            if changes.has_changed():
 
3665
            if tree.has_changes():
3557
3666
                raise errors.UncommittedChanges(tree)
3558
3667
 
3559
3668
        view_info = _get_view_info_for_change_reporter(tree)
3586
3695
                if revision is not None and len(revision) > 0:
3587
3696
                    raise errors.BzrCommandError('Cannot use --uncommitted and'
3588
3697
                        ' --revision at the same time.')
3589
 
                location = self._select_branch_location(tree, location)[0]
3590
 
                other_tree, other_path = WorkingTree.open_containing(location)
3591
 
                merger = _mod_merge.Merger.from_uncommitted(tree, other_tree,
3592
 
                    pb)
 
3698
                merger = self.get_merger_from_uncommitted(tree, location, pb,
 
3699
                                                          cleanups)
3593
3700
                allow_pending = False
3594
 
                if other_path != '':
3595
 
                    merger.interesting_files = [other_path]
3596
3701
 
3597
3702
            if merger is None:
3598
3703
                merger, allow_pending = self._get_merger_from_branch(tree,
3614
3719
                                       merger.other_rev_id)
3615
3720
                    result.report(self.outf)
3616
3721
                    return 0
3617
 
            merger.check_basis(False)
 
3722
            if merger.this_basis is None:
 
3723
                raise errors.BzrCommandError(
 
3724
                    "This branch has no commits."
 
3725
                    " (perhaps you would prefer 'bzr pull')")
3618
3726
            if preview:
3619
 
                return self._do_preview(merger)
 
3727
                return self._do_preview(merger, cleanups)
 
3728
            elif interactive:
 
3729
                return self._do_interactive(merger, cleanups)
3620
3730
            else:
3621
3731
                return self._do_merge(merger, change_reporter, allow_pending,
3622
3732
                                      verified)
3624
3734
            for cleanup in reversed(cleanups):
3625
3735
                cleanup()
3626
3736
 
3627
 
    def _do_preview(self, merger):
3628
 
        from bzrlib.diff import show_diff_trees
 
3737
    def _get_preview(self, merger, cleanups):
3629
3738
        tree_merger = merger.make_merger()
3630
3739
        tt = tree_merger.make_preview_transform()
3631
 
        try:
3632
 
            result_tree = tt.get_preview_tree()
3633
 
            show_diff_trees(merger.this_tree, result_tree, self.outf,
3634
 
                            old_label='', new_label='')
3635
 
        finally:
3636
 
            tt.finalize()
 
3740
        cleanups.append(tt.finalize)
 
3741
        result_tree = tt.get_preview_tree()
 
3742
        return result_tree
 
3743
 
 
3744
    def _do_preview(self, merger, cleanups):
 
3745
        from bzrlib.diff import show_diff_trees
 
3746
        result_tree = self._get_preview(merger, cleanups)
 
3747
        show_diff_trees(merger.this_tree, result_tree, self.outf,
 
3748
                        old_label='', new_label='')
3637
3749
 
3638
3750
    def _do_merge(self, merger, change_reporter, allow_pending, verified):
3639
3751
        merger.change_reporter = change_reporter
3647
3759
        else:
3648
3760
            return 0
3649
3761
 
 
3762
    def _do_interactive(self, merger, cleanups):
 
3763
        """Perform an interactive merge.
 
3764
 
 
3765
        This works by generating a preview tree of the merge, then using
 
3766
        Shelver to selectively remove the differences between the working tree
 
3767
        and the preview tree.
 
3768
        """
 
3769
        from bzrlib import shelf_ui
 
3770
        result_tree = self._get_preview(merger, cleanups)
 
3771
        writer = bzrlib.option.diff_writer_registry.get()
 
3772
        shelver = shelf_ui.Shelver(merger.this_tree, result_tree, destroy=True,
 
3773
                                   reporter=shelf_ui.ApplyReporter(),
 
3774
                                   diff_writer=writer(sys.stdout))
 
3775
        shelver.run()
 
3776
 
3650
3777
    def sanity_check_merger(self, merger):
3651
3778
        if (merger.show_base and
3652
3779
            not merger.merge_type is _mod_merge.Merge3Merger):
3687
3814
            base_branch, base_path = Branch.open_containing(base_loc,
3688
3815
                possible_transports)
3689
3816
        # Find the revision ids
3690
 
        if revision is None or len(revision) < 1 or revision[-1] is None:
 
3817
        other_revision_id = None
 
3818
        base_revision_id = None
 
3819
        if revision is not None:
 
3820
            if len(revision) >= 1:
 
3821
                other_revision_id = revision[-1].as_revision_id(other_branch)
 
3822
            if len(revision) == 2:
 
3823
                base_revision_id = revision[0].as_revision_id(base_branch)
 
3824
        if other_revision_id is None:
3691
3825
            other_revision_id = _mod_revision.ensure_null(
3692
3826
                other_branch.last_revision())
3693
 
        else:
3694
 
            other_revision_id = revision[-1].as_revision_id(other_branch)
3695
 
        if (revision is not None and len(revision) == 2
3696
 
            and revision[0] is not None):
3697
 
            base_revision_id = revision[0].as_revision_id(base_branch)
3698
 
        else:
3699
 
            base_revision_id = None
3700
3827
        # Remember where we merge from
3701
3828
        if ((remember or tree.branch.get_submit_branch() is None) and
3702
3829
             user_location is not None):
3711
3838
            allow_pending = True
3712
3839
        return merger, allow_pending
3713
3840
 
 
3841
    def get_merger_from_uncommitted(self, tree, location, pb, cleanups):
 
3842
        """Get a merger for uncommitted changes.
 
3843
 
 
3844
        :param tree: The tree the merger should apply to.
 
3845
        :param location: The location containing uncommitted changes.
 
3846
        :param pb: The progress bar to use for showing progress.
 
3847
        :param cleanups: A list of operations to perform to clean up the
 
3848
            temporary directories, unfinalized objects, etc.
 
3849
        """
 
3850
        location = self._select_branch_location(tree, location)[0]
 
3851
        other_tree, other_path = WorkingTree.open_containing(location)
 
3852
        merger = _mod_merge.Merger.from_uncommitted(tree, other_tree, pb)
 
3853
        if other_path != '':
 
3854
            merger.interesting_files = [other_path]
 
3855
        return merger
 
3856
 
3714
3857
    def _select_branch_location(self, tree, user_location, revision=None,
3715
3858
                                index=None):
3716
3859
        """Select a branch location, according to possible inputs.
4828
4971
 
4829
4972
    To use a specific mail program, set the mail_client configuration option.
4830
4973
    (For Thunderbird 1.5, this works around some bugs.)  Supported values for
4831
 
    specific clients are "claws", "evolution", "kmail", "mutt", and
4832
 
    "thunderbird"; generic options are "default", "editor", "emacsclient",
4833
 
    "mapi", and "xdg-email".  Plugins may also add supported clients.
 
4974
    specific clients are "claws", "evolution", "kmail", "mail.app" (MacOS X's
 
4975
    Mail.app), "mutt", and "thunderbird"; generic options are "default",
 
4976
    "editor", "emacsclient", "mapi", and "xdg-email".  Plugins may also add
 
4977
    supported clients.
4834
4978
 
4835
4979
    If mail is being sent, a to address is required.  This can be supplied
4836
4980
    either on the commandline, by setting the submit_to configuration
4869
5013
               help='Write merge directive to this file; '
4870
5014
                    'use - for stdout.',
4871
5015
               type=unicode),
 
5016
        Option('strict',
 
5017
               help='Refuse to send if there are uncommitted changes in'
 
5018
               ' the working tree, --no-strict disables the check.'),
4872
5019
        Option('mail-to', help='Mail the request to this address.',
4873
5020
               type=unicode),
4874
5021
        'revision',
4875
5022
        'message',
4876
5023
        Option('body', help='Body for the email.', type=unicode),
4877
5024
        RegistryOption('format',
4878
 
                       help='Use the specified output format.', 
4879
 
                       lazy_registry=('bzrlib.send', 'format_registry'))
 
5025
                       help='Use the specified output format.',
 
5026
                       lazy_registry=('bzrlib.send', 'format_registry')),
4880
5027
        ]
4881
5028
 
4882
5029
    def run(self, submit_branch=None, public_branch=None, no_bundle=False,
4883
5030
            no_patch=False, revision=None, remember=False, output=None,
4884
 
            format=None, mail_to=None, message=None, body=None, **kwargs):
 
5031
            format=None, mail_to=None, message=None, body=None,
 
5032
            strict=None, **kwargs):
4885
5033
        from bzrlib.send import send
4886
5034
        return send(submit_branch, revision, public_branch, remember,
4887
 
                         format, no_bundle, no_patch, output,
4888
 
                         kwargs.get('from', '.'), mail_to, message, body,
4889
 
                         self.outf)
 
5035
                    format, no_bundle, no_patch, output,
 
5036
                    kwargs.get('from', '.'), mail_to, message, body,
 
5037
                    self.outf,
 
5038
                    strict=strict)
4890
5039
 
4891
5040
 
4892
5041
class cmd_bundle_revisions(cmd_send):
4936
5085
               type=unicode),
4937
5086
        Option('output', short_name='o', help='Write directive to this file.',
4938
5087
               type=unicode),
 
5088
        Option('strict',
 
5089
               help='Refuse to bundle revisions if there are uncommitted'
 
5090
               ' changes in the working tree, --no-strict disables the check.'),
4939
5091
        'revision',
4940
5092
        RegistryOption('format',
4941
5093
                       help='Use the specified output format.',
4949
5101
 
4950
5102
    def run(self, submit_branch=None, public_branch=None, no_bundle=False,
4951
5103
            no_patch=False, revision=None, remember=False, output=None,
4952
 
            format=None, **kwargs):
 
5104
            format=None, strict=None, **kwargs):
4953
5105
        if output is None:
4954
5106
            output = '-'
4955
5107
        from bzrlib.send import send
4956
5108
        return send(submit_branch, revision, public_branch, remember,
4957
5109
                         format, no_bundle, no_patch, output,
4958
5110
                         kwargs.get('from', '.'), None, None, None,
4959
 
                         self.outf)
 
5111
                         self.outf, strict=strict)
4960
5112
 
4961
5113
 
4962
5114
class cmd_tag(Command):
5134
5286
            ),
5135
5287
        Option('bind-to', help='Branch to bind checkout to.', type=str),
5136
5288
        Option('force',
5137
 
               help='Perform reconfiguration even if local changes'
5138
 
               ' will be lost.')
 
5289
            help='Perform reconfiguration even if local changes'
 
5290
            ' will be lost.'),
 
5291
        Option('stacked-on',
 
5292
            help='Reconfigure a branch to be stacked on another branch.',
 
5293
            type=unicode,
 
5294
            ),
 
5295
        Option('unstacked',
 
5296
            help='Reconfigure a branch to be unstacked.  This '
 
5297
                'may require copying substantial data into it.',
 
5298
            ),
5139
5299
        ]
5140
5300
 
5141
 
    def run(self, location=None, target_type=None, bind_to=None, force=False):
 
5301
    def run(self, location=None, target_type=None, bind_to=None, force=False,
 
5302
            stacked_on=None,
 
5303
            unstacked=None):
5142
5304
        directory = bzrdir.BzrDir.open(location)
 
5305
        if stacked_on and unstacked:
 
5306
            raise BzrCommandError("Can't use both --stacked-on and --unstacked")
 
5307
        elif stacked_on is not None:
 
5308
            reconfigure.ReconfigureStackedOn().apply(directory, stacked_on)
 
5309
        elif unstacked:
 
5310
            reconfigure.ReconfigureUnstacked().apply(directory)
 
5311
        # At the moment you can use --stacked-on and a different
 
5312
        # reconfiguration shape at the same time; there seems no good reason
 
5313
        # to ban it.
5143
5314
        if target_type is None:
5144
 
            raise errors.BzrCommandError('No target configuration specified')
 
5315
            if stacked_on or unstacked:
 
5316
                return
 
5317
            else:
 
5318
                raise errors.BzrCommandError('No target configuration '
 
5319
                    'specified')
5145
5320
        elif target_type == 'branch':
5146
5321
            reconfiguration = reconfigure.Reconfigure.to_branch(directory)
5147
5322
        elif target_type == 'tree':
5190
5365
 
5191
5366
    takes_args = ['to_location']
5192
5367
    takes_options = [Option('force',
5193
 
                        help='Switch even if local commits will be lost.')
 
5368
                        help='Switch even if local commits will be lost.'),
 
5369
                     Option('create-branch', short_name='b',
 
5370
                        help='Create the target branch from this one before'
 
5371
                             ' switching to it.'),
5194
5372
                     ]
5195
5373
 
5196
 
    def run(self, to_location, force=False):
 
5374
    def run(self, to_location, force=False, create_branch=False):
5197
5375
        from bzrlib import switch
5198
5376
        tree_location = '.'
5199
5377
        control_dir = bzrdir.BzrDir.open_containing(tree_location)[0]
5201
5379
            branch = control_dir.open_branch()
5202
5380
            had_explicit_nick = branch.get_config().has_explicit_nickname()
5203
5381
        except errors.NotBranchError:
 
5382
            branch = None
5204
5383
            had_explicit_nick = False
5205
 
        try:
5206
 
            to_branch = Branch.open(to_location)
5207
 
        except errors.NotBranchError:
5208
 
            this_url = self._get_branch_location(control_dir)
5209
 
            to_branch = Branch.open(
5210
 
                urlutils.join(this_url, '..', to_location))
 
5384
        if create_branch:
 
5385
            if branch is None:
 
5386
                raise errors.BzrCommandError('cannot create branch without'
 
5387
                                             ' source branch')
 
5388
            if '/' not in to_location and '\\' not in to_location:
 
5389
                # This path is meant to be relative to the existing branch
 
5390
                this_url = self._get_branch_location(control_dir)
 
5391
                to_location = urlutils.join(this_url, '..', to_location)
 
5392
            to_branch = branch.bzrdir.sprout(to_location,
 
5393
                                 possible_transports=[branch.bzrdir.root_transport],
 
5394
                                 source_branch=branch).open_branch()
 
5395
            # try:
 
5396
            #     from_branch = control_dir.open_branch()
 
5397
            # except errors.NotBranchError:
 
5398
            #     raise BzrCommandError('Cannot create a branch from this'
 
5399
            #         ' location when we cannot open this branch')
 
5400
            # from_branch.bzrdir.sprout(
 
5401
            pass
 
5402
        else:
 
5403
            try:
 
5404
                to_branch = Branch.open(to_location)
 
5405
            except errors.NotBranchError:
 
5406
                this_url = self._get_branch_location(control_dir)
 
5407
                to_branch = Branch.open(
 
5408
                    urlutils.join(this_url, '..', to_location))
5211
5409
        switch.switch(control_dir, to_branch, force)
5212
5410
        if had_explicit_nick:
5213
5411
            branch = control_dir.open_branch() #get the new branch!
5456
5654
        if writer is None:
5457
5655
            writer = bzrlib.option.diff_writer_registry.get()
5458
5656
        try:
5459
 
            Shelver.from_args(writer(sys.stdout), revision, all, file_list,
5460
 
                              message, destroy=destroy).run()
 
5657
            shelver = Shelver.from_args(writer(sys.stdout), revision, all,
 
5658
                file_list, message, destroy=destroy)
 
5659
            try:
 
5660
                shelver.run()
 
5661
            finally:
 
5662
                shelver.work_tree.unlock()
5461
5663
        except errors.UserAbort:
5462
5664
            return 0
5463
5665
 
5502
5704
 
5503
5705
    def run(self, shelf_id=None, action='apply'):
5504
5706
        from bzrlib.shelf_ui import Unshelver
5505
 
        Unshelver.from_args(shelf_id, action).run()
 
5707
        unshelver = Unshelver.from_args(shelf_id, action)
 
5708
        try:
 
5709
            unshelver.run()
 
5710
        finally:
 
5711
            unshelver.tree.unlock()
5506
5712
 
5507
5713
 
5508
5714
class cmd_clean_tree(Command):