~abentley/bzrtools/bzrtools.dev

« back to all changes in this revision

Viewing changes to __init__.py

  • Committer: Aaron Bentley
  • Date: 2007-06-18 15:03:02 UTC
  • Revision ID: abentley@panoramicfeedback.com-20070618150302-u35gtfierenla4kx
remove references to python2.4

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
#!/usr/bin/python
2
 
"""Shelf - temporarily set aside changes, then bring them back."""
3
 
 
 
1
# Copyright (C) 2005, 2006, 2007 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
 
 
19
"""\
 
20
Various useful plugins for working with bzr.
 
21
"""
 
22
 
 
23
import bzrlib
 
24
 
 
25
 
 
26
__version__ = '0.18.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 or (bzrlib_version == desired_plus and
 
43
                                     bzrlib.version_info[3] == 'dev'):
 
44
        return
 
45
    try:
 
46
        from bzrlib.trace import warning
 
47
    except ImportError:
 
48
        # get the message out any way we can
 
49
        from warnings import warn as warning
 
50
    if bzrlib_version < desired:
 
51
        warning('Installed Bazaar version %s is too old to be used with'
 
52
                ' plugin \n'
 
53
                '"Bzrtools" %s.' % (bzrlib.__version__, __version__))
 
54
        # Not using BzrNewError, because it may not exist.
 
55
        raise Exception, ('Version mismatch', version_info)
 
56
    else:
 
57
        warning('Plugin "Bzrtools" is not up to date with installed Bazaar'
 
58
                ' version %s.\n'
 
59
                ' There should be a newer version of Bzrtools available, e.g.'
 
60
                ' %i.%i.'
 
61
                % (bzrlib.__version__, bzrlib_version[0], bzrlib_version[1]))
 
62
        if bzrlib_version != desired_plus:
 
63
            raise Exception, 'Version mismatch'
 
64
 
 
65
 
 
66
check_bzrlib_version(version_info[:2])
 
67
 
 
68
from bzrlib.lazy_import import lazy_import
 
69
lazy_import(globals(), """
 
70
from bzrlib import help
 
71
import shelf
 
72
""")
 
73
 
 
74
from errors import CommandError, NoPyBaz
 
75
from patchsource import BzrPatchSource
 
76
import sys
 
77
import os.path
 
78
 
 
79
import bzrlib.builtins
4
80
import bzrlib.commands
5
 
import bzrlib.branch
 
81
from bzrlib.commands import get_cmd_object
6
82
from bzrlib.errors import BzrCommandError
 
83
import bzrlib.ignores
7
84
from bzrlib.option import Option
8
 
from shelf import Shelf
 
85
sys.path.insert(0, os.path.realpath(os.path.join(os.path.dirname(__file__),
 
86
                                                 "external")))
 
87
 
 
88
import show_paths
 
89
 
 
90
bzrlib.ignores.add_runtime_ignores(['./.shelf'])
 
91
 
 
92
 
 
93
class cmd_clean_tree(bzrlib.commands.Command):
 
94
    """Remove unwanted files from working tree.
 
95
 
 
96
    By default, only unknown files, not ignored files, are deleted.  Versioned
 
97
    files are never deleted.
 
98
 
 
99
    Another class is 'detritus', which includes files emitted by bzr during
 
100
    normal operations and selftests.  (The value of these files decreases with
 
101
    time.)
 
102
 
 
103
    If no options are specified, unknown files are deleted.  Otherwise, option
 
104
    flags are respected, and may be combined.
 
105
 
 
106
    To check what clean-tree will do, use --dry-run.
 
107
    """
 
108
    takes_options = [Option('ignored', help='delete all ignored files.'),
 
109
                     Option('detritus', help='delete conflict files, merge'
 
110
                            ' backups, and failed selftest dirs.'),
 
111
                     Option('unknown',
 
112
                            help='delete files unknown to bzr.  (default)'),
 
113
                     Option('dry-run', help='show files to delete instead of'
 
114
                            ' deleting them.')]
 
