~abentley/bzrtools/bzrtools.dev

« back to all changes in this revision

Viewing changes to __init__.py

  • Committer: Aaron Bentley
  • Date: 2006-06-18 01:39:32 UTC
  • Revision ID: aaron.bentley@utoronto.ca-20060618013932-0162fdb3edab394b
Update is_clean test, now that commit returns a revision_id

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005, 2006 Aaron Bentley <aaron.bentley@utoronto.ca>
2
 
# Copyright (C) 2005, 2006 Canonical Limited.
3
 
# Copyright (C) 2006 Michael Ellerman.
4
 
#
5
 
#    This program is free software; you can redistribute it and/or modify
6
 
#    it under the terms of the GNU General Public License as published by
7
 
#    the Free Software Foundation; either version 2 of the License, or
8
 
#    (at your option) any later version.
9
 
#
10
 
#    This program is distributed in the hope that it will be useful,
11
 
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
 
#    GNU General Public License for more details.
14
 
#
15
 
#    You should have received a copy of the GNU General Public License
16
 
#    along with this program; if not, write to the Free Software
17
 
#    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18
 
 
 
1
#!/usr/bin/python
19
2
"""\
20
3
Various useful plugins for working with bzr.
21
4
"""
22
 
 
23
 
import bzrlib
24
 
 
25
 
 
26
 
__version__ = '0.14.0'
27
 
 
28
 
 
29
 
version_info = tuple(int(n) for n in __version__.split('.'))
30
 
 
31
 
 
32
 
def check_bzrlib_version(desired):
33
 
    """Check that bzrlib is compatible.
34
 
 
35
 
    If version is < bzrtools version, assume incompatible.
36
 
    If version == bzrtools version, assume completely compatible
37
 
    If version == bzrtools version + 1, assume compatible, with deprecations
38
 
    Otherwise, assume incompatible.
39
 
    """
40
 
    desired_plus = (desired[0], desired[1]+1)
41
 
    bzrlib_version = bzrlib.version_info[:2]
42
 
    if bzrlib_version == desired:
43
 
        return
44
 
    try:
45
 
        from bzrlib.trace import warning
46
 
    except ImportError:
47
 
        # get the message out any way we can
48
 
        from warnings import warn as warning
49
 
    if bzrlib_version < desired:
50
 
        warning('Installed bzr version %s is too old to be used with bzrtools'
51
 
                ' %s.' % (bzrlib.__version__, __version__))
52
 
        # Not using BzrNewError, because it may not exist.
53
 
        raise Exception, ('Version mismatch', version_info)
54
 
    else:
55
 
        warning('Bzrtools is not up to date with installed bzr version %s.'
56
 
                ' \nThere should be a newer version available, e.g. %i.%i.' 
57
 
                % (bzrlib.__version__, bzrlib_version[0], bzrlib_version[1]))
58
 
        if bzrlib_version != desired_plus:
59
 
            raise Exception, 'Version mismatch'
60
 
 
61
 
 
62
 
check_bzrlib_version(version_info[:2])
63
 
 
64
 
 
65
 
from errors import CommandError, NoPyBaz
 
5
import bzrlib.commands
 
6
import rspush
 
7
from errors import CommandError
66
8
from patchsource import BzrPatchSource
67
9
from shelf import Shelf
 
10
from switch import cmd_switch
68
11
import sys
69
12
import os.path
70
 
 
71
 
import bzrlib.builtins
72
 
import bzrlib.commands
73
 
from bzrlib.commands import get_cmd_object
 
13
from bzrlib.option import Option
 
14
import bzrlib.branch
74
15
from bzrlib.errors import BzrCommandError
75
 
from bzrlib.help import command_usage
76
 
import bzrlib.ignores
77
 
from bzrlib.option import Option
78
16
sys.path.insert(0, os.path.realpath(os.path.join(os.path.dirname(__file__), 
79
17
                                                 "external")))
80
 
 
81
 
import show_paths
82
 
 
83
 
bzrlib.ignores.add_runtime_ignores(['./.shelf'])
 
18
from bzrlib import DEFAULT_IGNORE
 
19
from bzrlib.help import command_usage
 
