~abentley/bzrtools/bzrtools.dev

« back to all changes in this revision

Viewing changes to __init__.py

  • Committer: Aaron Bentley
  • Date: 2006-03-31 01:47:15 UTC
  • Revision ID: aaron.bentley@utoronto.ca-20060331014715-127c9cda9bbc1e6f
Strip trailing / from input location

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#!/usr/bin/python
 
2
"""\
 
3
Various useful plugins for working with bzr.
 
4
"""
 
5
import bzrlib.commands
 
6
import push
 
7
from errors import CommandError
 
8
from patchsource import BzrPatchSource
 
9
from shelf import Shelf
 
10
import sys
 
11
import os.path
 
12
from bzrlib.option import Option
 
13
import bzrlib.branch
 
14
from bzrlib.errors import BzrCommandError
 
15
sys.path.insert(0, os.path.realpath(os.path.join(os.path.dirname(__file__), 
 
16
                                                 "external")))
 
17
from bzrlib import DEFAULT_IGNORE
 
18
 
 
19
 
 
20
DEFAULT_IGNORE.append('./.shelf')
 
21
DEFAULT_IGNORE.append('./.bzr-shelf*')
 
22
 
 
23
 
 
24
Option.OPTIONS['ignored'] = Option('ignored',
 
25
        help='delete all ignored files.')
 
26
Option.OPTIONS['detritus'] = Option('detritus',
 
27
        help='delete conflict files merge backups, and failed selftest dirs.' +
 
28
              '(*.THIS, *.BASE, *.OTHER, *~, *.tmp')
 
29
Option.OPTIONS['dry-run'] = Option('dry-run',
 
30
        help='show files to delete instead of deleting them.')
 
31
 
 
32
class cmd_clean_tree(bzrlib.commands.Command):
 
33
    """Remove unwanted files from working tree.  <BZRTOOLS>
 
34
    Normally, ignored files are left alone.
 
35
    """
 
36
    takes_options = ['ignored', 'detritus', 'dry-run']
 
37
    def run(self, ignored=False, detritus=False, dry_run=False):
 
38
        from clean_tree import clean_tree
 
39
        clean_tree('.', ignored=ignored, detritus=detritus, dry_run=dry_run)
 
40
 
 
41
Option.OPTIONS['merge-branch'] = Option('merge-branch',type=str)
 
42
 
 
43
class cmd_graph_ancestry(bzrlib.commands.Command):
 
44
    """Produce ancestry graphs using dot.  <BZRTOOLS>
 
45
    
 
46
    Output format is detected according to file extension.  Some of the more
 
47
    common output formats are html, png, gif, svg, ps.  An extension of '.dot'
 
48
    will cause a dot graph file to be produced.  HTML output has mouseovers
 
49
    that show the commit message.
 
50
 
 
51
    Branches are labeled r?, where ? is the revno.  If they have no revno,
 
52
    with the last 5 characters of their revision identifier are used instead.
 
53
 
 
54
    The value starting with d is "(maximum) distance from the null revision".
 
55
    
 
56
    If --merge-branch is specified, the two branches are compared and a merge
 
57
    base is selected.
 
58
    
 
59
    Legend:
 
60
    white    normal revision
 
61
    yellow   THIS  history
 
62
    red      OTHER history
 
63
    orange   COMMON history
 
64
    blue     COMMON non-history ancestor
 
65
    green    Merge base (COMMON ancestor farthest from the null revision)
 
66
    dotted   Ghost revision (missing from branch storage)
 
67
 
 
68
    Ancestry is usually collapsed by skipping revisions with a single parent
 
69
    and descendant.  The number of skipped revisions is shown on the arrow.
 
70
    This feature can be disabled with --no-collapse.
 
71
 
 
72
    By default, revisions are ordered by distance from root, but they can be
 
73
    clustered instead using --cluster.
 
74
 
 
75
    If available, rsvg is used to antialias PNG and JPEG output, but this can
 
76
    be disabled with --no-antialias.
 
77
    """
 