115
    def run(self, unknown=False, ignored=False, detritus=False, dry_run=False):
 
116
        from clean_tree import clean_tree
 
117
        if not (unknown or ignored or detritus):
 
118
            unknown = True
 
119
        clean_tree('.', unknown=unknown, ignored=ignored, detritus=detritus, 
 
120
                   dry_run=dry_run)
 
121
 
 
122
 
 
123
class cmd_graph_ancestry(bzrlib.commands.Command):
 
124
    """Produce ancestry graphs using dot.
 
125
    
 
126
    Output format is detected according to file extension.  Some of the more
 
127
    common output formats are html, png, gif, svg, ps.  An extension of '.dot'
 
128
    will cause a dot graph file to be produced.  HTML output has mouseovers
 
129
    that show the commit message.
 
130
 
 
131
    Branches are labeled r?, where ? is the revno.  If they have no revno,
 
132
    with the last 5 characters of their revision identifier are used instead.
 
133
 
 
134
    The value starting with d is "(maximum) distance from the null revision".
 
135
 
 
136
    If --merge-branch is specified, the two branches are compared and a merge
 
137
    base is selected.
 
138
 
 
139
    Legend:
 
140
    white    normal revision
 
141
    yellow   THIS  history
 
142
    red      OTHER history
 
143
    orange   COMMON history
 
144
    blue     COMMON non-history ancestor
 
145
    green    Merge base (COMMON ancestor farthest from the null revision)
 
146
    dotted   Ghost revision (missing from branch storage)
 
147
 
 
148
    Ancestry is usually collapsed by skipping revisions with a single parent
 
149
    and descendant.  The number of skipped revisions is shown on the arrow.
 
150
    This feature can be disabled with --no-collapse.
 
151
 
 
152
    By default, revisions are ordered by distance from root, but they can be
 
153
    clustered instead using --cluster.
 
154
 
 
155
    If available, rsvg is used to antialias PNG and JPEG output, but this can
 
156
    be disabled with --no-antialias.
 
157
    """
 
158
    takes_args = ['file', 'merge-branch?']
 
159
    takes_options = [Option('no-collapse', help="Do not skip simple nodes"),
 
160
                     Option('no-antialias',
 
161
                     help="Do not use rsvg to produce antialiased output"),
 
162
                     Option('merge-branch', type=str,
 
163
                     help="Use this branch to calcuate a merge base"),
 
164
                     Option('cluster', help="Use clustered output."),
 
165
                     Option('max-distance',
 
166
                            help="Show no nodes farther than this", type=int),
 
167
                     Option('directory',
 
168
                            help='Source branch to use (default is current'
 
169
                            ' directory)',
 
170
                            short_name='d',
 
171
                            type=unicode),
 
172
                    ]
 
173
    def run(self, file, merge_branch, no_collapse=False, no_antialias=False,
 
174
        cluster=False, max_distance=100, directory='.'):
 
175
        if max_distance == -1:
 
176
            max_distance = None
 
177
        import graph
 
178
        if cluster:
 
179
            ranking = "cluster"
 
180
        else:
 
181
            ranking = "forced"
 
182
        graph.write_ancestry_file(directory, file, not no_collapse,
 
183
                                  not no_antialias, merge_branch, ranking,
 
184
                                  max_distance=max_distance)
 
185
 
 
186
 
 
187
class cmd_fetch_ghosts(bzrlib.commands.Command):
 
188
    """Attempt to retrieve ghosts from another branch.
 
189
    If the other branch is not supplied, the last-pulled branch is used.
 
190
    """
 
191
    aliases = ['fetch-missing']
 
192
    takes_args = ['branch?']
 
193
    takes_options = [Option('no-fix')]
 
194
    def run(self, branch=None, no_fix=False):
 
195
        from fetch_ghosts import fetch_ghosts
 
196
        fetch_ghosts(branch, no_fix)
 
197
 
 
198
strip_help="""Strip the smallest prefix containing num leading slashes  from \
 
199
each file name found in the patch file."""
 
200
 
 
201
 
 
202
class cmd_patch(bzrlib.commands.Command):
 