20
 
 
21
 
 
22
DEFAULT_IGNORE.append('./.shelf')
 
23
DEFAULT_IGNORE.append('./.bzr-shelf*')
84
24
 
85
25
 
86
26
class cmd_clean_tree(bzrlib.commands.Command):
87
 
    """Remove unwanted files from working tree.
88
 
 
89
 
    By default, only unknown files, not ignored files, are deleted.  Versioned
90
 
    files are never deleted.
91
 
 
92
 
    Another class is 'detritus', which includes files emitted by bzr during
93
 
    normal operations and selftests.  (The value of these files decreases with
94
 
    time.)
95
 
 
96
 
    If no options are specified, unknown files are deleted.  Otherwise, option
97
 
    flags are respected, and may be combined.
98
 
 
99
 
    To check what clean-tree will do, use --dry-run.
 
27
    """Remove unwanted files from working tree.  <BZRTOOLS>
 
28
    Normally, ignored files are left alone.
100
29
    """
101
30
    takes_options = [Option('ignored', help='delete all ignored files.'), 
102
 
                     Option('detritus', help='delete conflict files, merge'
103
 
                            ' backups, and failed selftest dirs.'), 
104
 
                     Option('unknown', 
105
 
                            help='delete files unknown to bzr.  (default)'),
 
31
                     Option('detritus', help='delete conflict files merge'
 
32
                            ' backups, and failed selftest dirs.  (*.THIS, '
 
33
                            '*.BASE, *.OTHER, *~, *.tmp)'), 
106
34
                     Option('dry-run', help='show files to delete instead of'
107
35
                            ' deleting them.')]
108
 
    def run(self, unknown=False, ignored=False, detritus=False, dry_run=False):
 
36
    def run(self, ignored=False, detritus=False, dry_run=False):
109
37
        from clean_tree import clean_tree
110
 
        if not (unknown or ignored or detritus):
111
 
            unknown = True
112
 
        clean_tree('.', unknown=unknown, ignored=ignored, detritus=detritus, 
113
 
                   dry_run=dry_run)
114
 
 
 
38
        clean_tree('.', ignored=ignored, detritus=detritus, dry_run=dry_run)
115
39
 
116
40
class cmd_graph_ancestry(bzrlib.commands.Command):
117
 
    """Produce ancestry graphs using dot.
 
41
    """Produce ancestry graphs using dot.  <BZRTOOLS>
118
42
    
119
43
    Output format is detected according to file extension.  Some of the more
120
44
    common output formats are html, png, gif, svg, ps.  An extension of '.dot'
165
89
        graph.write_ancestry_file(branch, file, not no_collapse, 
166
90
                                  not no_antialias, merge_branch, ranking)
167
91
 
168
 
 
169
92
class cmd_fetch_ghosts(bzrlib.commands.Command):
170
 
    """Attempt to retrieve ghosts from another branch.
 
93
    """Attempt to retrieve ghosts from another branch.  <BZRTOOLS>
171
94
    If the other branch is not supplied, the last-pulled branch is used.
172
95
    """
173
96
    aliases = ['fetch-missing']
181
104
each file name found in the patch file."""
182
105
Option.OPTIONS['bzrdiff'] = Option('bzrdiff',type=None,
183
106
                                help="""Handle extra bzr tags""")
184
 
 
185
 
 
186
107
class cmd_patch(bzrlib.commands.Command):
187
 
    """Apply a named patch to the current tree.
 
108
    """Apply a named patch to the current tree.  <BZRTOOLS>
188
109
    """
189
110
    takes_args = ['filename?']
190
111
    takes_options = [Option('strip', type=int, help=strip_help)]
198
119
 
199
120
        return patch(wt, filename, strip, legacy= not bzrdiff)
200
121
 
201
 
 
202
122
class cmd_shelve(bzrlib.commands.Command):
203
 
    """Temporarily set aside some changes from the current tree.
 
123
    """Temporarily set aside some changes from the current tree.  <BZRTOOLS>
204
124
 
205
125
    Shelve allows you to temporarily put changes you've made "on the shelf",
206
126
    ie. out of the way, until a later time when you can bring them back from