78
    takes_args = ['branch', 'file']
 
79
    takes_options = [Option('no-collapse', help="Do not skip simple nodes"), 
 
80
                     Option('no-antialias',
 
81
                     help="Do not use rsvg to produce antialiased output"), 
 
82
                     Option('merge-branch', type=str, 
 
83
                     help="Use this branch to calcuate a merge base"), 
 
84
                     Option('cluster', help="Use clustered output.")]
 
85
    def run(self, branch, file, no_collapse=False, no_antialias=False,
 
86
        merge_branch=None, cluster=False):
 
87
        import graph
 
88
        if cluster:
 
89
            ranking = "cluster"
 
90
        else:
 
91
            ranking = "forced"
 
92
        graph.write_ancestry_file(branch, file, not no_collapse, 
 
93
                                  not no_antialias, merge_branch, ranking)
 
94
 
 
95
class cmd_fetch_ghosts(bzrlib.commands.Command):
 
96
    """Attempt to retrieve ghosts from another branch.  <BZRTOOLS>
 
97
    If the other branch is not supplied, the last-pulled branch is used.
 
98
    """
 
99
    aliases = ['fetch-missing']
 
100
    takes_args = ['branch?']
 
101
    takes_options = [Option('no-fix')]
 
102
    def run(self, branch=None, no_fix=False):
 
103
        from fetch_ghosts import fetch_ghosts
 
104
        fetch_ghosts(branch, no_fix)
 
105
 
 
106
strip_help="""Strip the smallest prefix containing num leading slashes  from \
 
107
each file name found in the patch file."""
 
108
Option.OPTIONS['strip'] = Option('strip', type=int, help=strip_help)
 
109
Option.OPTIONS['bzrdiff'] = Option('bzrdiff',type=None,
 
110
                                help="""Handle extra bzr tags""")
 
111
class cmd_patch(bzrlib.commands.Command):
 
112
    """Apply a named patch to the current tree.  <BZRTOOLS>
 
113
    """
 
114
    takes_args = ['filename?']
 
115
    takes_options = ['strip','bzrdiff']
 
116
    def run(self, filename=None, strip=-1, bzrdiff=0):
 
117
        from patch import patch
 
118
        from bzrlib.workingtree import WorkingTree
 
119
        wt = WorkingTree.open_containing('.')[0]
 
120
        if strip == -1:
 
121
            if bzrdiff: strip = 0
 
122
            else:       strip = 1
 
123
 
 
124
        return patch(wt, filename, strip, legacy= not bzrdiff)
 
125
 
 
126
class cmd_shelve(bzrlib.commands.Command):
 
127
    """Temporarily set aside some changes from the current tree.  <BZRTOOLS>
 
128
 
 
129
    Shelve allows you to temporarily put changes you've made "on the shelf",
 
130
    ie. out of the way, until a later time when you can bring them back from
 
131
    the shelf with the 'unshelve' command.
 
132
 
 
133
    Shelve is intended to help separate several sets of text changes that have
 
134
    been inappropriately mingled.  If you just want to get rid of all changes
 
135
    (text and otherwise) and you don't need to restore them later, use revert.
 
136
    If you want to shelve all text changes at once, use shelve --all.
 
137
 
 
138
    By default shelve asks you what you want to shelve, press '?' at the
 
139
    prompt to get help. To shelve everything run shelve --all.
 
140
 
 
141
    You can put multiple items on the shelf, each time you run unshelve the
 
142
    most recently shelved changes will be reinstated.
 
143
 
 
144
    If filenames are specified, only the changes to those files will be
 
145
    shelved, other files will be left untouched.
 
146
 
 
147
    If a revision is specified, changes since that revision will be shelved.
 
148
    """
 
149
 
 
150
    takes_args = ['file*']
 
151
    takes_options = ['message', 'revision',
 
152
            Option('all', help='Shelve all changes without prompting')]
 
153
 
 
154
    def run(self, all=False, file_list=None, message=None, revision=None):
 
155
        if revision is not None and revision:
 