203
    """Apply a named patch to the current tree.
 
204
    """
 
205
    takes_args = ['filename?']
 
206
    takes_options = [Option('strip', type=int, help=strip_help),
 
207
                     Option('silent', help='Suppress chatter')]
 
208
    def run(self, filename=None, strip=None, silent=False):
 
209
        from patch import patch
 
210
        from bzrlib.workingtree import WorkingTree
 
211
        wt = WorkingTree.open_containing('.')[0]
 
212
        if strip is None:
 
213
            strip = 0
 
214
        return patch(wt, filename, strip, silent)
 
215
 
9
216
 
10
217
class cmd_shelve(bzrlib.commands.Command):
11
 
    """Temporarily set aside some changes to the current working tree.
 
218
    """Temporarily set aside some changes from the current tree.
12
219
 
13
220
    Shelve allows you to temporarily put changes you've made "on the shelf",
14
221
    ie. out of the way, until a later time when you can bring them back from
15
222
    the shelf with the 'unshelve' command.
16
223
 
17
 
    You can put multiple items on the shelf, each time you run unshelve the
18
 
    most recently shelved changes will be reinstated.
 
224
    Shelve is intended to help separate several sets of text changes that have
 
225
    been inappropriately mingled.  If you just want to get rid of all changes
 
226
    (text and otherwise) and you don't need to restore them later, use revert.
 
227
    If you want to shelve all text changes at once, use shelve --all.
 
228
 
 
229
    By default shelve asks you what you want to shelve, press '?' at the
 
230
    prompt to get help. To shelve everything run shelve --all.
19
231
 
20
232
    If filenames are specified, only the changes to those files will be
21
233
    shelved, other files will be left untouched.
22
234
 
23
235
    If a revision is specified, changes since that revision will be shelved.
24
236
 
25
 
    If you specifiy "--pick" you'll be prompted for each hunk of the diff as
26
 
    to whether you want to shelve it or not. Press "?" at the prompt for help.
 
237
    You can put multiple items on the shelf. Normally each time you run
 
238
    unshelve the most recently shelved changes will be reinstated. However,
 
239
    you can also unshelve changes in a different order by explicitly
 
240
    specifiying which changes to unshelve. This works best when the changes
 
241
    don't depend on each other.
 
242
 
 
243
    While you have patches on the shelf you can view and manipulate them with
 
244
    the 'shelf' command. Run 'bzr shelf -h' for more info.