224
144
    you can also unshelve changes in a different order by explicitly
225
145
    specifiying which changes to unshelve. This works best when the changes
226
146
    don't depend on each other.
227
 
 
228
 
    While you have patches on the shelf you can view and manipulate them with
229
 
    the 'shelf' command. Run 'bzr shelf -h' for more info.
230
147
    """
231
148
 
232
149
    takes_args = ['file*']
233
150
    takes_options = ['message', 'revision',
234
 
            Option('all', help='Shelve all changes without prompting'), 
235
 
            Option('no-color', help='Never display changes in color')]
 
151
            Option('all', help='Shelve all changes without prompting')]
236
152
 
237
 
    def run(self, all=False, file_list=None, message=None, revision=None,
238
 
            no_color=False):
 
153
    def run(self, all=False, file_list=None, message=None, revision=None):
239
154
        if revision is not None and revision:
240
155
            if len(revision) == 1:
241
156
                revision = revision[0]
245
160
 
246
161
        source = BzrPatchSource(revision, file_list)
247
162
        s = Shelf(source.base)
248
 
        s.shelve(source, all, message, no_color)
 
163
        s.shelve(source, all, message)
249
164
        return 0
250
165
 
251
166
 
301
216
    def run(self, subcommand, args_list):
302
217
        import sys
303
218
 
304
 
        if args_list is None:
305
 
            args_list = []
306
219
        cmd = self._get_cmd_object(subcommand)
307
220
        source = BzrPatchSource()
308
221
        s = Shelf(source.base)
354
267
        return text
355
268
 
356
269
 
 
270
 
357
271
class cmd_unshelve(bzrlib.commands.Command):
358
 
    """Restore shelved changes.
 
272
    """Restore shelved changes.  <BZRTOOLS>
359
273
 
360
274
    By default the most recently shelved changes are restored. However if you
361
275
    specify a patch by name those changes will be restored instead.
365
279
    takes_options = [
366
280
            Option('all', help='Unshelve all changes without prompting'),
367
281
            Option('force', help='Force unshelving even if errors occur'),
368
 
            Option('no-color', help='Never display changes in color')
369
 
        ]
 
282
    ]
370
283
    takes_args = ['patch?']
371
 
    def run(self, patch=None, all=False, force=False, no_color=False):
 
284
    def run(self, patch=None, all=False, force=False):
372
285
        source = BzrPatchSource()
373
286
        s = Shelf(source.base)
374
 
        s.unshelve(source, patch, all, force, no_color)
 
287
        s.unshelve(source, patch, all, force)
375
288
        return 0
376
289
 
377
290
 
378
291
class cmd_shell(bzrlib.commands.Command):
379
 
    """Begin an interactive shell tailored for bzr.
 
292
    """Begin an interactive shell tailored for bzr.  <BZRTOOLS>
380
293
    Bzr commands can be used without typing bzr first, and will be run natively
381
294
    when possible.  Tab completion is tailored for bzr.  The shell prompt shows
382
295
    the branch nick, revno, and path.
397
310
        import shell
398
311
        return shell.run_shell()
399
312
 
400
 
 
401
313
class cmd_branch_history(bzrlib.commands.Command):
402
314
    """\
403
 
    Display the development history of a branch.
 
315
    Display the development history of a branch  <BZRTOOLS>.
404
316
 
405
317
    Each different committer or branch nick is considered a different line of
406
318
    development.  Committers are treated as the same if they have the same
414
326
 
415
327
class cmd_zap(bzrlib.commands.Command):
416
328
    """\
417
 
    Remove a lightweight checkout, if it can be done safely.
418
 
 
419
 
    This command will remove a lightweight checkout without losing data.  That
420
 
    means it only removes lightweight checkouts, and only if they have no
421
 
    uncommitted changes.
422
 
 
423
 
    If --branch is specified, the branch will be deleted too, but only if the
424
 
    the branch has no new commits (relative to its parent).
 
329
    Remove a checkout, if it can be done safely. <BZRTOOLS>
 
330
 
 
331
    This command will remove a checkout without losing data.  That means
 
332
    it only removes checkouts, and only if they have no uncommitted changes.
425
333
    """
