~abentley/bzrtools/bzrtools.dev

« back to all changes in this revision

Viewing changes to __init__.py

  • Committer: Michael Ellerman
  • Date: 2005-11-28 08:53:15 UTC
  • mto: (0.3.1 shelf-dev) (325.1.2 bzrtools)
  • mto: This revision was merged to the branch mainline in revision 334.
  • Revision ID: michael@ellerman.id.au-20051128085315-a955739cb6304e9b
Ask "shelve this change" instead of "keep this change", which is hopefully
more intuitive. Change the wording of some prompts for clarity.

Show diffs side-by-side

added added

removed removed

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