27
245
    """
 
246
 
28
247
    takes_args = ['file*']
29
 
    takes_options = [Option('pick'), 'message', 'revision']
30
 
    def run(self, pick=False, file_list=None, message=None, revision=None):
31
 
        if file_list is not None and len(file_list) > 0:
32
 
            branchdir = file_list[0]
33
 
        else:
34
 
            branchdir = '.'
 
248
    takes_options = ['message', 'revision',
 
249
            Option('all', help='Shelve all changes without prompting'),
 
250
            Option('no-color', help='Never display changes in color')]
35
251
 
 
252
    def run(self, all=False, file_list=None, message=None, revision=None,
 
253
            no_color=False):
36
254
        if revision is not None and revision:
37
255
            if len(revision) == 1:
38
256
                revision = revision[0]
39
257
            else:
40
 
                raise BzrCommandError("shelve only accepts a single revision "
 
258
                raise CommandError("shelve only accepts a single revision "
41
259
                                  "parameter.")
42
260
 
43
 
        s = Shelf(branchdir)
44
 
        return s.shelve(pick, message, revision, file_list)
 
261
        source = BzrPatchSource(revision, file_list)
 
262
        s = shelf.Shelf(source.base)
 
263
        s.shelve(source, all, message, no_color)
 
264
        return 0
 
265
 
 
266
 
 
267
# The following classes are only used as subcommands for 'shelf', they're
 
268
# not to be registered directly with bzr.
 
269
 
 
270
class cmd_shelf_list(bzrlib.commands.Command):
 
271
    """List the patches on the current shelf."""
 
272
    aliases = ['list', 'ls']
 
273
    def run(self):
 
274
        self.shelf.list()
 
275
 
 
276
 
 
277
class cmd_shelf_delete(bzrlib.commands.Command):
 
278
    """Delete the patch from the current shelf."""
 
279
    aliases = ['delete', 'del']
 
280
    takes_args = ['patch']
 
281
    def run(self, patch):
 
282
        self.shelf.delete(patch)
 
283
 
 
284
 
 
285
class cmd_shelf_switch(bzrlib.commands.Command):
 
286
    """Switch to the other shelf, create it if necessary."""
 
287
    aliases = ['switch']
 
288
    takes_args = ['othershelf']
 
289
    def run(self, othershelf):
 
290
        s = shelf.Shelf(self.shelf.base, othershelf)
 
291
        s.make_default()
 
292
 
 
293
 
 
294
class cmd_shelf_show(bzrlib.commands.Command):
 
295
    """Show the contents of the specified or topmost patch."""
 
296
    aliases = ['show', 'cat', 'display']
 
297
    takes_args = ['patch?']
 
298
    def run(self, patch=None):
 
299
        self.shelf.display(patch)
 
300
 
 
301
 
 
302
class cmd_shelf_upgrade(bzrlib.commands.Command):
 
303
    """Upgrade old format shelves."""
 
304
    aliases = ['upgrade']
 
305
    def run(self):
 
306
        self.shelf.upgrade()
 
307
 
 
308
 
 
309
class cmd_shelf(bzrlib.commands.Command):
 
310
    """Perform various operations on your shelved patches. See also shelve."""
 
311
    takes_args = ['subcommand', 'args*']
 
312
 
 
313
    subcommands = [cmd_shelf_list, cmd_shelf_delete, cmd_shelf_switch,
 
314
        cmd_shelf_show, cmd_shelf_upgrade]
 
315
 
 
316
    def run(self, subcommand, args_list):
 
317
        import sys
 
318
 
 
319
        if args_list is None:
 
320
            args_list = []
 
321
        cmd = self._get_cmd_object(subcommand)
 
322
        source = BzrPatchSource()
 
323
        s = shelf.Shelf(source.base)
 
324
        cmd.shelf = s
 
325
 
 
326
        if args_list is None:
 
327
            args_list = []
 
328
        return cmd.run_argv_aliases(args_list)
 
329
 
 
330
    def _get_cmd_object(self, cmd_name):
 
331
        for cmd_class in self.subcommands:
 
332
            for alias in cmd_class.aliases:
 
333
                if alias == cmd_name:
 
334
                    return cmd_class()
 
335
        raise CommandError("Unknown shelf subcommand '%s'" % cmd_name)
 
336
 
 
337
    def help(self):
 
338
        text = ["%s\n\nSubcommands:\n" % self.__doc__]
 
339
 
 
340
        for cmd_class in self.subcommands:
 
341
            text.extend(self.sub_help(cmd_class) + ['\n'])
 
342
 
 
343
        return ''.join(text)
 
344
 
 
345
    def sub_help(self, cmd_class):
 
346
        text = []
 
347
        cmd_obj = cmd_class()
 
348
        indent = 2 * ' '
 
349
 
 
350
        usage = cmd_obj._usage()
 
351
        usage = usage.replace('bzr shelf-', '')
 
352
        text.append('%s%s\n' % (indent, usage))
 
353
 
 
354
        text.append('%s%s\n' % (2 * indent, cmd_class.__doc__))
 
355
 
 
356
        # Somewhat copied from bzrlib.help.help_on_command_options
 
357
        option_help = []
 
358
        for option_name, option in sorted(cmd_obj.options().items()):
 
359
            if option_name == 'help':
 
360
                continue
 
361
            option_help.append('%s--%s' % (3 * indent, option_name))
 
362
            if option.type is not None:
 
363
                option_help.append(' %s' % option.argname.upper())
 
364
            if option.short_name():
 
365
                option_help.append(', -%s' % option.short_name())
 
366
            option_help.append('%s%s\n' % (2 * indent, option.help))
 
367
 
 
368
        if len(option_help) > 0:
 
369
            text.append('%soptions:\n' % (2 * indent))
 
370
            text.extend(option_help)
 
371
 
 
372
        return text
 
373
 
45
374
 
46
375
class cmd_unshelve(bzrlib.commands.Command):
47
 
    """Reinstate the most recently shelved changes.
 