426
334
    takes_options = [Option("branch", help="Remove associtated branch from"
427
335
                                           " repository")]
433
341
 
434
342
class cmd_cbranch(bzrlib.commands.Command):
435
343
    """
436
 
    Create a new checkout, associated with a new repository branch.
 
344
    Create a new checkout, associated with a new repository branch. <BZRTOOLS>
437
345
    
438
346
    When you cbranch, bzr looks up the repository associated with your current
439
 
    directory in locations.conf.  It creates a new branch in that repository
 
347
    directory in branches.conf.  It creates a new branch in that repository
440
348
    with the same name and relative path as the checkout you request.
441
349
 
442
 
    The locations.conf parameter is "cbranch_root".  So if you want 
 
350
    The branches.conf parameter is "cbranch_root".  So if you want 
443
351
    cbranch operations in /home/jrandom/bigproject to produce branches in 
444
352
    /home/jrandom/bigproject/repository, you'd add this:
445
353
 
451
359
    be produced if the source branch is in 0.7 format (or earlier).
452
360
    """
453
361
    takes_options = [Option("lightweight", 
454
 
                            help="Create a lightweight checkout"), 'revision']
 
362
                            help="Create a lightweight checkout")]
455
363
    takes_args = ["source", "target?"]
456
 
    def run(self, source, target=None, lightweight=False, revision=None):
 
364
    def run(self, source, target=None, lightweight=False):
457
365
        from cbranch import cbranch
458
 
        return cbranch(source, target, lightweight=lightweight, 
459
 
                       revision=revision)
 
366
        return cbranch(source, target, lightweight=lightweight)
460
367
 
461
368
 
462
369
class cmd_branches(bzrlib.commands.Command):
463
 
    """Scan a location for branches"""
 
370
    """Scan a location for branches <BZRTOOLS>"""
464
371
    takes_args = ["location?"]
465
372
    def run(self, location=None):
466
373
        from branches import branches
468
375
 
469
376
 
470
377
class cmd_multi_pull(bzrlib.commands.Command):
471
 
    """Pull all the branches under a location, e.g. a repository.
 
378
    """Pull all the branches under a location, e.g. a repository. <BZRTOOLS>
472
379
    
473
380
    Both branches present in the directory and the branches of checkouts are
474
381
    pulled.
524
431
        from branch_mark import branch_mark
525
432
        branch_mark(mark, branch, delete)
526
433
 
527
 
 
528
434
class cmd_import(bzrlib.commands.Command):
529
 
    """Import sources from a tarball
 
435
    """Import sources from a tarball <BZRTOOLS>
530
436
    
531
437
    This command will import a tarball into a bzr tree, replacing any versioned
532
438
    files already present.  If a directory is specified, it is used as the
544
450
        from upstream_import import do_import
545
451
        do_import(source, tree)
546
452
 
547
 
 
548
 
class cmd_cdiff(bzrlib.commands.Command):
549
 
    """A color version of bzr's diff"""
550
 
    takes_args = property(lambda x: get_cmd_object('diff').takes_args)
551
 
    takes_options = property(lambda x: get_cmd_object('diff').takes_options)
552
 
    def run(*args, **kwargs):
553
 
        from colordiff import colordiff
554
 
        colordiff(*args, **kwargs)
555
 
 
556
 
 
557
 
class cmd_baz_import(bzrlib.commands.Command):
558
 
    """Import an Arch or Baz archive into a bzr repository.
559
 
 
560
 
    This command should be used on local archives (or mirrors) only.  It is
561
 
    quite slow on remote archives.
 
453
class cmd_shove(bzrlib.commands.Command):
 
454
    """Apply uncommitted changes to another tree <BZRTOOLS>
562
455
    
563
 
    reuse_history allows you to specify any previous imports you 
564
 
    have done of different archives, which this archive has branches
565
 
    tagged from. This will dramatically reduce the time to convert 
566
 
    the archive as it will not have to convert the history already
567
 
    converted in that other branch.
568
 
 
569
 
    If you specify prefixes, only branches whose names start with that prefix
570
 
    will be imported.  Skipped branches will be listed, so you can import any
571
 
    branches you missed by accident.  Here's an example of doing a partial