156
            if len(revision) == 1:
 
157
                revision = revision[0]
 
158
            else:
 
159
                raise CommandError("shelve only accepts a single revision "
 
160
                                  "parameter.")
 
161
 
 
162
        source = BzrPatchSource(revision, file_list)
 
163
        s = Shelf(source.base)
 
164
        s.shelve(source, all, message)
 
165
        return 0
 
166
 
 
167
class cmd_shelf(bzrlib.commands.Command):
 
168
    """Perform various operations on your shelved patches. See also shelve.
 
169
 
 
170
    Subcommands:
 
171
        list   (ls)           List the patches on the current shelf.
 
172
        delete (del) <patch>  Delete a patch from the current shelf.
 
173
        switch       <shelf>  Switch to the named shelf, create it if necessary.
 
174
        show         <patch>  Show the contents of the specified patch.
 
175
        upgrade               Upgrade old format shelves.
 
176
    """
 
177
    takes_args = ['subcommand', 'args*']
 
178
 
 
179
    def run(self, subcommand, args_list):
 
180
        import sys
 
181
 
 
182
        source = BzrPatchSource()
 
183
        s = Shelf(source.base)
 
184
 
 
185
        if subcommand == 'ls' or subcommand == 'list':
 
186
            self.__check_no_args(args_list, "shelf list takes no arguments!")
 
187
            s.list()
 
188
        elif subcommand == 'delete' or subcommand == 'del':
 
189
            self.__check_one_arg(args_list, "shelf delete takes one argument!")
 
190
            s.delete(args_list[0])
 
191
        elif subcommand == 'switch':
 
192
            self.__check_one_arg(args_list, "shelf switch takes one argument!")
 
193
            s = Shelf(source.base, args_list[0])
 
194
            s.make_default()
 
195
        elif subcommand == 'show':
 
196
            self.__check_one_arg(args_list, "shelf show takes one argument!")
 
197
            s.display(args_list[0])
 
198
        elif subcommand == 'upgrade':
 
199
            self.__check_no_args(args_list, "shelf upgrade takes no arguments!")
 
200
            s.upgrade()
 
201
        else:
 
202
            print subcommand, args_list
 
203
            print >>sys.stderr, "Unknown shelf subcommand '%s'" % subcommand
 
204
 
 
205
    def __check_one_arg(self, args, msg):
 
206
        if args is None or len(args) != 1:
 
207
            raise CommandError(msg)
 
208
 
 
209
    def __check_no_args(self, args, msg):
 
210
        if args is not None:
 
211
            raise CommandError(msg)
 
212
 
 
213
 
 
214
class cmd_unshelve(bzrlib.commands.Command):
 
215
    """Restore the most recently shelved changes to current tree.  <BZRTOOLS>
 
216
    See 'shelve' for more information.
 
217
    """
 
218
    takes_options = [
 
219
            Option('all', help='Unshelve all changes without prompting'),
 
220
            Option('force', help='Force unshelving even if errors occur'),
 
221
    ]
 
222
    def run(self, all=False, force=False):
 
223
        source = BzrPatchSource()
 
224
        s = Shelf(source.base)
 
225
        s.unshelve(source, all, force)
 
226
        return 0
 
227
 
 
228
 
 
229
class cmd_shell(bzrlib.commands.Command):
 
230
    """Begin an interactive shell tailored for bzr.  <BZRTOOLS>
 
231
    Bzr commands can be used without typing bzr first, and will be run natively
 
232
    when possible.  Tab completion is tailored for bzr.  The shell prompt shows
 
233
    the branch nick, revno, and path.
 
234
 
 
235
    If it encounters any moderately complicated shell command, it will punt to
 
236
    the system shell.
 
237
 
 
238
    Example:
 
239
    $ bzr shell
 
240
    bzr bzrtools:287/> status
 
241
    modified:
 
242
      __init__.py
 
243
    bzr bzrtools:287/> status --[TAB][TAB]
 
244
    --all        --help       --revision   --show-ids
 
245
    bzr bzrtools:287/> status --
 
246
    """
 