376
    """Restore shelved changes.
 
377
 
 
378
    By default the most recently shelved changes are restored. However if you
 
379
    specify a patch by name those changes will be restored instead.
 
380
 
48
381
    See 'shelve' for more information.
49
382
    """
50
 
    takes_options = [Option('pick')]
51
 
    def run(self, pick=False):
52
 
        s = Shelf('.')
53
 
        return s.unshelve(pick)
54
 
 
55
 
bzrlib.commands.register_command(cmd_shelve)
56
 
bzrlib.commands.register_command(cmd_unshelve)
 
383
    takes_options = [
 
384
            Option('all', help='Unshelve all changes without prompting'),
 
385
            Option('force', help='Force unshelving even if errors occur'),
 
386
            Option('no-color', help='Never display changes in color')
 
387
        ]
 
388
    takes_args = ['patch?']
 
389
    def run(self, patch=None, all=False, force=False, no_color=False):
 
390
        source = BzrPatchSource()
 
391
        s = shelf.Shelf(source.base)
 
392
        s.unshelve(source, patch, all, force, no_color)
 
393
        return 0
 
394
 
 
395
 
 
396
class cmd_shell(bzrlib.commands.Command):
 
397
    """Begin an interactive shell tailored for bzr.
 
398
    Bzr commands can be used without typing bzr first, and will be run natively
 
399
    when possible.  Tab completion is tailored for bzr.  The shell prompt shows
 
400
    the branch nick, revno, and path.
 
401
 
 
402
    If it encounters any moderately complicated shell command, it will punt to
 
403
    the system shell.
 
404
 
 
405
    Example:
 
406
    $ bzr shell
 
407
    bzr bzrtools:287/> status
 
408
    modified:
 
409
      __init__.py
 
410
    bzr bzrtools:287/> status --[TAB][TAB]
 
411
    --all        --help       --revision   --show-ids
 
412
    bzr bzrtools:287/> status --
 
413
    """
 
414
    def run(self):
 
415
        import shell
 
416
        return shell.run_shell()
 
417
 
 
418
 
 
419
class cmd_branch_history(bzrlib.commands.Command):
 
420
    """\
 
421
    Display the development history of a branch.
 
422
 
 
423
    Each different committer or branch nick is considered a different line of
 
424
    development.  Committers are treated as the same if they have the same
 
425
    name, or if they have the same email address.
 
426
    """
 
427
    takes_args = ["branch?"]
 
428
    def run(self, branch=None):
 
429
        from branchhistory import branch_history
 
430
        return branch_history(branch)
 
431
 
 
432
 
 
433
class cmd_zap(bzrlib.commands.Command):
 
434
    """\
 
435
    Remove a lightweight checkout, if it can be done safely.
 
436
 
 
437
    This command will remove a lightweight checkout without losing data.  That
 
438
    means it only removes lightweight checkouts, and only if they have no
 
439
    uncommitted changes.
 
440
 
 
441
    If --branch is specified, the branch will be deleted too, but only if the
 
442
    the branch has no new commits (relative to its parent).
 
443
    """
 
444
    takes_options = [Option("branch", help="Remove associtated branch from"
 
445
                                           " repository")]
 
446
    takes_args = ["checkout"]
 
447
    def run(self, checkout, branch=False):
 
448
        from zap import zap
 
449
        return zap(checkout, remove_branch=branch)
 
450
 
 
451
 
 
452
class cmd_cbranch(bzrlib.commands.Command):
 