572
 
    import from thelove@canonical.com:
573
 
    bzr baz-import thelove thelove@canonical.com --prefixes dists:talloc-except
574
 
 
575
 
    WARNING: Encoding should not be specified unless necessary, because if you
576
 
    specify an encoding, your converted branch will not interoperate with
577
 
    independently-converted branches, unless the other branches were converted
578
 
    with exactly the same encoding.  Any encoding recognized by Python may
579
 
    be specified.  Aliases are not detected, so 'utf_8', 'U8', 'UTF' and 'utf8'
580
 
    are incompatible.
581
 
    """
582
 
    takes_args = ['to_root_dir', 'from_archive', 'reuse_history*']
583
 
    takes_options = ['verbose', Option('prefixes', type=str,
584
 
                     help="Prefixes of branches to import, colon-separated"),
585
 
                     Option('encoding', type=str, 
586
 
                     help='Force encoding to specified value.  See WARNING.')]
587
 
 
588
 
    def run(self, to_root_dir, from_archive, encoding=None, verbose=False,
589
 
            reuse_history_list=[], prefixes=None):
590
 
        from errors import NoPyBaz
591
 
        try:
592
 
            import baz_import
593
 
            baz_import.baz_import(to_root_dir, from_archive, encoding,
594
 
                                  verbose, reuse_history_list, prefixes)
595
 
        except NoPyBaz:
596
 
            print "This command is disabled.  Please install PyBaz."
597
 
 
598
 
 
599
 
class cmd_baz_import_branch(bzrlib.commands.Command):
600
 
    """Import an Arch or Baz branch into a bzr branch.
601
 
 
602
 
    WARNING: Encoding should not be specified unless necessary, because if you
603
 
    specify an encoding, your converted branch will not interoperate with
604
 
    independently-converted branches, unless the other branches were converted
605
 
    with exactly the same encoding.  Any encoding recognized by Python may
606
 
    be specified.  Aliases are not detected, so 'utf_8', 'U8', 'UTF' and 'utf8'
607
 
    are incompatible.
608
 
    """
609
 
    takes_args = ['to_location', 'from_branch?', 'reuse_history*']
610
 
    takes_options = ['verbose', Option('max-count', type=int),
611
 
                     Option('encoding', type=str, 
612
 
                     help='Force encoding to specified value.  See WARNING.')]
613
 
 
614
 
    def run(self, to_location, from_branch=None, fast=False, max_count=None,
615
 
            encoding=None, verbose=False, dry_run=False,
616
 
            reuse_history_list=[]):
617
 
        from errors import NoPyBaz
618
 
        try:
619
 
            import baz_import
620
 
            baz_import.baz_import_branch(to_location, from_branch, fast, 
621
 
                                         max_count, verbose, encoding, dry_run,
622
 
                                         reuse_history_list)
623
 
        except NoPyBaz:
624
 
            print "This command is disabled.  Please install PyBaz."
625
 
 
626
 
 
627
 
class cmd_rspush(bzrlib.commands.Command):
628
 
    """Upload this branch to another location using rsync.
629
 
 
630
 
    If no location is specified, the last-used location will be used.  To 
631
 
    prevent dirty trees from being uploaded, rspush will error out if there are 
632
 
    unknown files or local changes.  It will also error out if the upstream 
633
 
    directory is non-empty and not an earlier version of the branch. 