247
    def run(self):
 
248
        import shell
 
249
        return shell.run_shell()
 
250
 
 
251
class cmd_branch_history(bzrlib.commands.Command):
 
252
    """\
 
253
    Display the development history of a branch  <BZRTOOLS>.
 
254
 
 
255
    Each different committer or branch nick is considered a different line of
 
256
    development.  Committers are treated as the same if they have the same
 
257
    name, or if they have the same email address.
 
258
    """
 
259
    takes_args = ["branch?"]
 
260
    def run(self, branch=None):
 
261
        from branchhistory import branch_history 
 
262
        return branch_history(branch)
 
263
 
 
264
 
 
265
class cmd_zap(bzrlib.commands.Command):
 
266
    """\
 
267
    Remove a checkout, if it can be done safely. <BZRTOOLS>
 
268
 
 
269
    This command will remove a checkout without losing data.  That means
 
270
    it only removes checkouts, and only if they have no uncommitted changes.
 
271
    """
 
272
    takes_options = [Option("branch", help="Remove associtated branch from"
 
273
                                           " repository")]
 
274
    takes_args = ["checkout"]
 
275
    def run(self, checkout, branch=False):
 
276
        from zap import zap
 
277
        return zap(checkout, remove_branch=branch)
 
278
 
 
279
 
 
280
class cmd_cbranch(bzrlib.commands.Command):
 
281
    """
 
282
    Create a new checkout, associated with a new repository branch. <BZRTOOLS>
 
283
    
 
284
    When you cbranch, bzr looks up the repository associated with your current
 
285
    directory in branches.conf.  It creates a new branch in that repository
 
286
    with the same name and relative path as the checkout you request.
 
287
 
 
288
    The branches.conf parameter is "cbranch_root".  So if you want 
 
289
    cbranch operations in /home/jrandom/bigproject to produce branches in 
 
290
    /home/jrandom/bigproject/repository, you'd add this:
 
291
 
 
292
    [/home/jrandom/bigproject]
 
293
    cbranch_root = /home/jrandom/bigproject/repository
 
294
 
 
295
    Note that if "/home/jrandom/bigproject/repository" isn't a repository,
 
296
    standalone branches will be produced.  Standalone branches will also
 
297
    be produced if the source branch is in 0.7 format (or earlier).
 
298
    """
 
299
    takes_options = [Option("lightweight", 
 
300
                            help="Create a lightweight checkout")]
 
301
    takes_args = ["source", "target?"]
 
302
    def run(self, source, target=None, lightweight=False):
 
303
        from cbranch import cbranch
 
304
        return cbranch(source, target, lightweight=lightweight)
 
305
 
 
306
 
 
307
class cmd_branches(bzrlib.commands.Command):
 
308
    """Scan a location for branches <BZRTOOLS>"""
 
309
    takes_args = ["location?"]
 
310
    def run(self, location=None):
 
311
        from branches import branches
 
312
        return branches(location)
 
313
 
 
314
 
 
315
class cmd_multi_pull(bzrlib.commands.Command):
 
316
    """Pull all the branches under a location, e.g. a repository. <BZRTOOLS>
 
317
    
 
318
    Both branches present in the directory and the branches of checkouts are
 
319
    pulled.
 
320
    """
 
321
    takes_args = ["location?"]
 
322
    def run(self, location=None):
 
323
        from bzrlib.branch import Branch
 
324
        from bzrlib.transport import get_transport
 
325
        from bzrtools import iter_branch_tree
 
326
        if location is None:
 
327
            location = '.'
 
328
        t = get_transport(location)
 
329
        if not t.listable():
 
330
            print "Can't list this type of location."
 
331
            return 3
 
332
        for branch, wt in iter_branch_tree(t):
 
333
            if wt is None:
 
334
                pullable = branch
 
335
            else:
 
336
                pullable = wt
 
337
            parent = branch.get_parent()
 
338
            if parent is None:
 
339
                continue
 