453
    """
 
454
    Create a new checkout, associated with a new repository branch.
 
455
 
 
456
    When you cbranch, bzr looks up a target location in locations.conf, and
 
457
    creates the branch there.
 
458
 
 
459
    In your locations.conf, add the following lines:
 
460
    [/working_directory_root]
 
461
    cbranch_target = /branch_root
 
462
    cbranch_target:policy = appendpath
 
463
 
 
464
    This will mean that if you run "bzr cbranch foo/bar foo/baz" in the
 
465
    working directory root, the branch will be created in
 
466
    "/branch_root/foo/baz"
 
467
 
 
468
    NOTE: cbranch also supports "cbranch_root", but that behaviour is
 
469
    deprecated.
 
470
    """
 
471
    takes_options = [Option("lightweight",
 
472
                            help="Create a lightweight checkout"), 'revision']
 
473
    takes_args = ["source", "target?"]
 
474
    def run(self, source, target=None, lightweight=False, revision=None):
 
475
        from cbranch import cbranch
 
476
        return cbranch(source, target, lightweight=lightweight,
 
477
                       revision=revision)
 
478
 
 
479
 
 
480
class cmd_branches(bzrlib.commands.Command):
 
481
    """Scan a location for branches"""
 
482
    takes_args = ["location?"]
 
483
    def run(self, location=None):
 
484
        from branches import branches
 
485
        return branches(location)
 
486
 
 
487
 
 
488
class cmd_multi_pull(bzrlib.commands.Command):
 
489
    """Pull all the branches under a location, e.g. a repository.
 
490
 
 
491
    Both branches present in the directory and the branches of checkouts are
 
492
    pulled.
 
493
    """
 
494
    takes_args = ["location?"]
 
495
    def run(self, location=None):
 
496
        from bzrlib.branch import Branch
 
497
        from bzrlib.transport import get_transport
 
498
        from bzrtools import iter_branch_tree
 
499
        if location is None:
 
500
            location = '.'
 
501
        t = get_transport(location)
 
502
        if not t.listable():
 
503
            print "Can't list this type of location."
 
504
            return 3
 
505
        for branch, wt in iter_branch_tree(t):
 
506
            if wt is None:
 
507
                pullable = branch
 
508
            else:
 
509
                pullable = wt
 
510
            parent = branch.get_parent()
 
511
            if parent is None:
 
512
                continue
 
513
            if wt is not None:
 
514
                base = wt.basedir
 
515
            else:
 
516
                base = branch.base
 
517
            if base.startswith(t.base):
 
518
                relpath = base[len(t.base):].rstrip('/')
 
519
            else:
 
520
                relpath = base
 
521
            print "Pulling %s from %s" % (relpath, parent)
 
522
            try:
 
523
                pullable.pull(Branch.open(parent))
 
524
            except Exception, e:
 
525
                print e
 
526
 
 
527
 
 
528
class cmd_branch_mark(bzrlib.commands.Command):
 
529
    """
 
530
    Add, view or list branch markers <EXPERIMENTAL>
 
531
 
 
532
    To add a mark, do 'bzr branch-mark MARK'.
 
533
    To list marks, do 'bzr branch-mark' (this lists all marks for the branch's
 
534
    repository).
 
535
    To delete a mark, do 'bzr branch-mark --delete MARK'
 
536
 
 
537
    These marks can be used to track a branch's status.
 
538
    """
 
539
    takes_args = ['mark?', 'branch?']
 
540
    takes_options = [Option('delete', help='Delete this mark')]
 
541
    def run(self, mark=None, branch=None, delete=False):
 
542
        from branch_mark import branch_mark
 
543
        branch_mark(mark, branch, delete)
 
544
 
 
545
 
 
546
class cmd_import(bzrlib.commands.Command):
 
547
    """Import sources from a directory, tarball or zip file
 
548
 
 
549
    This command will import a directory, tarball or zip file into a bzr
 
550
    tree, replacing any versioned files already present.  If a directory is
 
551
    specified, it is used as the target.  If the directory does not exist, or
 
552
    is not versioned, it is created.
 
553
 
 
554
    Tarballs may be gzip or bzip2 compressed.  This is autodetected.
 
555
 
 
556
    If the tarball or zip has a single root directory, that directory is
 
557
    stripped when extracting the tarball.  This is not done for directories.
 
558
    """
 