634
 
    """
635
 
    takes_args = ['location?']
636
 
    takes_options = [Option('overwrite', help='Ignore differences between'
637
 
                            ' branches and overwrite unconditionally'),
638
 
                     Option('no-tree', help='Do not push the working tree,'
639
 
                            ' just the .bzr.')]
640
 
 
641
 
    def run(self, location=None, overwrite=False, no_tree=False):
642
 
        from bzrlib import workingtree
643
 
        import bzrtools
644
 
        cur_branch = workingtree.WorkingTree.open_containing(".")[0]
645
 
        bzrtools.rspush(cur_branch, location, overwrite=overwrite, 
646
 
                      working_tree=not no_tree)
647
 
 
648
 
 
649
 
class cmd_switch(bzrlib.commands.Command):
650
 
    """Set the branch of a lightweight checkout and update."""
651
 
 
652
 
    takes_args = ['to_location']
653
 
 
654
 
    def run(self, to_location):
655
 
        from switch import cmd_switch
656
 
        cmd_switch().run(to_location)
657
 
 
658
 
 
659
 
commands = [
660
 
            cmd_baz_import,
661
 
            cmd_baz_import_branch,
662
 
            cmd_branches,
663
 
            cmd_branch_history,
664
 
            cmd_branch_mark,
665
 
            cmd_cbranch,  
666
 
            cmd_cdiff,
667
 
            cmd_clean_tree,
668
 
            cmd_fetch_ghosts,
669
 
            cmd_graph_ancestry,
670
 
            cmd_import,
671
 
            cmd_multi_pull,
672
 
            cmd_patch,
673
 
            cmd_rspush,
674
 
            cmd_shelf, 
675
 
            cmd_shell,
676
 
            cmd_shelve, 
677
 
            cmd_switch,
678
 
            cmd_unshelve, 
679
 
            cmd_zap,            
680
 
            ]
 
456
    This is useful when you start to make changes in one tree, then realize
 
457
    they should really be done in a different tree.
 
458
 
 
459
    Shove is implemented using merge, so:
 
460
     - All changes, including renames and adds, will be applied.
 
461
     - No changes that have already been applied will be applied.
 
462
     - If the target is significantly different from the source, conflicts may
 
463
       be produced.
 
464
    """
 
465
 
 
466
    takes_args = ['target', 'source?']
 
467
    def run(self, target, source='.'):
 
468
        from shove import do_shove
 
469
        do_shove(source, target)
 
470
 
 
471
 
 
472
commands = [cmd_shelve, cmd_unshelve, cmd_shelf, cmd_clean_tree,
 
473
            cmd_graph_ancestry, cmd_fetch_ghosts, cmd_patch, cmd_shell,
 
474
            cmd_branch_history, cmd_zap, cmd_cbranch, cmd_branches, 
 
475
            cmd_multi_pull, cmd_switch, cmd_branch_mark, cmd_import, cmd_shove]
 
476
 
 
477
 
 
478
import bzrlib.builtins
 
479
commands.append(rspush.cmd_rspush)
 
480
 
 
481
from errors import NoPyBaz
 
482
try:
 
483
    import baz_import
 
484
    commands.append(baz_import.cmd_baz_import_branch)
 
485
    commands.append(baz_import.cmd_baz_import)
 
486
 
 
487
except NoPyBaz:
 
488
    class cmd_baz_import_branch(bzrlib.commands.Command):
 
489
        """Disabled. (Requires PyBaz)   <BZRTOOLS>"""
 
490
        takes_args = ['to_location?', 'from_branch?', 'reuse_history*']
 
491
        takes_options = ['verbose', Option('max-count', type=int)]
 
492
        def run(self, to_location=None, from_branch=None, fast=False, 
 
493
                max_count=None, verbose=False, dry_run=False,
 
494
                reuse_history_list=[]):
 
495
            print "This command is disabled.  Please install PyBaz."
 
496
 
 
497
 
 
498
    class cmd_baz_import(bzrlib.commands.Command):
 
499
        """Disabled. (Requires PyBaz)   <BZRTOOLS>"""
 
500
        takes_args = ['to_root_dir?', 'from_archive?', 'reuse_history*']
 
501
        takes_options = ['verbose', Option('prefixes', type=str,
 
502
                         help="Prefixes of branches to import")]
 
503
        def run(self, to_root_dir=None, from_archive=None, verbose=False,
 
504
                reuse_history_list=[], prefixes=None):
 
505
                print "This command is disabled.  Please install PyBaz."
 
506
    commands.extend((cmd_baz_import_branch, cmd_baz_import))
681
507
 
682
508
 
683
509
if hasattr(bzrlib.commands, 'register_command'):
690
516
    import tests
691
517
    from doctest import DocTestSuite, ELLIPSIS
692
518
    from unittest import TestSuite
693
 
    import bzrtools
694
519
    import tests.clean_tree
695
520
    import upstream_import
696
521
    import zap