340
            if wt is not None:
 
341
                base = wt.basedir
 
342
            else:
 
343
                base = branch.base
 
344
            if base.startswith(t.base):
 
345
                relpath = base[len(t.base):].rstrip('/')
 
346
            else:
 
347
                relpath = base
 
348
            print "Pulling %s from %s" % (relpath, parent)
 
349
            try:
 
350
                pullable.pull(Branch.open(parent))
 
351
            except Exception, e:
 
352
                print e
 
353
 
 
354
 
 
355
commands = [cmd_shelve, cmd_unshelve, cmd_shelf, cmd_clean_tree,
 
356
            cmd_graph_ancestry, cmd_fetch_ghosts, cmd_patch, cmd_shell,
 
357
            cmd_branch_history, cmd_zap, cmd_cbranch, cmd_branches, 
 
358
            cmd_multi_pull]
 
359
 
 
360
 
 
361
command_decorators = []
 
362
 
 
363
 
 
364
import bzrlib.builtins
 
365
if not hasattr(bzrlib.builtins, "cmd_push"):
 
366
    commands.append(push.cmd_push)
 
367
else:
 
368
    command_decorators.append(push.cmd_push)
 
369
 
 
370
from errors import NoPyBaz
 
371
try:
 
372
    import baz_import
 
373
    commands.append(baz_import.cmd_baz_import_branch)
 
374
    commands.append(baz_import.cmd_baz_import)
 
375
 
 
376
except NoPyBaz:
 
377
    class cmd_baz_import_branch(bzrlib.commands.Command):
 
378
        """Disabled. (Requires PyBaz)   <BZRTOOLS>"""
 
379
        takes_args = ['to_location?', 'from_branch?', 'reuse_history*']
 
380
        takes_options = ['verbose', Option('max-count', type=int)]
 
381
        def run(self, to_location=None, from_branch=None, fast=False, 
 
382
                max_count=None, verbose=False, dry_run=False,
 
383
                reuse_history_list=[]):
 
384
            print "This command is disabled.  Please install PyBaz."
 
385
 
 
386
 
 
387
    class cmd_baz_import(bzrlib.commands.Command):
 
388
        """Disabled. (Requires PyBaz)   <BZRTOOLS>"""
 
389
        takes_args = ['to_root_dir?', 'from_archive?', 'reuse_history*']
 
390
        takes_options = ['verbose', Option('prefixes', type=str,
 
391
                         help="Prefixes of branches to import")]
 
392
        def run(self, to_root_dir=None, from_archive=None, verbose=False,
 
393
                reuse_history_list=[], prefixes=None):
 
394
                print "This command is disabled.  Please install PyBaz."
 
395
    commands.extend((cmd_baz_import_branch, cmd_baz_import))
 
396
 
 
397
 
 
398
if hasattr(bzrlib.commands, 'register_command'):
 
399
    for command in commands:
 
400
        bzrlib.commands.register_command(command)
 
401
    for command in command_decorators:
 
402
        command._original_command = bzrlib.commands.register_command(
 
403
            command, True)
 
404
 
 
405
 
 
406
def test_suite():
 
407
    import baz_import
 
408
    from bzrlib.tests.TestUtil import TestLoader
 
409
    import tests
 
410
    from doctest import DocTestSuite, ELLIPSIS
 
411
    from unittest import TestSuite
 
412
    import clean_tree
 
413
    import zap
 
414
    import tests.blackbox
 
415
    import tests.shelf_tests
 
416
    result = TestSuite()
 
417
    result.addTest(DocTestSuite(bzrtools, optionflags=ELLIPSIS))
 
418
    result.addTest(clean_tree.test_suite())
 
419
    result.addTest(DocTestSuite(baz_import))
 
420
    result.addTest(tests.test_suite())
 
421
    result.addTest(TestLoader().loadTestsFromModule(tests.shelf_tests))
 
422
    result.addTest(tests.blackbox.test_suite())
 
423
    result.addTest(zap.test_suite())
 
424
    return result