559
 
 
560
    takes_args = ['source', 'tree?']
 
561
    def run(self, source, tree=None):
 
562
        from upstream_import import do_import
 
563
        do_import(source, tree)
 
564
 
 
565
 
 
566
class cmd_cdiff(bzrlib.commands.Command):
 
567
    """A color version of bzr's diff"""
 
568
    takes_args = property(lambda x: get_cmd_object('diff').takes_args)
 
569
 
 
570
    def _takes_options(self):
 
571
        options = list(get_cmd_object('diff').takes_options)
 
572
        options.append(Option('check-style',
 
573
            help='Warn if trailing whitespace or spurious changes have been'
 
574
                 ' added.'))
 
575
        return options
 
576
 
 
577
    takes_options = property(_takes_options)
 
578
 
 
579
    def run(self, check_style=False, *args, **kwargs):
 
580
        from colordiff import colordiff
 
581
        colordiff(check_style, *args, **kwargs)
 
582
 
 
583
 
 
584
class cmd_baz_import(bzrlib.commands.Command):
 
585
    """Import an Arch or Baz archive into a bzr repository.
 
586
 
 
587
    This command should be used on local archives (or mirrors) only.  It is
 
588
    quite slow on remote archives.
 
589
 
 
590
    reuse_history allows you to specify any previous imports you
 
591
    have done of different archives, which this archive has branches
 
592
    tagged from. This will dramatically reduce the time to convert
 
593
    the archive as it will not have to convert the history already
 
594
    converted in that other branch.
 
595
 
 
596
    If you specify prefixes, only branches whose names start with that prefix
 
597
    will be imported.  Skipped branches will be listed, so you can import any
 
598
    branches you missed by accident.  Here's an example of doing a partial
 
599
    import from thelove@canonical.com:
 
600
    bzr baz-import thelove thelove@canonical.com --prefixes dists:talloc-except
 
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_root_dir', 'from_archive', 'reuse_history*']
 
610
    takes_options = ['verbose', Option('prefixes', type=str,
 
611
                     help="Prefixes of branches to import, colon-separated"),
 
612
                     Option('encoding', type=str,
 
613
                     help='Force encoding to specified value.  See WARNING.')]
 
614
 
 
615
    def run(self, to_root_dir, from_archive, encoding=None, verbose=False,
 
616
            reuse_history_list=[], prefixes=None):
 
617
        from errors import NoPyBaz
 
618
        try:
 
619
            import baz_import
 
620
            baz_import.baz_import(to_root_dir, from_archive, encoding,
 
621
                                  verbose, reuse_history_list, prefixes)
 
622
        except NoPyBaz:
 
623
            print "This command is disabled.  Please install PyBaz."
 
624
 
 
625
 
 
626
class cmd_baz_import_branch(bzrlib.commands.Command):
 
627
    """Import an Arch or Baz branch into a bzr branch.
 
628
 
 
629
    WARNING: Encoding should not be specified unless necessary, because if you
 
630
    specify an encoding, your converted branch will not interoperate with
 
631
    independently-converted branches, unless the other branches were converted
 
632
    with exactly the same encoding.  Any encoding recognized by Python may
 
633
    be specified.  Aliases are not detected, so 'utf_8', 'U8', 'UTF' and 'utf8'
 
634
    are incompatible.
 
635
    """
 
636
    takes_args = ['to_location', 'from_branch?', 'reuse_history*']
 
637
    takes_options = ['verbose', Option('max-count', type=int),
 
638
                     Option('encoding', type=str,
 
639
                     help='Force encoding to specified value.  See WARNING.')]
 
640
 
 
641
    def run(self, to_location, from_branch=None, fast=False, max_count=None,
 
642
            encoding=None, verbose=False, dry_run=False,
 
643
            reuse_history_list=[]):
 
644
        from errors import NoPyBaz
 
645
        try:
 
646
            import baz_import
 
647
            baz_import.baz_import_branch(to_location, from_branch, fast,
 
648
                                         max_count, verbose, encoding, dry_run,
 
649
                                         reuse_history_list)
 
650
        except NoPyBaz:
 
651
            print "This command is disabled.  Please install PyBaz."
 
652
 
 
653
 
 
654
class cmd_rspush(bzrlib.commands.Command):
 
655
    """Upload this branch to another location using rsync.
 
656
 
 
657
    If no location is specified, the last-used location will be used.  To
 
658
    prevent dirty trees from being uploaded, rspush will error out if there are
 
659
    unknown files or local changes.  It will also error out if the upstream
 
660
    directory is non-empty and not an earlier version of the branch.
 
661
    """
 
662
    takes_args = ['location?']
 
663
    takes_options = [Option('overwrite', help='Ignore differences between'
 
664
                            ' branches and overwrite unconditionally'),
 
665
                     Option('no-tree', help='Do not push the working tree,'
 
666
                            ' just the .bzr.')]
 
667
 
 
668
    def run(self, location=None, overwrite=False, no_tree=False):
 
669
        from bzrlib import workingtree
 
670
        import bzrtools
 
671
        cur_branch = workingtree.WorkingTree.open_containing(".")[0]
 
672
        bzrtools.rspush(cur_branch, location, overwrite=overwrite,
 
673
                      working_tree=not no_tree)
 
674
 
 
675
 
 
676
class cmd_switch(bzrlib.commands.Command):
 
677
    """Set the branch of a lightweight checkout and update."""
 
678
 
 
679
    takes_args = ['to_location']
 
680
 
 
681
    def run(self, to_location):
 
682
        from switch import cmd_switch
 
683
        cmd_switch().run(to_location)
 
684
 
 
685
 
 
686
commands = [
 
687
            cmd_baz_import,
 
688
            cmd_baz_import_branch,
 
689
            cmd_branches,
 
690
            cmd_branch_history,
 
691
            cmd_branch_mark,
 
692
            cmd_cbranch,
 
693
            cmd_cdiff,
 
694
            cmd_clean_tree,
 
695
            cmd_fetch_ghosts,
 
696
            cmd_graph_ancestry,
 
697
            cmd_import,
 
698
            cmd_multi_pull,
 
699
            cmd_patch,
 
700
            cmd_rspush,
 
701
            cmd_shelf,
 
702
            cmd_shell,
 
703
            cmd_shelve,
 
704
            cmd_switch,
 
705
            cmd_unshelve,
 
706
            cmd_zap,
 
707
            ]
 
708
 
 
709
 
 
710
if hasattr(bzrlib.commands, 'register_command'):
 
711
    for command in commands:
 
712
        bzrlib.commands.register_command(command)
 
713
 
57
714
 
58
715
def test_suite():
59
716
    from bzrlib.tests.TestUtil import TestLoader
60
717
    import tests
61
 
    return TestLoader().loadTestsFromModule(tests)
 
718
    from doctest import DocTestSuite, ELLIPSIS
 
719
    from unittest import TestSuite
 
720
    import bzrtools
 
721
    import tests.clean_tree
 
722
    import tests.is_clean
 
723
    import tests.upstream_import
 
724
    import zap
 
725
    import tests.blackbox
 
726
    import tests.shelf_tests
 
727
    result = TestSuite()
 
728
    result.addTest(DocTestSuite(bzrtools, optionflags=ELLIPSIS))
 
729
    result.addTest(tests.clean_tree.test_suite())
 
730
    try:
 
731
        import baz_import
 
732
        result.addTest(DocTestSuite(baz_import))
 
733
    except NoPyBaz:
 
734
        pass
 
735
    result.addTest(tests.test_suite())
 
736
    result.addTest(TestLoader().loadTestsFromModule(tests.shelf_tests))
 
737
    result.addTest(tests.blackbox.test_suite())
 
738
    result.addTest(tests.upstream_import.test_suite())
 
739
    result.addTest(zap.test_suite())
 
740
    result.addTest(TestLoader().loadTestsFromModule(tests.is_clean))
 
741
    return result