/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to bzrlib/builtins.py

  • Committer: John Arbash Meinel
  • Date: 2007-02-08 23:40:24 UTC
  • mto: This revision was merged to the branch mainline in revision 2278.
  • Revision ID: john@arbash-meinel.com-20070208234024-w1s6kqucpdckj42i
Cleanup docstring for Aaron Bentley

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# Copyright (C) 2004, 2005, 2006 Canonical Ltd
 
2
#
 
3
# This program is free software; you can redistribute it and/or modify
 
4
# it under the terms of the GNU General Public License as published by
 
5
# the Free Software Foundation; either version 2 of the License, or
 
6
# (at your option) any later version.
 
7
#
 
8
# This program is distributed in the hope that it will be useful,
 
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
11
# GNU General Public License for more details.
 
12
#
 
13
# You should have received a copy of the GNU General Public License
 
14
# along with this program; if not, write to the Free Software
 
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
16
 
 
17
"""builtin bzr commands"""
 
18
 
 
19
import os
 
20
 
 
21
from bzrlib.lazy_import import lazy_import
 
22
lazy_import(globals(), """
 
23
import codecs
 
24
import errno
 
25
import sys
 
26
import tempfile
 
27
 
 
28
import bzrlib
 
29
from bzrlib import (
 
30
    branch,
 
31
    bundle,
 
32
    bzrdir,
 
33
    delta,
 
34
    config,
 
35
    errors,
 
36
    ignores,
 
37
    log,
 
38
    merge as _mod_merge,
 
39
    osutils,
 
40
    repository,
 
41
    symbol_versioning,
 
42
    transport,
 
43
    tree as _mod_tree,
 
44
    ui,
 
45
    urlutils,
 
46
    )
 
47
from bzrlib.branch import Branch
 
48
from bzrlib.bundle.apply_bundle import install_bundle, merge_bundle
 
49
from bzrlib.conflicts import ConflictList
 
50
from bzrlib.revision import common_ancestor
 
51
from bzrlib.revisionspec import RevisionSpec
 
52
from bzrlib.workingtree import WorkingTree
 
53
""")
 
54
 
 
55
from bzrlib.commands import Command, display_command
 
56
from bzrlib.option import Option, RegistryOption
 
57
from bzrlib.progress import DummyProgress, ProgressPhase
 
58
from bzrlib.trace import mutter, note, log_error, warning, is_quiet, info
 
59
 
 
60
 
 
61
def tree_files(file_list, default_branch=u'.'):
 
62
    try:
 
63
        return internal_tree_files(file_list, default_branch)
 
64
    except errors.FileInWrongBranch, e:
 
65
        raise errors.BzrCommandError("%s is not in the same branch as %s" %
 
66
                                     (e.path, file_list[0]))
 
67
 
 
68
 
 
69
# XXX: Bad function name; should possibly also be a class method of
 
70
# WorkingTree rather than a function.
 
71
def internal_tree_files(file_list, default_branch=u'.'):
 
72
    """Convert command-line paths to a WorkingTree and relative paths.
 
73
 
 
74
    This is typically used for command-line processors that take one or
 
75
    more filenames, and infer the workingtree that contains them.
 
76
 
 
77
    The filenames given are not required to exist.
 
78
 
 
79
    :param file_list: Filenames to convert.  
 
80
 
 
81
    :param default_branch: Fallback tree path to use if file_list is empty or
 
82
        None.
 
83
 
 
84
    :return: workingtree, [relative_paths]
 
85
    """
 
86
    if file_list is None or len(file_list) == 0:
 
87
        return WorkingTree.open_containing(default_branch)[0], file_list
 
88
    tree = WorkingTree.open_containing(osutils.realpath(file_list[0]))[0]
 
89
    new_list = []
 
90
    for filename in file_list:
 
91
        try:
 
92
            new_list.append(tree.relpath(osutils.dereference_path(filename)))
 
93
        except errors.PathNotChild:
 
94
            raise errors.FileInWrongBranch(tree.branch, filename)
 
95
    return tree, new_list
 
96
 
 
97
 
 
98
@symbol_versioning.deprecated_function(symbol_versioning.zero_fifteen)
 
99
def get_format_type(typestring):
 
100
    """Parse and return a format specifier."""
 
101
    # Have to use BzrDirMetaFormat1 directly, so that
 
102
    # RepositoryFormat.set_default_format works
 
103
    if typestring == "default":
 
104
        return bzrdir.BzrDirMetaFormat1()
 
105
    try:
 
106
        return bzrdir.format_registry.make_bzrdir(typestring)
 
107
    except KeyError:
 
108
        msg = 'Unknown bzr format "%s". See "bzr help formats".' % typestring
 
109
        raise errors.BzrCommandError(msg)
 
110
 
 
111
 
 
112
# TODO: Make sure no commands unconditionally use the working directory as a
 
113
# branch.  If a filename argument is used, the first of them should be used to
 
114
# specify the branch.  (Perhaps this can be factored out into some kind of
 
115
# Argument class, representing a file in a branch, where the first occurrence
 
116
# opens the branch?)
 
117
 
 
118
class cmd_status(Command):
 
119
    """Display status summary.
 
120
 
 
121
    This reports on versioned and unknown files, reporting them
 
122
    grouped by state.  Possible states are:
 
123
 
 
124
    added
 
125
        Versioned in the working copy but not in the previous revision.
 
126
 
 
127
    removed
 
128
        Versioned in the previous revision but removed or deleted
 
129
        in the working copy.
 
130
 
 
131
    renamed
 
132
        Path of this file changed from the previous revision;
 
133
        the text may also have changed.  This includes files whose
 
134
        parent directory was renamed.
 
135
 
 
136
    modified
 
137
        Text has changed since the previous revision.
 
138
 
 
139
    kind changed
 
140
        File kind has been changed (e.g. from file to directory).
 
141
 
 
142
    unknown
 
143
        Not versioned and not matching an ignore pattern.
 
144
 
 
145
    To see ignored files use 'bzr ignored'.  For details in the
 
146
    changes to file texts, use 'bzr diff'.
 
147
    
 
148
    --short gives a status flags for each item, similar to the SVN's status
 
149
    command.
 
150
 
 
151
    Column 1: versioning / renames
 
152
      + File versioned
 
153
      - File unversioned
 
154
      R File renamed
 
155
      ? File unknown
 
156
      C File has conflicts
 
157
      P Entry for a pending merge (not a file)
 
158
 
 
159
    Column 2: Contents
 
160
      N File created
 
161
      D File deleted
 
162
      K File kind changed
 
163
      M File modified
 
164
 
 
165
    Column 3: Execute
 
166
      * The execute bit was changed
 
167
 
 
168
    If no arguments are specified, the status of the entire working
 
169
    directory is shown.  Otherwise, only the status of the specified
 
170
    files or directories is reported.  If a directory is given, status
 
171
    is reported for everything inside that directory.
 
172
 
 
173
    If a revision argument is given, the status is calculated against
 
174
    that revision, or between two revisions if two are provided.
 
175
    """
 
176
    
 
177
    # TODO: --no-recurse, --recurse options
 
178
    
 
179
    takes_args = ['file*']
 
180
    takes_options = ['show-ids', 'revision', 'short']
 
181
    aliases = ['st', 'stat']
 
182
 
 
183
    encoding_type = 'replace'
 
184
    
 
185
    @display_command
 
186
    def run(self, show_ids=False, file_list=None, revision=None, short=False):
 
187
        from bzrlib.status import show_tree_status
 
188
 
 
189
        tree, file_list = tree_files(file_list)
 
190
            
 
191
        show_tree_status(tree, show_ids=show_ids,
 
192
                         specific_files=file_list, revision=revision,
 
193
                         to_file=self.outf,
 
194
                         short=short)
 
195
 
 
196
 
 
197
class cmd_cat_revision(Command):
 
198
    """Write out metadata for a revision.
 
199
    
 
200
    The revision to print can either be specified by a specific
 
201
    revision identifier, or you can use --revision.
 
202
    """
 
203
 
 
204
    hidden = True
 
205
    takes_args = ['revision_id?']
 
206
    takes_options = ['revision']
 
207
    # cat-revision is more for frontends so should be exact
 
208
    encoding = 'strict'
 
209
    
 
210
    @display_command
 
211
    def run(self, revision_id=None, revision=None):
 
212
 
 
213
        if revision_id is not None and revision is not None:
 
214
            raise errors.BzrCommandError('You can only supply one of'
 
215
                                         ' revision_id or --revision')
 
216
        if revision_id is None and revision is None:
 
217
            raise errors.BzrCommandError('You must supply either'
 
218
                                         ' --revision or a revision_id')
 
219
        b = WorkingTree.open_containing(u'.')[0].branch
 
220
 
 
221
        # TODO: jam 20060112 should cat-revision always output utf-8?
 
222
        if revision_id is not None:
 
223
            self.outf.write(b.repository.get_revision_xml(revision_id).decode('utf-8'))
 
224
        elif revision is not None:
 
225
            for rev in revision:
 
226
                if rev is None:
 
227
                    raise errors.BzrCommandError('You cannot specify a NULL'
 
228
                                                 ' revision.')
 
229
                revno, rev_id = rev.in_history(b)
 
230
                self.outf.write(b.repository.get_revision_xml(rev_id).decode('utf-8'))
 
231
    
 
232
 
 
233
class cmd_remove_tree(Command):
 
234
    """Remove the working tree from a given branch/checkout.
 
235
 
 
236
    Since a lightweight checkout is little more than a working tree
 
237
    this will refuse to run against one.
 
238
    """
 
239
 
 
240
    hidden = True
 
241
 
 
242
    takes_args = ['location?']
 
243
 
 
244
    def run(self, location='.'):
 
245
        d = bzrdir.BzrDir.open(location)
 
246
        
 
247
        try:
 
248
            working = d.open_workingtree()
 
249
        except errors.NoWorkingTree:
 
250
            raise errors.BzrCommandError("No working tree to remove")
 
251
        except errors.NotLocalUrl:
 
252
            raise errors.BzrCommandError("You cannot remove the working tree of a "
 
253
                                         "remote path")
 
254
        
 
255
        working_path = working.bzrdir.root_transport.base
 
256
        branch_path = working.branch.bzrdir.root_transport.base
 
257
        if working_path != branch_path:
 
258
            raise errors.BzrCommandError("You cannot remove the working tree from "
 
259
                                         "a lightweight checkout")
 
260
        
 
261
        d.destroy_workingtree()
 
262
        
 
263
 
 
264
class cmd_revno(Command):
 
265
    """Show current revision number.
 
266
 
 
267
    This is equal to the number of revisions on this branch.
 
268
    """
 
269
 
 
270
    takes_args = ['location?']
 
271
 
 
272
    @display_command
 
273
    def run(self, location=u'.'):
 
274
        self.outf.write(str(Branch.open_containing(location)[0].revno()))
 
275
        self.outf.write('\n')
 
276
 
 
277
 
 
278
class cmd_revision_info(Command):
 
279
    """Show revision number and revision id for a given revision identifier.
 
280
    """
 
281
    hidden = True
 
282
    takes_args = ['revision_info*']
 
283
    takes_options = ['revision']
 
284
 
 
285
    @display_command
 
286
    def run(self, revision=None, revision_info_list=[]):
 
287
 
 
288
        revs = []
 
289
        if revision is not None:
 
290
            revs.extend(revision)
 
291
        if revision_info_list is not None:
 
292
            for rev in revision_info_list:
 
293
                revs.append(RevisionSpec.from_string(rev))
 
294
        if len(revs) == 0:
 
295
            raise errors.BzrCommandError('You must supply a revision identifier')
 
296
 
 
297
        b = WorkingTree.open_containing(u'.')[0].branch
 
298
 
 
299
        for rev in revs:
 
300
            revinfo = rev.in_history(b)
 
301
            if revinfo.revno is None:
 
302
                print '     %s' % revinfo.rev_id
 
303
            else:
 
304
                print '%4d %s' % (revinfo.revno, revinfo.rev_id)
 
305
 
 
306
    
 
307
class cmd_add(Command):
 
308
    """Add specified files or directories.
 
309
 
 
310
    In non-recursive mode, all the named items are added, regardless
 
311
    of whether they were previously ignored.  A warning is given if
 
312
    any of the named files are already versioned.
 
313
 
 
314
    In recursive mode (the default), files are treated the same way
 
315
    but the behaviour for directories is different.  Directories that
 
316
    are already versioned do not give a warning.  All directories,
 
317
    whether already versioned or not, are searched for files or
 
318
    subdirectories that are neither versioned or ignored, and these
 
319
    are added.  This search proceeds recursively into versioned
 
320
    directories.  If no names are given '.' is assumed.
 
321
 
 
322
    Therefore simply saying 'bzr add' will version all files that
 
323
    are currently unknown.
 
324
 
 
325
    Adding a file whose parent directory is not versioned will
 
326
    implicitly add the parent, and so on up to the root. This means
 
327
    you should never need to explicitly add a directory, they'll just
 
328
    get added when you add a file in the directory.
 
329
 
 
330
    --dry-run will show which files would be added, but not actually 
 
331
    add them.
 
332
 
 
333
    --file-ids-from will try to use the file ids from the supplied path.
 
334
    It looks up ids trying to find a matching parent directory with the
 
335
    same filename, and then by pure path.
 
336
    """
 
337
    takes_args = ['file*']
 
338
    takes_options = ['no-recurse', 'dry-run', 'verbose',
 
339
                     Option('file-ids-from', type=unicode,
 
340
                            help='Lookup file ids from here')]
 
341
    encoding_type = 'replace'
 
342
 
 
343
    def run(self, file_list, no_recurse=False, dry_run=False, verbose=False,
 
344
            file_ids_from=None):
 
345
        import bzrlib.add
 
346
 
 
347
        if file_ids_from is not None:
 
348
            try:
 
349
                base_tree, base_path = WorkingTree.open_containing(
 
350
                                            file_ids_from)
 
351
            except errors.NoWorkingTree:
 
352
                base_branch, base_path = Branch.open_containing(
 
353
                                            file_ids_from)
 
354
                base_tree = base_branch.basis_tree()
 
355
 
 
356
            action = bzrlib.add.AddFromBaseAction(base_tree, base_path,
 
357
                          to_file=self.outf, should_print=(not is_quiet()))
 
358
        else:
 
359
            action = bzrlib.add.AddAction(to_file=self.outf,
 
360
                should_print=(not is_quiet()))
 
361
 
 
362
        added, ignored = bzrlib.add.smart_add(file_list, not no_recurse,
 
363
                                              action=action, save=not dry_run)
 
364
        if len(ignored) > 0:
 
365
            if verbose:
 
366
                for glob in sorted(ignored.keys()):
 
367
                    for path in ignored[glob]:
 
368
                        self.outf.write("ignored %s matching \"%s\"\n" 
 
369
                                        % (path, glob))
 
370
            else:
 
371
                match_len = 0
 
372
                for glob, paths in ignored.items():
 
373
                    match_len += len(paths)
 
374
                self.outf.write("ignored %d file(s).\n" % match_len)
 
375
            self.outf.write("If you wish to add some of these files,"
 
376
                            " please add them by name.\n")
 
377
 
 
378
 
 
379
class cmd_mkdir(Command):
 
380
    """Create a new versioned directory.
 
381
 
 
382
    This is equivalent to creating the directory and then adding it.
 
383
    """
 
384
 
 
385
    takes_args = ['dir+']
 
386
    encoding_type = 'replace'
 
387
 
 
388
    def run(self, dir_list):
 
389
        for d in dir_list:
 
390
            os.mkdir(d)
 
391
            wt, dd = WorkingTree.open_containing(d)
 
392
            wt.add([dd])
 
393
            self.outf.write('added %s\n' % d)
 
394
 
 
395
 
 
396
class cmd_relpath(Command):
 
397
    """Show path of a file relative to root"""
 
398
 
 
399
    takes_args = ['filename']
 
400
    hidden = True
 
401
    
 
402
    @display_command
 
403
    def run(self, filename):
 
404
        # TODO: jam 20050106 Can relpath return a munged path if
 
405
        #       sys.stdout encoding cannot represent it?
 
406
        tree, relpath = WorkingTree.open_containing(filename)
 
407
        self.outf.write(relpath)
 
408
        self.outf.write('\n')
 
409
 
 
410
 
 
411
class cmd_inventory(Command):
 
412
    """Show inventory of the current working copy or a revision.
 
413
 
 
414
    It is possible to limit the output to a particular entry
 
415
    type using the --kind option.  For example: --kind file.
 
416
 
 
417
    It is also possible to restrict the list of files to a specific
 
418
    set. For example: bzr inventory --show-ids this/file
 
419
    """
 
420
 
 
421
    takes_options = ['revision', 'show-ids', 'kind']
 
422
    takes_args = ['file*']
 
423
 
 
424
    @display_command
 
425
    def run(self, revision=None, show_ids=False, kind=None, file_list=None):
 
426
        if kind and kind not in ['file', 'directory', 'symlink']:
 
427
            raise errors.BzrCommandError('invalid kind specified')
 
428
 
 
429
        work_tree, file_list = tree_files(file_list)
 
430
 
 
431
        if revision is not None:
 
432
            if len(revision) > 1:
 
433
                raise errors.BzrCommandError('bzr inventory --revision takes'
 
434
                                             ' exactly one revision identifier')
 
435
            revision_id = revision[0].in_history(work_tree.branch).rev_id
 
436
            tree = work_tree.branch.repository.revision_tree(revision_id)
 
437
                        
 
438
            # We include work_tree as well as 'tree' here
 
439
            # So that doing '-r 10 path/foo' will lookup whatever file
 
440
            # exists now at 'path/foo' even if it has been renamed, as
 
441
            # well as whatever files existed in revision 10 at path/foo
 
442
            trees = [tree, work_tree]
 
443
        else:
 
444
            tree = work_tree
 
445
            trees = [tree]
 
446
 
 
447
        if file_list is not None:
 
448
            file_ids = _mod_tree.find_ids_across_trees(file_list, trees,
 
449
                                                      require_versioned=True)
 
450
            # find_ids_across_trees may include some paths that don't
 
451
            # exist in 'tree'.
 
452
            entries = sorted((tree.id2path(file_id), tree.inventory[file_id])
 
453
                             for file_id in file_ids if file_id in tree)
 
454
        else:
 
455
            entries = tree.inventory.entries()
 
456
 
 
457
        for path, entry in entries:
 
458
            if kind and kind != entry.kind:
 
459
                continue
 
460
            if show_ids:
 
461
                self.outf.write('%-50s %s\n' % (path, entry.file_id))
 
462
            else:
 
463
                self.outf.write(path)
 
464
                self.outf.write('\n')
 
465
 
 
466
 
 
467
class cmd_mv(Command):
 
468
    """Move or rename a file.
 
469
 
 
470
    usage:
 
471
        bzr mv OLDNAME NEWNAME
 
472
        bzr mv SOURCE... DESTINATION
 
473
 
 
474
    If the last argument is a versioned directory, all the other names
 
475
    are moved into it.  Otherwise, there must be exactly two arguments
 
476
    and the file is changed to a new name.
 
477
 
 
478
    If OLDNAME does not exist on the filesystem but is versioned and
 
479
    NEWNAME does exist on the filesystem but is not versioned, mv
 
480
    assumes that the file has been manually moved and only updates
 
481
    its internal inventory to reflect that change.
 
482
    The same is valid when moving many SOURCE files to a DESTINATION.
 
483
 
 
484
    Files cannot be moved between branches.
 
485
    """
 
486
 
 
487
    takes_args = ['names*']
 
488
    takes_options = [Option("after", help="move only the bzr identifier"
 
489
        " of the file (file has already been moved). Use this flag if"
 
490
        " bzr is not able to detect this itself.")]
 
491
    aliases = ['move', 'rename']
 
492
    encoding_type = 'replace'
 
493
 
 
494
    def run(self, names_list, after=False):
 
495
        if names_list is None:
 
496
            names_list = []
 
497
 
 
498
        if len(names_list) < 2:
 
499
            raise errors.BzrCommandError("missing file argument")
 
500
        tree, rel_names = tree_files(names_list)
 
501
        
 
502
        if os.path.isdir(names_list[-1]):
 
503
            # move into existing directory
 
504
            for pair in tree.move(rel_names[:-1], rel_names[-1], after=after):
 
505
                self.outf.write("%s => %s\n" % pair)
 
506
        else:
 
507
            if len(names_list) != 2:
 
508
                raise errors.BzrCommandError('to mv multiple files the'
 
509
                                             ' destination must be a versioned'
 
510
                                             ' directory')
 
511
            tree.rename_one(rel_names[0], rel_names[1], after=after)
 
512
            self.outf.write("%s => %s\n" % (rel_names[0], rel_names[1]))
 
513
            
 
514
    
 
515
class cmd_pull(Command):
 
516
    """Turn this branch into a mirror of another branch.
 
517
 
 
518
    This command only works on branches that have not diverged.  Branches are
 
519
    considered diverged if the destination branch's most recent commit is one
 
520
    that has not been merged (directly or indirectly) into the parent.
 
521
 
 
522
    If branches have diverged, you can use 'bzr merge' to integrate the changes
 
523
    from one into the other.  Once one branch has merged, the other should
 
524
    be able to pull it again.
 
525
 
 
526
    If you want to forget your local changes and just update your branch to
 
527
    match the remote one, use pull --overwrite.
 
528
 
 
529
    If there is no default location set, the first pull will set it.  After
 
530
    that, you can omit the location to use the default.  To change the
 
531
    default, use --remember. The value will only be saved if the remote
 
532
    location can be accessed.
 
533
    """
 
534
 
 
535
    takes_options = ['remember', 'overwrite', 'revision', 'verbose']
 
536
    takes_args = ['location?']
 
537
    encoding_type = 'replace'
 
538
 
 
539
    def run(self, location=None, remember=False, overwrite=False, revision=None, verbose=False):
 
540
        # FIXME: too much stuff is in the command class
 
541
        try:
 
542
            tree_to = WorkingTree.open_containing(u'.')[0]
 
543
            branch_to = tree_to.branch
 
544
        except errors.NoWorkingTree:
 
545
            tree_to = None
 
546
            branch_to = Branch.open_containing(u'.')[0]
 
547
 
 
548
        reader = None
 
549
        if location is not None:
 
550
            try:
 
551
                reader = bundle.read_bundle_from_url(location)
 
552
            except errors.NotABundle:
 
553
                pass # Continue on considering this url a Branch
 
554
 
 
555
        stored_loc = branch_to.get_parent()
 
556
        if location is None:
 
557
            if stored_loc is None:
 
558
                raise errors.BzrCommandError("No pull location known or"
 
559
                                             " specified.")
 
560
            else:
 
561
                display_url = urlutils.unescape_for_display(stored_loc,
 
562
                        self.outf.encoding)
 
563
                self.outf.write("Using saved location: %s\n" % display_url)
 
564
                location = stored_loc
 
565
 
 
566
 
 
567
        if reader is not None:
 
568
            install_bundle(branch_to.repository, reader)
 
569
            branch_from = branch_to
 
570
        else:
 
571
            branch_from = Branch.open(location)
 
572
 
 
573
            if branch_to.get_parent() is None or remember:
 
574
                branch_to.set_parent(branch_from.base)
 
575
 
 
576
        rev_id = None
 
577
        if revision is None:
 
578
            if reader is not None:
 
579
                rev_id = reader.target
 
580
        elif len(revision) == 1:
 
581
            rev_id = revision[0].in_history(branch_from).rev_id
 
582
        else:
 
583
            raise errors.BzrCommandError('bzr pull --revision takes one value.')
 
584
 
 
585
        old_rh = branch_to.revision_history()
 
586
        if tree_to is not None:
 
587
            count = tree_to.pull(branch_from, overwrite, rev_id)
 
588
        else:
 
589
            count = branch_to.pull(branch_from, overwrite, rev_id)
 
590
        note('%d revision(s) pulled.' % (count,))
 
591
 
 
592
        if verbose:
 
593
            new_rh = branch_to.revision_history()
 
594
            if old_rh != new_rh:
 
595
                # Something changed
 
596
                from bzrlib.log import show_changed_revisions
 
597
                show_changed_revisions(branch_to, old_rh, new_rh,
 
598
                                       to_file=self.outf)
 
599
 
 
600
 
 
601
class cmd_push(Command):
 
602
    """Update a mirror of this branch.
 
603
    
 
604
    The target branch will not have its working tree populated because this
 
605
    is both expensive, and is not supported on remote file systems.
 
606
    
 
607
    Some smart servers or protocols *may* put the working tree in place in
 
608
    the future.
 
609
 
 
610
    This command only works on branches that have not diverged.  Branches are
 
611
    considered diverged if the destination branch's most recent commit is one
 
612
    that has not been merged (directly or indirectly) by the source branch.
 
613
 
 
614
    If branches have diverged, you can use 'bzr push --overwrite' to replace
 
615
    the other branch completely, discarding its unmerged changes.
 
616
    
 
617
    If you want to ensure you have the different changes in the other branch,
 
618
    do a merge (see bzr help merge) from the other branch, and commit that.
 
619
    After that you will be able to do a push without '--overwrite'.
 
620
 
 
621
    If there is no default push location set, the first push will set it.
 
622
    After that, you can omit the location to use the default.  To change the
 
623
    default, use --remember. The value will only be saved if the remote
 
624
    location can be accessed.
 
625
    """
 
626
 
 
627
    takes_options = ['remember', 'overwrite', 'verbose',
 
628
                     Option('create-prefix',
 
629
                            help='Create the path leading up to the branch '
 
630
                                 'if it does not already exist'),
 
631
                     Option('use-existing-dir',
 
632
                            help='By default push will fail if the target'
 
633
                                 ' directory exists, but does not already'
 
634
                                 ' have a control directory. This flag will'
 
635
                                 ' allow push to proceed.'),
 
636
                     ]
 
637
    takes_args = ['location?']
 
638
    encoding_type = 'replace'
 
639
 
 
640
    def run(self, location=None, remember=False, overwrite=False,
 
641
            create_prefix=False, verbose=False, use_existing_dir=False):
 
642
        # FIXME: Way too big!  Put this into a function called from the
 
643
        # command.
 
644
        
 
645
        br_from = Branch.open_containing('.')[0]
 
646
        stored_loc = br_from.get_push_location()
 
647
        if location is None:
 
648
            if stored_loc is None:
 
649
                raise errors.BzrCommandError("No push location known or specified.")
 
650
            else:
 
651
                display_url = urlutils.unescape_for_display(stored_loc,
 
652
                        self.outf.encoding)
 
653
                self.outf.write("Using saved location: %s\n" % display_url)
 
654
                location = stored_loc
 
655
 
 
656
        to_transport = transport.get_transport(location)
 
657
        location_url = to_transport.base
 
658
 
 
659
        old_rh = []
 
660
        count = 0
 
661
 
 
662
        br_to = repository_to = dir_to = None
 
663
        try:
 
664
            dir_to = bzrdir.BzrDir.open_from_transport(to_transport)
 
665
        except errors.NotBranchError:
 
666
            pass # Didn't find anything
 
667
        else:
 
668
            # If we can open a branch, use its direct repository, otherwise see
 
669
            # if there is a repository without a branch.
 
670
            try:
 
671
                br_to = dir_to.open_branch()
 
672
            except errors.NotBranchError:
 
673
                # Didn't find a branch, can we find a repository?
 
674
                try:
 
675
                    repository_to = dir_to.find_repository()
 
676
                except errors.NoRepositoryPresent:
 
677
                    pass
 
678
            else:
 
679
                # Found a branch, so we must have found a repository
 
680
                repository_to = br_to.repository
 
681
 
 
682
        old_rh = []
 
683
        if dir_to is None:
 
684
            # XXX: Refactor the create_prefix/no_create_prefix code into a
 
685
            #      common helper function
 
686
            try:
 
687
                to_transport.mkdir('.')
 
688
            except errors.FileExists:
 
689
                if not use_existing_dir:
 
690
                    raise errors.BzrCommandError("Target directory %s"
 
691
                         " already exists, but does not have a valid .bzr"
 
692
                         " directory. Supply --use-existing-dir to push"
 
693
                         " there anyway." % location)
 
694
            except errors.NoSuchFile:
 
695
                if not create_prefix:
 
696
                    raise errors.BzrCommandError("Parent directory of %s"
 
697
                        " does not exist."
 
698
                        "\nYou may supply --create-prefix to create all"
 
699
                        " leading parent directories."
 
700
                        % location)
 
701
 
 
702
                cur_transport = to_transport
 
703
                needed = [cur_transport]
 
704
                # Recurse upwards until we can create a directory successfully
 
705
                while True:
 
706
                    new_transport = cur_transport.clone('..')
 
707
                    if new_transport.base == cur_transport.base:
 
708
                        raise errors.BzrCommandError("Failed to create path"
 
709
                                                     " prefix for %s."
 
710
                                                     % location)
 
711
                    try:
 
712
                        new_transport.mkdir('.')
 
713
                    except errors.NoSuchFile:
 
714
                        needed.append(new_transport)
 
715
                        cur_transport = new_transport
 
716
                    else:
 
717
                        break
 
718
 
 
719
                # Now we only need to create child directories
 
720
                while needed:
 
721
                    cur_transport = needed.pop()
 
722
                    cur_transport.mkdir('.')
 
723
            
 
724
            # Now the target directory exists, but doesn't have a .bzr
 
725
            # directory. So we need to create it, along with any work to create
 
726
            # all of the dependent branches, etc.
 
727
            dir_to = br_from.bzrdir.clone(location_url,
 
728
                revision_id=br_from.last_revision())
 
729
            br_to = dir_to.open_branch()
 
730
            count = br_to.last_revision_info()[0]
 
731
            # We successfully created the target, remember it
 
732
            if br_from.get_push_location() is None or remember:
 
733
                br_from.set_push_location(br_to.base)
 
734
        elif repository_to is None:
 
735
            # we have a bzrdir but no branch or repository
 
736
            # XXX: Figure out what to do other than complain.
 
737
            raise errors.BzrCommandError("At %s you have a valid .bzr control"
 
738
                " directory, but not a branch or repository. This is an"
 
739
                " unsupported configuration. Please move the target directory"
 
740
                " out of the way and try again."
 
741
                % location)
 
742
        elif br_to is None:
 
743
            # We have a repository but no branch, copy the revisions, and then
 
744
            # create a branch.
 
745
            last_revision_id = br_from.last_revision()
 
746
            repository_to.fetch(br_from.repository,
 
747
                                revision_id=last_revision_id)
 
748
            br_to = br_from.clone(dir_to, revision_id=last_revision_id)
 
749
            count = len(br_to.revision_history())
 
750
            if br_from.get_push_location() is None or remember:
 
751
                br_from.set_push_location(br_to.base)
 
752
        else: # We have a valid to branch
 
753
            # We were able to connect to the remote location, so remember it
 
754
            # we don't need to successfully push because of possible divergence.
 
755
            if br_from.get_push_location() is None or remember:
 
756
                br_from.set_push_location(br_to.base)
 
757
            old_rh = br_to.revision_history()
 
758
            try:
 
759
                try:
 
760
                    tree_to = dir_to.open_workingtree()
 
761
                except errors.NotLocalUrl:
 
762
                    warning('This transport does not update the working '
 
763
                            'tree of: %s' % (br_to.base,))
 
764
                    count = br_from.push(br_to, overwrite)
 
765
                except errors.NoWorkingTree:
 
766
                    count = br_from.push(br_to, overwrite)
 
767
                else:
 
768
                    tree_to.lock_write()
 
769
                    try:
 
770
                        count = br_from.push(tree_to.branch, overwrite)
 
771
                        tree_to.update()
 
772
                    finally:
 
773
                        tree_to.unlock()
 
774
            except errors.DivergedBranches:
 
775
                raise errors.BzrCommandError('These branches have diverged.'
 
776
                                        '  Try using "merge" and then "push".')
 
777
        note('%d revision(s) pushed.' % (count,))
 
778
 
 
779
        if verbose:
 
780
            new_rh = br_to.revision_history()
 
781
            if old_rh != new_rh:
 
782
                # Something changed
 
783
                from bzrlib.log import show_changed_revisions
 
784
                show_changed_revisions(br_to, old_rh, new_rh,
 
785
                                       to_file=self.outf)
 
786
 
 
787
 
 
788
class cmd_branch(Command):
 
789
    """Create a new copy of a branch.
 
790
 
 
791
    If the TO_LOCATION is omitted, the last component of the FROM_LOCATION will
 
792
    be used.  In other words, "branch ../foo/bar" will attempt to create ./bar.
 
793
 
 
794
    To retrieve the branch as of a particular revision, supply the --revision
 
795
    parameter, as in "branch foo/bar -r 5".
 
796
 
 
797
    --basis is to speed up branching from remote branches.  When specified, it
 
798
    copies all the file-contents, inventory and revision data from the basis
 
799
    branch before copying anything from the remote branch.
 
800
    """
 
801
    takes_args = ['from_location', 'to_location?']
 
802
    takes_options = ['revision', 'basis']
 
803
    aliases = ['get', 'clone']
 
804
 
 
805
    def run(self, from_location, to_location=None, revision=None, basis=None):
 
806
        if revision is None:
 
807
            revision = [None]
 
808
        elif len(revision) > 1:
 
809
            raise errors.BzrCommandError(
 
810
                'bzr branch --revision takes exactly 1 revision value')
 
811
        try:
 
812
            br_from = Branch.open(from_location)
 
813
        except OSError, e:
 
814
            if e.errno == errno.ENOENT:
 
815
                raise errors.BzrCommandError('Source location "%s" does not'
 
816
                                             ' exist.' % to_location)
 
817
            else:
 
818
                raise
 
819
        br_from.lock_read()
 
820
        try:
 
821
            if basis is not None:
 
822
                basis_dir = bzrdir.BzrDir.open_containing(basis)[0]
 
823
            else:
 
824
                basis_dir = None
 
825
            if len(revision) == 1 and revision[0] is not None:
 
826
                revision_id = revision[0].in_history(br_from)[1]
 
827
            else:
 
828
                # FIXME - wt.last_revision, fallback to branch, fall back to
 
829
                # None or perhaps NULL_REVISION to mean copy nothing
 
830
                # RBC 20060209
 
831
                revision_id = br_from.last_revision()
 
832
            if to_location is None:
 
833
                to_location = os.path.basename(from_location.rstrip("/\\"))
 
834
                name = None
 
835
            else:
 
836
                name = os.path.basename(to_location) + '\n'
 
837
 
 
838
            to_transport = transport.get_transport(to_location)
 
839
            try:
 
840
                to_transport.mkdir('.')
 
841
            except errors.FileExists:
 
842
                raise errors.BzrCommandError('Target directory "%s" already'
 
843
                                             ' exists.' % to_location)
 
844
            except errors.NoSuchFile:
 
845
                raise errors.BzrCommandError('Parent of "%s" does not exist.'
 
846
                                             % to_location)
 
847
            try:
 
848
                # preserve whatever source format we have.
 
849
                dir = br_from.bzrdir.sprout(to_transport.base,
 
850
                        revision_id, basis_dir)
 
851
                branch = dir.open_branch()
 
852
            except errors.NoSuchRevision:
 
853
                to_transport.delete_tree('.')
 
854
                msg = "The branch %s has no revision %s." % (from_location, revision[0])
 
855
                raise errors.BzrCommandError(msg)
 
856
            except errors.UnlistableBranch:
 
857
                osutils.rmtree(to_location)
 
858
                msg = "The branch %s cannot be used as a --basis" % (basis,)
 
859
                raise errors.BzrCommandError(msg)
 
860
            if name:
 
861
                branch.control_files.put_utf8('branch-name', name)
 
862
            note('Branched %d revision(s).' % branch.revno())
 
863
        finally:
 
864
            br_from.unlock()
 
865
 
 
866
 
 
867
class cmd_checkout(Command):
 
868
    """Create a new checkout of an existing branch.
 
869
 
 
870
    If BRANCH_LOCATION is omitted, checkout will reconstitute a working tree for
 
871
    the branch found in '.'. This is useful if you have removed the working tree
 
872
    or if it was never created - i.e. if you pushed the branch to its current
 
873
    location using SFTP.
 
874
    
 
875
    If the TO_LOCATION is omitted, the last component of the BRANCH_LOCATION will
 
876
    be used.  In other words, "checkout ../foo/bar" will attempt to create ./bar.
 
877
 
 
878
    To retrieve the branch as of a particular revision, supply the --revision
 
879
    parameter, as in "checkout foo/bar -r 5". Note that this will be immediately
 
880
    out of date [so you cannot commit] but it may be useful (i.e. to examine old
 
881
    code.)
 
882
 
 
883
    --basis is to speed up checking out from remote branches.  When specified, it
 
884
    uses the inventory and file contents from the basis branch in preference to the
 
885
    branch being checked out.
 
886
 
 
887
    See "help checkouts" for more information on checkouts.
 
888
    """
 
889
    takes_args = ['branch_location?', 'to_location?']
 
890
    takes_options = ['revision', # , 'basis']
 
891
                     Option('lightweight',
 
892
                            help="perform a lightweight checkout. Lightweight "
 
893
                                 "checkouts depend on access to the branch for "
 
894
                                 "every operation. Normal checkouts can perform "
 
895
                                 "common operations like diff and status without "
 
896
                                 "such access, and also support local commits."
 
897
                            ),
 
898
                     ]
 
899
    aliases = ['co']
 
900
 
 
901
    def run(self, branch_location=None, to_location=None, revision=None, basis=None,
 
902
            lightweight=False):
 
903
        if revision is None:
 
904
            revision = [None]
 
905
        elif len(revision) > 1:
 
906
            raise errors.BzrCommandError(
 
907
                'bzr checkout --revision takes exactly 1 revision value')
 
908
        if branch_location is None:
 
909
            branch_location = osutils.getcwd()
 
910
            to_location = branch_location
 
911
        source = Branch.open(branch_location)
 
912
        if len(revision) == 1 and revision[0] is not None:
 
913
            revision_id = revision[0].in_history(source)[1]
 
914
        else:
 
915
            revision_id = None
 
916
        if to_location is None:
 
917
            to_location = os.path.basename(branch_location.rstrip("/\\"))
 
918
        # if the source and to_location are the same, 
 
919
        # and there is no working tree,
 
920
        # then reconstitute a branch
 
921
        if (osutils.abspath(to_location) ==
 
922
            osutils.abspath(branch_location)):
 
923
            try:
 
924
                source.bzrdir.open_workingtree()
 
925
            except errors.NoWorkingTree:
 
926
                source.bzrdir.create_workingtree()
 
927
                return
 
928
        try:
 
929
            os.mkdir(to_location)
 
930
        except OSError, e:
 
931
            if e.errno == errno.EEXIST:
 
932
                raise errors.BzrCommandError('Target directory "%s" already'
 
933
                                             ' exists.' % to_location)
 
934
            if e.errno == errno.ENOENT:
 
935
                raise errors.BzrCommandError('Parent of "%s" does not exist.'
 
936
                                             % to_location)
 
937
            else:
 
938
                raise
 
939
        source.create_checkout(to_location, revision_id, lightweight)
 
940
 
 
941
 
 
942
class cmd_renames(Command):
 
943
    """Show list of renamed files.
 
944
    """
 
945
    # TODO: Option to show renames between two historical versions.
 
946
 
 
947
    # TODO: Only show renames under dir, rather than in the whole branch.
 
948
    takes_args = ['dir?']
 
949
 
 
950
    @display_command
 
951
    def run(self, dir=u'.'):
 
952
        tree = WorkingTree.open_containing(dir)[0]
 
953
        old_inv = tree.basis_tree().inventory
 
954
        new_inv = tree.read_working_inventory()
 
955
        renames = list(_mod_tree.find_renames(old_inv, new_inv))
 
956
        renames.sort()
 
957
        for old_name, new_name in renames:
 
958
            self.outf.write("%s => %s\n" % (old_name, new_name))
 
959
 
 
960
 
 
961
class cmd_update(Command):
 
962
    """Update a tree to have the latest code committed to its branch.
 
963
    
 
964
    This will perform a merge into the working tree, and may generate
 
965
    conflicts. If you have any local changes, you will still 
 
966
    need to commit them after the update for the update to be complete.
 
967
    
 
968
    If you want to discard your local changes, you can just do a 
 
969
    'bzr revert' instead of 'bzr commit' after the update.
 
970
    """
 
971
    takes_args = ['dir?']
 
972
    aliases = ['up']
 
973
 
 
974
    def run(self, dir='.'):
 
975
        tree = WorkingTree.open_containing(dir)[0]
 
976
        master = tree.branch.get_master_branch()
 
977
        if master is not None:
 
978
            tree.lock_write()
 
979
        else:
 
980
            tree.lock_tree_write()
 
981
        try:
 
982
            existing_pending_merges = tree.get_parent_ids()[1:]
 
983
            last_rev = tree.last_revision()
 
984
            if last_rev == tree.branch.last_revision():
 
985
                # may be up to date, check master too.
 
986
                master = tree.branch.get_master_branch()
 
987
                if master is None or last_rev == master.last_revision():
 
988
                    revno = tree.branch.revision_id_to_revno(last_rev)
 
989
                    note("Tree is up to date at revision %d." % (revno,))
 
990
                    return 0
 
991
            conflicts = tree.update()
 
992
            revno = tree.branch.revision_id_to_revno(tree.last_revision())
 
993
            note('Updated to revision %d.' % (revno,))
 
994
            if tree.get_parent_ids()[1:] != existing_pending_merges:
 
995
                note('Your local commits will now show as pending merges with '
 
996
                     "'bzr status', and can be committed with 'bzr commit'.")
 
997
            if conflicts != 0:
 
998
                return 1
 
999
            else:
 
1000
                return 0
 
1001
        finally:
 
1002
            tree.unlock()
 
1003
 
 
1004
 
 
1005
class cmd_info(Command):
 
1006
    """Show information about a working tree, branch or repository.
 
1007
 
 
1008
    This command will show all known locations and formats associated to the
 
1009
    tree, branch or repository.  Statistical information is included with
 
1010
    each report.
 
1011
 
 
1012
    Branches and working trees will also report any missing revisions.
 
1013
    """
 
1014
    takes_args = ['location?']
 
1015
    takes_options = ['verbose']
 
1016
 
 
1017
    @display_command
 
1018
    def run(self, location=None, verbose=False):
 
1019
        from bzrlib.info import show_bzrdir_info
 
1020
        show_bzrdir_info(bzrdir.BzrDir.open_containing(location)[0],
 
1021
                         verbose=verbose)
 
1022
 
 
1023
 
 
1024
class cmd_remove(Command):
 
1025
    """Make a file unversioned.
 
1026
 
 
1027
    This makes bzr stop tracking changes to a versioned file.  It does
 
1028
    not delete the working copy.
 
1029
 
 
1030
    You can specify one or more files, and/or --new.  If you specify --new,
 
1031
    only 'added' files will be removed.  If you specify both, then new files
 
1032
    in the specified directories will be removed.  If the directories are
 
1033
    also new, they will also be removed.
 
1034
    """
 
1035
    takes_args = ['file*']
 
1036
    takes_options = ['verbose', Option('new', help='remove newly-added files')]
 
1037
    aliases = ['rm']
 
1038
    encoding_type = 'replace'
 
1039
    
 
1040
    def run(self, file_list, verbose=False, new=False):
 
1041
        tree, file_list = tree_files(file_list)
 
1042
        if new is False:
 
1043
            if file_list is None:
 
1044
                raise errors.BzrCommandError('Specify one or more files to'
 
1045
                                             ' remove, or use --new.')
 
1046
        else:
 
1047
            added = tree.changes_from(tree.basis_tree(),
 
1048
                specific_files=file_list).added
 
1049
            file_list = sorted([f[0] for f in added], reverse=True)
 
1050
            if len(file_list) == 0:
 
1051
                raise errors.BzrCommandError('No matching files.')
 
1052
        tree.remove(file_list, verbose=verbose, to_file=self.outf)
 
1053
 
 
1054
 
 
1055
class cmd_file_id(Command):
 
1056
    """Print file_id of a particular file or directory.
 
1057
 
 
1058
    The file_id is assigned when the file is first added and remains the
 
1059
    same through all revisions where the file exists, even when it is
 
1060
    moved or renamed.
 
1061
    """
 
1062
 
 
1063
    hidden = True
 
1064
    takes_args = ['filename']
 
1065
 
 
1066
    @display_command
 
1067
    def run(self, filename):
 
1068
        tree, relpath = WorkingTree.open_containing(filename)
 
1069
        i = tree.inventory.path2id(relpath)
 
1070
        if i is None:
 
1071
            raise errors.NotVersionedError(filename)
 
1072
        else:
 
1073
            self.outf.write(i + '\n')
 
1074
 
 
1075
 
 
1076
class cmd_file_path(Command):
 
1077
    """Print path of file_ids to a file or directory.
 
1078
 
 
1079
    This prints one line for each directory down to the target,
 
1080
    starting at the branch root.
 
1081
    """
 
1082
 
 
1083
    hidden = True
 
1084
    takes_args = ['filename']
 
1085
 
 
1086
    @display_command
 
1087
    def run(self, filename):
 
1088
        tree, relpath = WorkingTree.open_containing(filename)
 
1089
        inv = tree.inventory
 
1090
        fid = inv.path2id(relpath)
 
1091
        if fid is None:
 
1092
            raise errors.NotVersionedError(filename)
 
1093
        for fip in inv.get_idpath(fid):
 
1094
            self.outf.write(fip + '\n')
 
1095
 
 
1096
 
 
1097
class cmd_reconcile(Command):
 
1098
    """Reconcile bzr metadata in a branch.
 
1099
 
 
1100
    This can correct data mismatches that may have been caused by
 
1101
    previous ghost operations or bzr upgrades. You should only
 
1102
    need to run this command if 'bzr check' or a bzr developer 
 
1103
    advises you to run it.
 
1104
 
 
1105
    If a second branch is provided, cross-branch reconciliation is
 
1106
    also attempted, which will check that data like the tree root
 
1107
    id which was not present in very early bzr versions is represented
 
1108
    correctly in both branches.
 
1109
 
 
1110
    At the same time it is run it may recompress data resulting in 
 
1111
    a potential saving in disk space or performance gain.
 
1112
 
 
1113
    The branch *MUST* be on a listable system such as local disk or sftp.
 
1114
    """
 
1115
    takes_args = ['branch?']
 
1116
 
 
1117
    def run(self, branch="."):
 
1118
        from bzrlib.reconcile import reconcile
 
1119
        dir = bzrdir.BzrDir.open(branch)
 
1120
        reconcile(dir)
 
1121
 
 
1122
 
 
1123
class cmd_revision_history(Command):
 
1124
    """Display the list of revision ids on a branch."""
 
1125
    takes_args = ['location?']
 
1126
 
 
1127
    hidden = True
 
1128
 
 
1129
    @display_command
 
1130
    def run(self, location="."):
 
1131
        branch = Branch.open_containing(location)[0]
 
1132
        for revid in branch.revision_history():
 
1133
            self.outf.write(revid)
 
1134
            self.outf.write('\n')
 
1135
 
 
1136
 
 
1137
class cmd_ancestry(Command):
 
1138
    """List all revisions merged into this branch."""
 
1139
    takes_args = ['location?']
 
1140
 
 
1141
    hidden = True
 
1142
 
 
1143
    @display_command
 
1144
    def run(self, location="."):
 
1145
        try:
 
1146
            wt = WorkingTree.open_containing(location)[0]
 
1147
        except errors.NoWorkingTree:
 
1148
            b = Branch.open(location)
 
1149
            last_revision = b.last_revision()
 
1150
        else:
 
1151
            b = wt.branch
 
1152
            last_revision = wt.last_revision()
 
1153
 
 
1154
        revision_ids = b.repository.get_ancestry(last_revision)
 
1155
        assert revision_ids[0] is None
 
1156
        revision_ids.pop(0)
 
1157
        for revision_id in revision_ids:
 
1158
            self.outf.write(revision_id + '\n')
 
1159
 
 
1160
 
 
1161
class cmd_init(Command):
 
1162
    """Make a directory into a versioned branch.
 
1163
 
 
1164
    Use this to create an empty branch, or before importing an
 
1165
    existing project.
 
1166
 
 
1167
    If there is a repository in a parent directory of the location, then 
 
1168
    the history of the branch will be stored in the repository.  Otherwise
 
1169
    init creates a standalone branch which carries its own history in 
 
1170
    .bzr.
 
1171
 
 
1172
    If there is already a branch at the location but it has no working tree,
 
1173
    the tree can be populated with 'bzr checkout'.
 
1174
 
 
1175
    Recipe for importing a tree of files:
 
1176
        cd ~/project
 
1177
        bzr init
 
1178
        bzr add .
 
1179
        bzr status
 
1180
        bzr commit -m 'imported project'
 
1181
    """
 
1182
    takes_args = ['location?']
 
1183
    takes_options = [
 
1184
                     RegistryOption('format',
 
1185
                            help='Specify a format for this branch. See "bzr '
 
1186
                            'help formats" for details',
 
1187
                            converter=bzrdir.format_registry.make_bzrdir,
 
1188
                            registry=bzrdir.format_registry,
 
1189
                            value_switches=True, title="Branch Format"),
 
1190
                     ]
 
1191
    def run(self, location=None, format=None):
 
1192
        if format is None:
 
1193
            format = bzrdir.format_registry.make_bzrdir('default')
 
1194
        if location is None:
 
1195
            location = u'.'
 
1196
 
 
1197
        to_transport = transport.get_transport(location)
 
1198
 
 
1199
        # The path has to exist to initialize a
 
1200
        # branch inside of it.
 
1201
        # Just using os.mkdir, since I don't
 
1202
        # believe that we want to create a bunch of
 
1203
        # locations if the user supplies an extended path
 
1204
        # TODO: create-prefix
 
1205
        try:
 
1206
            to_transport.mkdir('.')
 
1207
        except errors.FileExists:
 
1208
            pass
 
1209
                    
 
1210
        try:
 
1211
            existing_bzrdir = bzrdir.BzrDir.open(location)
 
1212
        except errors.NotBranchError:
 
1213
            # really a NotBzrDir error...
 
1214
            bzrdir.BzrDir.create_branch_convenience(location, format=format)
 
1215
        else:
 
1216
            from bzrlib.transport.local import LocalTransport
 
1217
            if existing_bzrdir.has_branch():
 
1218
                if (isinstance(to_transport, LocalTransport)
 
1219
                    and not existing_bzrdir.has_workingtree()):
 
1220
                        raise errors.BranchExistsWithoutWorkingTree(location)
 
1221
                raise errors.AlreadyBranchError(location)
 
1222
            else:
 
1223
                existing_bzrdir.create_branch()
 
1224
                existing_bzrdir.create_workingtree()
 
1225
 
 
1226
 
 
1227
class cmd_init_repository(Command):
 
1228
    """Create a shared repository to hold branches.
 
1229
 
 
1230
    New branches created under the repository directory will store their revisions
 
1231
    in the repository, not in the branch directory, if the branch format supports
 
1232
    shared storage.
 
1233
 
 
1234
    example:
 
1235
        bzr init-repo repo
 
1236
        bzr init repo/trunk
 
1237
        bzr checkout --lightweight repo/trunk trunk-checkout
 
1238
        cd trunk-checkout
 
1239
        (add files here)
 
1240
    """
 
1241
    takes_args = ["location"] 
 
1242
    takes_options = [RegistryOption('format',
 
1243
                            help='Specify a format for this repository. See'
 
1244
                                 ' "bzr help formats" for details',
 
1245
                            registry=bzrdir.format_registry,
 
1246
                            converter=bzrdir.format_registry.make_bzrdir,
 
1247
                            value_switches=True, title='Repository format'),
 
1248
                     Option('trees',
 
1249
                             help='Allows branches in repository to have'
 
1250
                             ' a working tree')]
 
1251
    aliases = ["init-repo"]
 
1252
    def run(self, location, format=None, trees=False):
 
1253
        if format is None:
 
1254
            format = bzrdir.format_registry.make_bzrdir('default')
 
1255
 
 
1256
        if location is None:
 
1257
            location = '.'
 
1258
 
 
1259
        to_transport = transport.get_transport(location)
 
1260
        try:
 
1261
            to_transport.mkdir('.')
 
1262
        except errors.FileExists:
 
1263
            pass
 
1264
 
 
1265
        newdir = format.initialize_on_transport(to_transport)
 
1266
        repo = newdir.create_repository(shared=True)
 
1267
        repo.set_make_working_trees(trees)
 
1268
 
 
1269
 
 
1270
class cmd_diff(Command):
 
1271
    """Show differences in the working tree or between revisions.
 
1272
    
 
1273
    If files are listed, only the changes in those files are listed.
 
1274
    Otherwise, all changes for the tree are listed.
 
1275
 
 
1276
    "bzr diff -p1" is equivalent to "bzr diff --prefix old/:new/", and
 
1277
    produces patches suitable for "patch -p1".
 
1278
 
 
1279
    examples:
 
1280
        bzr diff
 
1281
            Shows the difference in the working tree versus the last commit
 
1282
        bzr diff -r1
 
1283
            Difference between the working tree and revision 1
 
1284
        bzr diff -r1..2
 
1285
            Difference between revision 2 and revision 1
 
1286
        bzr diff --diff-prefix old/:new/
 
1287
            Same as 'bzr diff' but prefix paths with old/ and new/
 
1288
        bzr diff bzr.mine bzr.dev
 
1289
            Show the differences between the two working trees
 
1290
        bzr diff foo.c
 
1291
            Show just the differences for 'foo.c'
 
1292
    """
 
1293
    # TODO: Option to use external diff command; could be GNU diff, wdiff,
 
1294
    #       or a graphical diff.
 
1295
 
 
1296
    # TODO: Python difflib is not exactly the same as unidiff; should
 
1297
    #       either fix it up or prefer to use an external diff.
 
1298
 
 
1299
    # TODO: Selected-file diff is inefficient and doesn't show you
 
1300
    #       deleted files.
 
1301
 
 
1302
    # TODO: This probably handles non-Unix newlines poorly.
 
1303
 
 
1304
    takes_args = ['file*']
 
1305
    takes_options = ['revision', 'diff-options',
 
1306
        Option('prefix', type=str,
 
1307
               short_name='p',
 
1308
               help='Set prefixes to added to old and new filenames, as '
 
1309
                    'two values separated by a colon.'),
 
1310
        ]
 
1311
    aliases = ['di', 'dif']
 
1312
    encoding_type = 'exact'
 
1313
 
 
1314
    @display_command
 
1315
    def run(self, revision=None, file_list=None, diff_options=None,
 
1316
            prefix=None):
 
1317
        from bzrlib.diff import diff_cmd_helper, show_diff_trees
 
1318
 
 
1319
        if (prefix is None) or (prefix == '0'):
 
1320
            # diff -p0 format
 
1321
            old_label = ''
 
1322
            new_label = ''
 
1323
        elif prefix == '1':
 
1324
            old_label = 'old/'
 
1325
            new_label = 'new/'
 
1326
        elif ':' in prefix:
 
1327
            old_label, new_label = prefix.split(":")
 
1328
        else:
 
1329
            raise BzrCommandError(
 
1330
                "--prefix expects two values separated by a colon")
 
1331
 
 
1332
        if revision and len(revision) > 2:
 
1333
            raise errors.BzrCommandError('bzr diff --revision takes exactly'
 
1334
                                         ' one or two revision specifiers')
 
1335
        
 
1336
        try:
 
1337
            tree1, file_list = internal_tree_files(file_list)
 
1338
            tree2 = None
 
1339
            b = None
 
1340
            b2 = None
 
1341
        except errors.FileInWrongBranch:
 
1342
            if len(file_list) != 2:
 
1343
                raise errors.BzrCommandError("Files are in different branches")
 
1344
 
 
1345
            tree1, file1 = WorkingTree.open_containing(file_list[0])
 
1346
            tree2, file2 = WorkingTree.open_containing(file_list[1])
 
1347
            if file1 != "" or file2 != "":
 
1348
                # FIXME diff those two files. rbc 20051123
 
1349
                raise errors.BzrCommandError("Files are in different branches")
 
1350
            file_list = None
 
1351
        except errors.NotBranchError:
 
1352
            if (revision is not None and len(revision) == 2
 
1353
                and not revision[0].needs_branch()
 
1354
                and not revision[1].needs_branch()):
 
1355
                # If both revision specs include a branch, we can
 
1356
                # diff them without needing a local working tree
 
1357
                tree1, tree2 = None, None
 
1358
            else:
 
1359
                raise
 
1360
 
 
1361
        if tree2 is not None:
 
1362
            if revision is not None:
 
1363
                # FIXME: but there should be a clean way to diff between
 
1364
                # non-default versions of two trees, it's not hard to do
 
1365
                # internally...
 
1366
                raise errors.BzrCommandError(
 
1367
                        "Sorry, diffing arbitrary revisions across branches "
 
1368
                        "is not implemented yet")
 
1369
            return show_diff_trees(tree1, tree2, sys.stdout, 
 
1370
                                   specific_files=file_list,
 
1371
                                   external_diff_options=diff_options,
 
1372
                                   old_label=old_label, new_label=new_label)
 
1373
 
 
1374
        return diff_cmd_helper(tree1, file_list, diff_options,
 
1375
                               revision_specs=revision,
 
1376
                               old_label=old_label, new_label=new_label)
 
1377
 
 
1378
 
 
1379
class cmd_deleted(Command):
 
1380
    """List files deleted in the working tree.
 
1381
    """
 
1382
    # TODO: Show files deleted since a previous revision, or
 
1383
    # between two revisions.
 
1384
    # TODO: Much more efficient way to do this: read in new
 
1385
    # directories with readdir, rather than stating each one.  Same
 
1386
    # level of effort but possibly much less IO.  (Or possibly not,
 
1387
    # if the directories are very large...)
 
1388
    takes_options = ['show-ids']
 
1389
 
 
1390
    @display_command
 
1391
    def run(self, show_ids=False):
 
1392
        tree = WorkingTree.open_containing(u'.')[0]
 
1393
        old = tree.basis_tree()
 
1394
        for path, ie in old.inventory.iter_entries():
 
1395
            if not tree.has_id(ie.file_id):
 
1396
                self.outf.write(path)
 
1397
                if show_ids:
 
1398
                    self.outf.write(' ')
 
1399
                    self.outf.write(ie.file_id)
 
1400
                self.outf.write('\n')
 
1401
 
 
1402
 
 
1403
class cmd_modified(Command):
 
1404
    """List files modified in working tree."""
 
1405
    hidden = True
 
1406
    @display_command
 
1407
    def run(self):
 
1408
        tree = WorkingTree.open_containing(u'.')[0]
 
1409
        td = tree.changes_from(tree.basis_tree())
 
1410
        for path, id, kind, text_modified, meta_modified in td.modified:
 
1411
            self.outf.write(path + '\n')
 
1412
 
 
1413
 
 
1414
class cmd_added(Command):
 
1415
    """List files added in working tree."""
 
1416
    hidden = True
 
1417
    @display_command
 
1418
    def run(self):
 
1419
        wt = WorkingTree.open_containing(u'.')[0]
 
1420
        basis_inv = wt.basis_tree().inventory
 
1421
        inv = wt.inventory
 
1422
        for file_id in inv:
 
1423
            if file_id in basis_inv:
 
1424
                continue
 
1425
            if inv.is_root(file_id) and len(basis_inv) == 0:
 
1426
                continue
 
1427
            path = inv.id2path(file_id)
 
1428
            if not os.access(osutils.abspath(path), os.F_OK):
 
1429
                continue
 
1430
            self.outf.write(path + '\n')
 
1431
 
 
1432
 
 
1433
class cmd_root(Command):
 
1434
    """Show the tree root directory.
 
1435
 
 
1436
    The root is the nearest enclosing directory with a .bzr control
 
1437
    directory."""
 
1438
    takes_args = ['filename?']
 
1439
    @display_command
 
1440
    def run(self, filename=None):
 
1441
        """Print the branch root."""
 
1442
        tree = WorkingTree.open_containing(filename)[0]
 
1443
        self.outf.write(tree.basedir + '\n')
 
1444
 
 
1445
 
 
1446
class cmd_log(Command):
 
1447
    """Show log of a branch, file, or directory.
 
1448
 
 
1449
    By default show the log of the branch containing the working directory.
 
1450
 
 
1451
    To request a range of logs, you can use the command -r begin..end
 
1452
    -r revision requests a specific revision, -r ..end or -r begin.. are
 
1453
    also valid.
 
1454
 
 
1455
    examples:
 
1456
        bzr log
 
1457
        bzr log foo.c
 
1458
        bzr log -r -10.. http://server/branch
 
1459
    """
 
1460
 
 
1461
    # TODO: Make --revision support uuid: and hash: [future tag:] notation.
 
1462
 
 
1463
    takes_args = ['location?']
 
1464
    takes_options = [Option('forward', 
 
1465
                            help='show from oldest to newest'),
 
1466
                     'timezone', 
 
1467
                     Option('verbose', 
 
1468
                             short_name='v',
 
1469
                             help='show files changed in each revision'),
 
1470
                     'show-ids', 'revision',
 
1471
                     'log-format',
 
1472
                     Option('message',
 
1473
                            short_name='m',
 
1474
                            help='show revisions whose message matches this regexp',
 
1475
                            type=str),
 
1476
                     ]
 
1477
    encoding_type = 'replace'
 
1478
 
 
1479
    @display_command
 
1480
    def run(self, location=None, timezone='original',
 
1481
            verbose=False,
 
1482
            show_ids=False,
 
1483
            forward=False,
 
1484
            revision=None,
 
1485
            log_format=None,
 
1486
            message=None):
 
1487
        from bzrlib.log import show_log
 
1488
        assert message is None or isinstance(message, basestring), \
 
1489
            "invalid message argument %r" % message
 
1490
        direction = (forward and 'forward') or 'reverse'
 
1491
        
 
1492
        # log everything
 
1493
        file_id = None
 
1494
        if location:
 
1495
            # find the file id to log:
 
1496
 
 
1497
            dir, fp = bzrdir.BzrDir.open_containing(location)
 
1498
            b = dir.open_branch()
 
1499
            if fp != '':
 
1500
                try:
 
1501
                    # might be a tree:
 
1502
                    inv = dir.open_workingtree().inventory
 
1503
                except (errors.NotBranchError, errors.NotLocalUrl):
 
1504
                    # either no tree, or is remote.
 
1505
                    inv = b.basis_tree().inventory
 
1506
                file_id = inv.path2id(fp)
 
1507
                if file_id is None:
 
1508
                    raise errors.BzrCommandError(
 
1509
                        "Path does not have any revision history: %s" %
 
1510
                        location)
 
1511
        else:
 
1512
            # local dir only
 
1513
            # FIXME ? log the current subdir only RBC 20060203 
 
1514
            if revision is not None \
 
1515
                    and len(revision) > 0 and revision[0].get_branch():
 
1516
                location = revision[0].get_branch()
 
1517
            else:
 
1518
                location = '.'
 
1519
            dir, relpath = bzrdir.BzrDir.open_containing(location)
 
1520
            b = dir.open_branch()
 
1521
 
 
1522
        if revision is None:
 
1523
            rev1 = None
 
1524
            rev2 = None
 
1525
        elif len(revision) == 1:
 
1526
            rev1 = rev2 = revision[0].in_history(b).revno
 
1527
        elif len(revision) == 2:
 
1528
            if revision[1].get_branch() != revision[0].get_branch():
 
1529
                # b is taken from revision[0].get_branch(), and
 
1530
                # show_log will use its revision_history. Having
 
1531
                # different branches will lead to weird behaviors.
 
1532
                raise errors.BzrCommandError(
 
1533
                    "Log doesn't accept two revisions in different branches.")
 
1534
            if revision[0].spec is None:
 
1535
                # missing begin-range means first revision
 
1536
                rev1 = 1
 
1537
            else:
 
1538
                rev1 = revision[0].in_history(b).revno
 
1539
 
 
1540
            if revision[1].spec is None:
 
1541
                # missing end-range means last known revision
 
1542
                rev2 = b.revno()
 
1543
            else:
 
1544
                rev2 = revision[1].in_history(b).revno
 
1545
        else:
 
1546
            raise errors.BzrCommandError('bzr log --revision takes one or two values.')
 
1547
 
 
1548
        # By this point, the revision numbers are converted to the +ve
 
1549
        # form if they were supplied in the -ve form, so we can do
 
1550
        # this comparison in relative safety
 
1551
        if rev1 > rev2:
 
1552
            (rev2, rev1) = (rev1, rev2)
 
1553
 
 
1554
        if log_format is None:
 
1555
            log_format = log.log_formatter_registry.get_default(b)
 
1556
 
 
1557
        lf = log_format(show_ids=show_ids, to_file=self.outf,
 
1558
                        show_timezone=timezone)
 
1559
 
 
1560
        show_log(b,
 
1561
                 lf,
 
1562
                 file_id,
 
1563
                 verbose=verbose,
 
1564
                 direction=direction,
 
1565
                 start_revision=rev1,
 
1566
                 end_revision=rev2,
 
1567
                 search=message)
 
1568
 
 
1569
 
 
1570
def get_log_format(long=False, short=False, line=False, default='long'):
 
1571
    log_format = default
 
1572
    if long:
 
1573
        log_format = 'long'
 
1574
    if short:
 
1575
        log_format = 'short'
 
1576
    if line:
 
1577
        log_format = 'line'
 
1578
    return log_format
 
1579
 
 
1580
 
 
1581
class cmd_touching_revisions(Command):
 
1582
    """Return revision-ids which affected a particular file.
 
1583
 
 
1584
    A more user-friendly interface is "bzr log FILE".
 
1585
    """
 
1586
 
 
1587
    hidden = True
 
1588
    takes_args = ["filename"]
 
1589
 
 
1590
    @display_command
 
1591
    def run(self, filename):
 
1592
        tree, relpath = WorkingTree.open_containing(filename)
 
1593
        b = tree.branch
 
1594
        inv = tree.read_working_inventory()
 
1595
        file_id = inv.path2id(relpath)
 
1596
        for revno, revision_id, what in log.find_touching_revisions(b, file_id):
 
1597
            self.outf.write("%6d %s\n" % (revno, what))
 
1598
 
 
1599
 
 
1600
class cmd_ls(Command):
 
1601
    """List files in a tree.
 
1602
    """
 
1603
 
 
1604
    takes_args = ['path?']
 
1605
    # TODO: Take a revision or remote path and list that tree instead.
 
1606
    takes_options = ['verbose', 'revision',
 
1607
                     Option('non-recursive',
 
1608
                            help='don\'t recurse into sub-directories'),
 
1609
                     Option('from-root',
 
1610
                            help='Print all paths from the root of the branch.'),
 
1611
                     Option('unknown', help='Print unknown files'),
 
1612
                     Option('versioned', help='Print versioned files'),
 
1613
                     Option('ignored', help='Print ignored files'),
 
1614
 
 
1615
                     Option('null', help='Null separate the files'),
 
1616
                     'kind', 'show-ids'
 
1617
                    ]
 
1618
    @display_command
 
1619
    def run(self, revision=None, verbose=False, 
 
1620
            non_recursive=False, from_root=False,
 
1621
            unknown=False, versioned=False, ignored=False,
 
1622
            null=False, kind=None, show_ids=False, path=None):
 
1623
 
 
1624
        if kind and kind not in ('file', 'directory', 'symlink'):
 
1625
            raise errors.BzrCommandError('invalid kind specified')
 
1626
 
 
1627
        if verbose and null:
 
1628
            raise errors.BzrCommandError('Cannot set both --verbose and --null')
 
1629
        all = not (unknown or versioned or ignored)
 
1630
 
 
1631
        selection = {'I':ignored, '?':unknown, 'V':versioned}
 
1632
 
 
1633
        if path is None:
 
1634
            fs_path = '.'
 
1635
            prefix = ''
 
1636
        else:
 
1637
            if from_root:
 
1638
                raise errors.BzrCommandError('cannot specify both --from-root'
 
1639
                                             ' and PATH')
 
1640
            fs_path = path
 
1641
            prefix = path
 
1642
        tree, branch, relpath = bzrdir.BzrDir.open_containing_tree_or_branch(
 
1643
            fs_path)
 
1644
        if from_root:
 
1645
            relpath = u''
 
1646
        elif relpath:
 
1647
            relpath += '/'
 
1648
        if revision is not None:
 
1649
            tree = branch.repository.revision_tree(
 
1650
                revision[0].in_history(branch).rev_id)
 
1651
        elif tree is None:
 
1652
            tree = branch.basis_tree()
 
1653
 
 
1654
        for fp, fc, fkind, fid, entry in tree.list_files(include_root=False):
 
1655
            if fp.startswith(relpath):
 
1656
                fp = osutils.pathjoin(prefix, fp[len(relpath):])
 
1657
                if non_recursive and '/' in fp:
 
1658
                    continue
 
1659
                if not all and not selection[fc]:
 
1660
                    continue
 
1661
                if kind is not None and fkind != kind:
 
1662
                    continue
 
1663
                if verbose:
 
1664
                    kindch = entry.kind_character()
 
1665
                    outstring = '%-8s %s%s' % (fc, fp, kindch)
 
1666
                    if show_ids and fid is not None:
 
1667
                        outstring = "%-50s %s" % (outstring, fid)
 
1668
                    self.outf.write(outstring + '\n')
 
1669
                elif null:
 
1670
                    self.outf.write(fp + '\0')
 
1671
                    if show_ids:
 
1672
                        if fid is not None:
 
1673
                            self.outf.write(fid)
 
1674
                        self.outf.write('\0')
 
1675
                    self.outf.flush()
 
1676
                else:
 
1677
                    if fid is not None:
 
1678
                        my_id = fid
 
1679
                    else:
 
1680
                        my_id = ''
 
1681
                    if show_ids:
 
1682
                        self.outf.write('%-50s %s\n' % (fp, my_id))
 
1683
                    else:
 
1684
                        self.outf.write(fp + '\n')
 
1685
 
 
1686
 
 
1687
class cmd_unknowns(Command):
 
1688
    """List unknown files."""
 
1689
    @display_command
 
1690
    def run(self):
 
1691
        for f in WorkingTree.open_containing(u'.')[0].unknowns():
 
1692
            self.outf.write(osutils.quotefn(f) + '\n')
 
1693
 
 
1694
 
 
1695
class cmd_ignore(Command):
 
1696
    """Ignore specified files or patterns.
 
1697
 
 
1698
    To remove patterns from the ignore list, edit the .bzrignore file.
 
1699
 
 
1700
    Trailing slashes on patterns are ignored. 
 
1701
    If the pattern contains a slash or is a regular expression, it is compared 
 
1702
    to the whole path from the branch root.  Otherwise, it is compared to only
 
1703
    the last component of the path.  To match a file only in the root 
 
1704
    directory, prepend './'.
 
1705
 
 
1706
    Ignore patterns specifying absolute paths are not allowed.
 
1707
 
 
1708
    Ignore patterns may include globbing wildcards such as:
 
1709
      ? - Matches any single character except '/'
 
1710
      * - Matches 0 or more characters except '/'
 
1711
      /**/ - Matches 0 or more directories in a path
 
1712
      [a-z] - Matches a single character from within a group of characters
 
1713
 
 
1714
    Ignore patterns may also be Python regular expressions.  
 
1715
    Regular expression ignore patterns are identified by a 'RE:' prefix 
 
1716
    followed by the regular expression.  Regular expression ignore patterns
 
1717
    may not include named or numbered groups.
 
1718
 
 
1719
    Note: ignore patterns containing shell wildcards must be quoted from 
 
1720
    the shell on Unix.
 
1721
 
 
1722
    examples:
 
1723
        bzr ignore ./Makefile
 
1724
        bzr ignore '*.class'
 
1725
        bzr ignore 'lib/**/*.o'
 
1726
        bzr ignore 'RE:lib/.*\.o'
 
1727
    """
 
1728
    takes_args = ['name_pattern*']
 
1729
    takes_options = [
 
1730
                     Option('old-default-rules',
 
1731
                            help='Out the ignore rules bzr < 0.9 always used.')
 
1732
                     ]
 
1733
    
 
1734
    def run(self, name_pattern_list=None, old_default_rules=None):
 
1735
        from bzrlib.atomicfile import AtomicFile
 
1736
        if old_default_rules is not None:
 
1737
            # dump the rules and exit
 
1738
            for pattern in ignores.OLD_DEFAULTS:
 
1739
                print pattern
 
1740
            return
 
1741
        if not name_pattern_list:
 
1742
            raise errors.BzrCommandError("ignore requires at least one "
 
1743
                                  "NAME_PATTERN or --old-default-rules")
 
1744
        for name_pattern in name_pattern_list:
 
1745
            if name_pattern[0] == '/':
 
1746
                raise errors.BzrCommandError(
 
1747
                    "NAME_PATTERN should not be an absolute path")
 
1748
        tree, relpath = WorkingTree.open_containing(u'.')
 
1749
        ifn = tree.abspath('.bzrignore')
 
1750
        if os.path.exists(ifn):
 
1751
            f = open(ifn, 'rt')
 
1752
            try:
 
1753
                igns = f.read().decode('utf-8')
 
1754
            finally:
 
1755
                f.close()
 
1756
        else:
 
1757
            igns = ''
 
1758
 
 
1759
        # TODO: If the file already uses crlf-style termination, maybe
 
1760
        # we should use that for the newly added lines?
 
1761
 
 
1762
        if igns and igns[-1] != '\n':
 
1763
            igns += '\n'
 
1764
        for name_pattern in name_pattern_list:
 
1765
            igns += name_pattern.rstrip('/') + '\n'
 
1766
 
 
1767
        f = AtomicFile(ifn, 'wb')
 
1768
        try:
 
1769
            f.write(igns.encode('utf-8'))
 
1770
            f.commit()
 
1771
        finally:
 
1772
            f.close()
 
1773
 
 
1774
        inv = tree.inventory
 
1775
        if inv.path2id('.bzrignore'):
 
1776
            mutter('.bzrignore is already versioned')
 
1777
        else:
 
1778
            mutter('need to make new .bzrignore file versioned')
 
1779
            tree.add(['.bzrignore'])
 
1780
 
 
1781
 
 
1782
class cmd_ignored(Command):
 
1783
    """List ignored files and the patterns that matched them.
 
1784
 
 
1785
    See also: bzr ignore"""
 
1786
    @display_command
 
1787
    def run(self):
 
1788
        tree = WorkingTree.open_containing(u'.')[0]
 
1789
        for path, file_class, kind, file_id, entry in tree.list_files():
 
1790
            if file_class != 'I':
 
1791
                continue
 
1792
            ## XXX: Slightly inefficient since this was already calculated
 
1793
            pat = tree.is_ignored(path)
 
1794
            print '%-50s %s' % (path, pat)
 
1795
 
 
1796
 
 
1797
class cmd_lookup_revision(Command):
 
1798
    """Lookup the revision-id from a revision-number
 
1799
 
 
1800
    example:
 
1801
        bzr lookup-revision 33
 
1802
    """
 
1803
    hidden = True
 
1804
    takes_args = ['revno']
 
1805
    
 
1806
    @display_command
 
1807
    def run(self, revno):
 
1808
        try:
 
1809
            revno = int(revno)
 
1810
        except ValueError:
 
1811
            raise errors.BzrCommandError("not a valid revision-number: %r" % revno)
 
1812
 
 
1813
        print WorkingTree.open_containing(u'.')[0].branch.get_rev_id(revno)
 
1814
 
 
1815
 
 
1816
class cmd_export(Command):
 
1817
    """Export past revision to destination directory.
 
1818
 
 
1819
    If no revision is specified this exports the last committed revision.
 
1820
 
 
1821
    Format may be an "exporter" name, such as tar, tgz, tbz2.  If none is
 
1822
    given, try to find the format with the extension. If no extension
 
1823
    is found exports to a directory (equivalent to --format=dir).
 
1824
 
 
1825
    Root may be the top directory for tar, tgz and tbz2 formats. If none
 
1826
    is given, the top directory will be the root name of the file.
 
1827
 
 
1828
    If branch is omitted then the branch containing the CWD will be used.
 
1829
 
 
1830
    Note: export of tree with non-ascii filenames to zip is not supported.
 
1831
 
 
1832
     Supported formats       Autodetected by extension
 
1833
     -----------------       -------------------------
 
1834
         dir                            -
 
1835
         tar                          .tar
 
1836
         tbz2                    .tar.bz2, .tbz2
 
1837
         tgz                      .tar.gz, .tgz
 
1838
         zip                          .zip
 
1839
    """
 
1840
    takes_args = ['dest', 'branch?']
 
1841
    takes_options = ['revision', 'format', 'root']
 
1842
    def run(self, dest, branch=None, revision=None, format=None, root=None):
 
1843
        from bzrlib.export import export
 
1844
 
 
1845
        if branch is None:
 
1846
            tree = WorkingTree.open_containing(u'.')[0]
 
1847
            b = tree.branch
 
1848
        else:
 
1849
            b = Branch.open(branch)
 
1850
            
 
1851
        if revision is None:
 
1852
            # should be tree.last_revision  FIXME
 
1853
            rev_id = b.last_revision()
 
1854
        else:
 
1855
            if len(revision) != 1:
 
1856
                raise errors.BzrCommandError('bzr export --revision takes exactly 1 argument')
 
1857
            rev_id = revision[0].in_history(b).rev_id
 
1858
        t = b.repository.revision_tree(rev_id)
 
1859
        try:
 
1860
            export(t, dest, format, root)
 
1861
        except errors.NoSuchExportFormat, e:
 
1862
            raise errors.BzrCommandError('Unsupported export format: %s' % e.format)
 
1863
 
 
1864
 
 
1865
class cmd_cat(Command):
 
1866
    """Write a file's text from a previous revision."""
 
1867
 
 
1868
    takes_options = ['revision', 'name-from-revision']
 
1869
    takes_args = ['filename']
 
1870
    encoding_type = 'exact'
 
1871
 
 
1872
    @display_command
 
1873
    def run(self, filename, revision=None, name_from_revision=False):
 
1874
        if revision is not None and len(revision) != 1:
 
1875
            raise errors.BzrCommandError("bzr cat --revision takes exactly"
 
1876
                                        " one number")
 
1877
 
 
1878
        tree = None
 
1879
        try:
 
1880
            tree, relpath = WorkingTree.open_containing(filename)
 
1881
            b = tree.branch
 
1882
        except (errors.NotBranchError, errors.NotLocalUrl):
 
1883
            pass
 
1884
 
 
1885
        if revision is not None and revision[0].get_branch() is not None:
 
1886
            b = Branch.open(revision[0].get_branch())
 
1887
        if tree is None:
 
1888
            b, relpath = Branch.open_containing(filename)
 
1889
            tree = b.basis_tree()
 
1890
        if revision is None:
 
1891
            revision_id = b.last_revision()
 
1892
        else:
 
1893
            revision_id = revision[0].in_history(b).rev_id
 
1894
 
 
1895
        cur_file_id = tree.path2id(relpath)
 
1896
        rev_tree = b.repository.revision_tree(revision_id)
 
1897
        old_file_id = rev_tree.path2id(relpath)
 
1898
        
 
1899
        if name_from_revision:
 
1900
            if old_file_id is None:
 
1901
                raise errors.BzrCommandError("%r is not present in revision %s"
 
1902
                                                % (filename, revision_id))
 
1903
            else:
 
1904
                rev_tree.print_file(old_file_id)
 
1905
        elif cur_file_id is not None:
 
1906
            rev_tree.print_file(cur_file_id)
 
1907
        elif old_file_id is not None:
 
1908
            rev_tree.print_file(old_file_id)
 
1909
        else:
 
1910
            raise errors.BzrCommandError("%r is not present in revision %s" %
 
1911
                                         (filename, revision_id))
 
1912
 
 
1913
 
 
1914
class cmd_local_time_offset(Command):
 
1915
    """Show the offset in seconds from GMT to local time."""
 
1916
    hidden = True    
 
1917
    @display_command
 
1918
    def run(self):
 
1919
        print osutils.local_time_offset()
 
1920
 
 
1921
 
 
1922
 
 
1923
class cmd_commit(Command):
 
1924
    """Commit changes into a new revision.
 
1925
    
 
1926
    If no arguments are given, the entire tree is committed.
 
1927
 
 
1928
    If selected files are specified, only changes to those files are
 
1929
    committed.  If a directory is specified then the directory and everything 
 
1930
    within it is committed.
 
1931
 
 
1932
    A selected-file commit may fail in some cases where the committed
 
1933
    tree would be invalid, such as trying to commit a file in a
 
1934
    newly-added directory that is not itself committed.
 
1935
    """
 
1936
    # TODO: Run hooks on tree to-be-committed, and after commit.
 
1937
 
 
1938
    # TODO: Strict commit that fails if there are deleted files.
 
1939
    #       (what does "deleted files" mean ??)
 
1940
 
 
1941
    # TODO: Give better message for -s, --summary, used by tla people
 
1942
 
 
1943
    # XXX: verbose currently does nothing
 
1944
 
 
1945
    takes_args = ['selected*']
 
1946
    takes_options = ['message', 'verbose', 
 
1947
                     Option('unchanged',
 
1948
                            help='commit even if nothing has changed'),
 
1949
                     Option('file', type=str, 
 
1950
                            short_name='F',
 
1951
                            argname='msgfile',
 
1952
                            help='file containing commit message'),
 
1953
                     Option('strict',
 
1954
                            help="refuse to commit if there are unknown "
 
1955
                            "files in the working tree."),
 
1956
                     Option('local',
 
1957
                            help="perform a local only commit in a bound "
 
1958
                                 "branch. Such commits are not pushed to "
 
1959
                                 "the master branch until a normal commit "
 
1960
                                 "is performed."
 
1961
                            ),
 
1962
                     ]
 
1963
    aliases = ['ci', 'checkin']
 
1964
 
 
1965
    def run(self, message=None, file=None, verbose=True, selected_list=None,
 
1966
            unchanged=False, strict=False, local=False):
 
1967
        from bzrlib.commit import (NullCommitReporter, ReportCommitToLog)
 
1968
        from bzrlib.errors import (PointlessCommit, ConflictsInTree,
 
1969
                StrictCommitFailed)
 
1970
        from bzrlib.msgeditor import edit_commit_message, \
 
1971
                make_commit_message_template
 
1972
 
 
1973
        # TODO: Need a blackbox test for invoking the external editor; may be
 
1974
        # slightly problematic to run this cross-platform.
 
1975
 
 
1976
        # TODO: do more checks that the commit will succeed before 
 
1977
        # spending the user's valuable time typing a commit message.
 
1978
        tree, selected_list = tree_files(selected_list)
 
1979
        if selected_list == ['']:
 
1980
            # workaround - commit of root of tree should be exactly the same
 
1981
            # as just default commit in that tree, and succeed even though
 
1982
            # selected-file merge commit is not done yet
 
1983
            selected_list = []
 
1984
 
 
1985
        if local and not tree.branch.get_bound_location():
 
1986
            raise errors.LocalRequiresBoundBranch()
 
1987
 
 
1988
        def get_message(commit_obj):
 
1989
            """Callback to get commit message"""
 
1990
            my_message = message
 
1991
            if my_message is None and not file:
 
1992
                template = make_commit_message_template(tree, selected_list)
 
1993
                my_message = edit_commit_message(template)
 
1994
                if my_message is None:
 
1995
                    raise errors.BzrCommandError("please specify a commit"
 
1996
                        " message with either --message or --file")
 
1997
            elif my_message and file:
 
1998
                raise errors.BzrCommandError(
 
1999
                    "please specify either --message or --file")
 
2000
            if file:
 
2001
                my_message = codecs.open(file, 'rt', 
 
2002
                                         bzrlib.user_encoding).read()
 
2003
            if my_message == "":
 
2004
                raise errors.BzrCommandError("empty commit message specified")
 
2005
            return my_message
 
2006
        
 
2007
        if verbose:
 
2008
            reporter = ReportCommitToLog()
 
2009
        else:
 
2010
            reporter = NullCommitReporter()
 
2011
 
 
2012
        try:
 
2013
            tree.commit(message_callback=get_message,
 
2014
                        specific_files=selected_list,
 
2015
                        allow_pointless=unchanged, strict=strict, local=local,
 
2016
                        reporter=reporter)
 
2017
        except PointlessCommit:
 
2018
            # FIXME: This should really happen before the file is read in;
 
2019
            # perhaps prepare the commit; get the message; then actually commit
 
2020
            raise errors.BzrCommandError("no changes to commit."
 
2021
                              " use --unchanged to commit anyhow")
 
2022
        except ConflictsInTree:
 
2023
            raise errors.BzrCommandError('Conflicts detected in working '
 
2024
                'tree.  Use "bzr conflicts" to list, "bzr resolve FILE" to'
 
2025
                ' resolve.')
 
2026
        except StrictCommitFailed:
 
2027
            raise errors.BzrCommandError("Commit refused because there are"
 
2028
                              " unknown files in the working tree.")
 
2029
        except errors.BoundBranchOutOfDate, e:
 
2030
            raise errors.BzrCommandError(str(e) + "\n"
 
2031
            'To commit to master branch, run update and then commit.\n'
 
2032
            'You can also pass --local to commit to continue working '
 
2033
            'disconnected.')
 
2034
 
 
2035
 
 
2036
class cmd_check(Command):
 
2037
    """Validate consistency of branch history.
 
2038
 
 
2039
    This command checks various invariants about the branch storage to
 
2040
    detect data corruption or bzr bugs.
 
2041
    """
 
2042
    takes_args = ['branch?']
 
2043
    takes_options = ['verbose']
 
2044
 
 
2045
    def run(self, branch=None, verbose=False):
 
2046
        from bzrlib.check import check
 
2047
        if branch is None:
 
2048
            tree = WorkingTree.open_containing()[0]
 
2049
            branch = tree.branch
 
2050
        else:
 
2051
            branch = Branch.open(branch)
 
2052
        check(branch, verbose)
 
2053
 
 
2054
 
 
2055
class cmd_upgrade(Command):
 
2056
    """Upgrade branch storage to current format.
 
2057
 
 
2058
    The check command or bzr developers may sometimes advise you to run
 
2059
    this command. When the default format has changed you may also be warned
 
2060
    during other operations to upgrade.
 
2061
    """
 
2062
    takes_args = ['url?']
 
2063
    takes_options = [
 
2064
                    RegistryOption('format',
 
2065
                        help='Upgrade to a specific format.  See "bzr help'
 
2066
                             ' formats" for details',
 
2067
                        registry=bzrdir.format_registry,
 
2068
                        converter=bzrdir.format_registry.make_bzrdir,
 
2069
                        value_switches=True, title='Branch format'),
 
2070
                    ]
 
2071
 
 
2072
 
 
2073
    def run(self, url='.', format=None):
 
2074
        from bzrlib.upgrade import upgrade
 
2075
        if format is None:
 
2076
            format = bzrdir.format_registry.make_bzrdir('default')
 
2077
        upgrade(url, format)
 
2078
 
 
2079
 
 
2080
class cmd_whoami(Command):
 
2081
    """Show or set bzr user id.
 
2082
    
 
2083
    examples:
 
2084
        bzr whoami --email
 
2085
        bzr whoami 'Frank Chu <fchu@example.com>'
 
2086
    """
 
2087
    takes_options = [ Option('email',
 
2088
                             help='display email address only'),
 
2089
                      Option('branch',
 
2090
                             help='set identity for the current branch instead of '
 
2091
                                  'globally'),
 
2092
                    ]
 
2093
    takes_args = ['name?']
 
2094
    encoding_type = 'replace'
 
2095
    
 
2096
    @display_command
 
2097
    def run(self, email=False, branch=False, name=None):
 
2098
        if name is None:
 
2099
            # use branch if we're inside one; otherwise global config
 
2100
            try:
 
2101
                c = Branch.open_containing('.')[0].get_config()
 
2102
            except errors.NotBranchError:
 
2103
                c = config.GlobalConfig()
 
2104
            if email:
 
2105
                self.outf.write(c.user_email() + '\n')
 
2106
            else:
 
2107
                self.outf.write(c.username() + '\n')
 
2108
            return
 
2109
 
 
2110
        # display a warning if an email address isn't included in the given name.
 
2111
        try:
 
2112
            config.extract_email_address(name)
 
2113
        except errors.NoEmailInUsername, e:
 
2114
            warning('"%s" does not seem to contain an email address.  '
 
2115
                    'This is allowed, but not recommended.', name)
 
2116
        
 
2117
        # use global config unless --branch given
 
2118
        if branch:
 
2119
            c = Branch.open_containing('.')[0].get_config()
 
2120
        else:
 
2121
            c = config.GlobalConfig()
 
2122
        c.set_user_option('email', name)
 
2123
 
 
2124
 
 
2125
class cmd_nick(Command):
 
2126
    """Print or set the branch nickname.  
 
2127
 
 
2128
    If unset, the tree root directory name is used as the nickname
 
2129
    To print the current nickname, execute with no argument.  
 
2130
    """
 
2131
    takes_args = ['nickname?']
 
2132
    def run(self, nickname=None):
 
2133
        branch = Branch.open_containing(u'.')[0]
 
2134
        if nickname is None:
 
2135
            self.printme(branch)
 
2136
        else:
 
2137
            branch.nick = nickname
 
2138
 
 
2139
    @display_command
 
2140
    def printme(self, branch):
 
2141
        print branch.nick 
 
2142
 
 
2143
 
 
2144
class cmd_selftest(Command):
 
2145
    """Run internal test suite.
 
2146
    
 
2147
    This creates temporary test directories in the working directory, but not
 
2148
    existing data is affected.  These directories are deleted if the tests
 
2149
    pass, or left behind to help in debugging if they fail and --keep-output
 
2150
    is specified.
 
2151
    
 
2152
    If arguments are given, they are regular expressions that say which tests
 
2153
    should run.  Tests matching any expression are run, and other tests are
 
2154
    not run.
 
2155
 
 
2156
    Alternatively if --first is given, matching tests are run first and then
 
2157
    all other tests are run.  This is useful if you have been working in a
 
2158
    particular area, but want to make sure nothing else was broken.
 
2159
 
 
2160
    If the global option '--no-plugins' is given, plugins are not loaded
 
2161
    before running the selftests.  This has two effects: features provided or
 
2162
    modified by plugins will not be tested, and tests provided by plugins will
 
2163
    not be run.
 
2164
 
 
2165
    examples::
 
2166
        bzr selftest ignore
 
2167
            run only tests relating to 'ignore'
 
2168
        bzr --no-plugins selftest -v
 
2169
            disable plugins and list tests as they're run
 
2170
    """
 
2171
    # TODO: --list should give a list of all available tests
 
2172
 
 
2173
    # NB: this is used from the class without creating an instance, which is
 
2174
    # why it does not have a self parameter.
 
2175
    def get_transport_type(typestring):
 
2176
        """Parse and return a transport specifier."""
 
2177
        if typestring == "sftp":
 
2178
            from bzrlib.transport.sftp import SFTPAbsoluteServer
 
2179
            return SFTPAbsoluteServer
 
2180
        if typestring == "memory":
 
2181
            from bzrlib.transport.memory import MemoryServer
 
2182
            return MemoryServer
 
2183
        if typestring == "fakenfs":
 
2184
            from bzrlib.transport.fakenfs import FakeNFSServer
 
2185
            return FakeNFSServer
 
2186
        msg = "No known transport type %s. Supported types are: sftp\n" %\
 
2187
            (typestring)
 
2188
        raise errors.BzrCommandError(msg)
 
2189
 
 
2190
    hidden = True
 
2191
    takes_args = ['testspecs*']
 
2192
    takes_options = ['verbose',
 
2193
                     Option('one', help='stop when one test fails'),
 
2194
                     Option('keep-output', 
 
2195
                            help='keep output directories when tests fail'),
 
2196
                     Option('transport', 
 
2197
                            help='Use a different transport by default '
 
2198
                                 'throughout the test suite.',
 
2199
                            type=get_transport_type),
 
2200
                     Option('benchmark', help='run the bzr bencharks.'),
 
2201
                     Option('lsprof-timed',
 
2202
                            help='generate lsprof output for benchmarked'
 
2203
                                 ' sections of code.'),
 
2204
                     Option('cache-dir', type=str,
 
2205
                            help='a directory to cache intermediate'
 
2206
                                 ' benchmark steps'),
 
2207
                     Option('clean-output',
 
2208
                            help='clean temporary tests directories'
 
2209
                                 ' without running tests'),
 
2210
                     Option('first',
 
2211
                            help='run all tests, but run specified tests first',
 
2212
                            )
 
2213
                     ]
 
2214
    encoding_type = 'replace'
 
2215
 
 
2216
    def run(self, testspecs_list=None, verbose=None, one=False,
 
2217
            keep_output=False, transport=None, benchmark=None,
 
2218
            lsprof_timed=None, cache_dir=None, clean_output=False,
 
2219
            first=False):
 
2220
        import bzrlib.ui
 
2221
        from bzrlib.tests import selftest
 
2222
        import bzrlib.benchmarks as benchmarks
 
2223
        from bzrlib.benchmarks import tree_creator
 
2224
 
 
2225
        if clean_output:
 
2226
            from bzrlib.tests import clean_selftest_output
 
2227
            clean_selftest_output()
 
2228
            return 0
 
2229
 
 
2230
        if cache_dir is not None:
 
2231
            tree_creator.TreeCreator.CACHE_ROOT = osutils.abspath(cache_dir)
 
2232
        print '%10s: %s' % ('bzr', osutils.realpath(sys.argv[0]))
 
2233
        print '%10s: %s' % ('bzrlib', bzrlib.__path__[0])
 
2234
        print
 
2235
        if testspecs_list is not None:
 
2236
            pattern = '|'.join(testspecs_list)
 
2237
        else:
 
2238
            pattern = ".*"
 
2239
        if benchmark:
 
2240
            test_suite_factory = benchmarks.test_suite
 
2241
            if verbose is None:
 
2242
                verbose = True
 
2243
            # TODO: should possibly lock the history file...
 
2244
            benchfile = open(".perf_history", "at", buffering=1)
 
2245
        else:
 
2246
            test_suite_factory = None
 
2247
            if verbose is None:
 
2248
                verbose = False
 
2249
            benchfile = None
 
2250
        try:
 
2251
            result = selftest(verbose=verbose, 
 
2252
                              pattern=pattern,
 
2253
                              stop_on_failure=one, 
 
2254
                              keep_output=keep_output,
 
2255
                              transport=transport,
 
2256
                              test_suite_factory=test_suite_factory,
 
2257
                              lsprof_timed=lsprof_timed,
 
2258
                              bench_history=benchfile,
 
2259
                              matching_tests_first=first,
 
2260
                              )
 
2261
        finally:
 
2262
            if benchfile is not None:
 
2263
                benchfile.close()
 
2264
        if result:
 
2265
            info('tests passed')
 
2266
        else:
 
2267
            info('tests failed')
 
2268
        return int(not result)
 
2269
 
 
2270
 
 
2271
class cmd_version(Command):
 
2272
    """Show version of bzr."""
 
2273
 
 
2274
    @display_command
 
2275
    def run(self):
 
2276
        from bzrlib.version import show_version
 
2277
        show_version()
 
2278
 
 
2279
 
 
2280
class cmd_rocks(Command):
 
2281
    """Statement of optimism."""
 
2282
 
 
2283
    hidden = True
 
2284
 
 
2285
    @display_command
 
2286
    def run(self):
 
2287
        print "it sure does!"
 
2288
 
 
2289
 
 
2290
class cmd_find_merge_base(Command):
 
2291
    """Find and print a base revision for merging two branches."""
 
2292
    # TODO: Options to specify revisions on either side, as if
 
2293
    #       merging only part of the history.
 
2294
    takes_args = ['branch', 'other']
 
2295
    hidden = True
 
2296
    
 
2297
    @display_command
 
2298
    def run(self, branch, other):
 
2299
        from bzrlib.revision import MultipleRevisionSources
 
2300
        
 
2301
        branch1 = Branch.open_containing(branch)[0]
 
2302
        branch2 = Branch.open_containing(other)[0]
 
2303
 
 
2304
        last1 = branch1.last_revision()
 
2305
        last2 = branch2.last_revision()
 
2306
 
 
2307
        source = MultipleRevisionSources(branch1.repository, 
 
2308
                                         branch2.repository)
 
2309
        
 
2310
        base_rev_id = common_ancestor(last1, last2, source)
 
2311
 
 
2312
        print 'merge base is revision %s' % base_rev_id
 
2313
 
 
2314
 
 
2315
class cmd_merge(Command):
 
2316
    """Perform a three-way merge.
 
2317
    
 
2318
    The branch is the branch you will merge from.  By default, it will merge
 
2319
    the latest revision.  If you specify a revision, that revision will be
 
2320
    merged.  If you specify two revisions, the first will be used as a BASE,
 
2321
    and the second one as OTHER.  Revision numbers are always relative to the
 
2322
    specified branch.
 
2323
 
 
2324
    By default, bzr will try to merge in all new work from the other
 
2325
    branch, automatically determining an appropriate base.  If this
 
2326
    fails, you may need to give an explicit base.
 
2327
    
 
2328
    Merge will do its best to combine the changes in two branches, but there
 
2329
    are some kinds of problems only a human can fix.  When it encounters those,
 
2330
    it will mark a conflict.  A conflict means that you need to fix something,
 
2331
    before you should commit.
 
2332
 
 
2333
    Use bzr resolve when you have fixed a problem.  See also bzr conflicts.
 
2334
 
 
2335
    If there is no default branch set, the first merge will set it. After
 
2336
    that, you can omit the branch to use the default.  To change the
 
2337
    default, use --remember. The value will only be saved if the remote
 
2338
    location can be accessed.
 
2339
 
 
2340
    Examples:
 
2341
 
 
2342
    To merge the latest revision from bzr.dev
 
2343
    bzr merge ../bzr.dev
 
2344
 
 
2345
    To merge changes up to and including revision 82 from bzr.dev
 
2346
    bzr merge -r 82 ../bzr.dev
 
2347
 
 
2348
    To merge the changes introduced by 82, without previous changes:
 
2349
    bzr merge -r 81..82 ../bzr.dev
 
2350
    
 
2351
    merge refuses to run if there are any uncommitted changes, unless
 
2352
    --force is given.
 
2353
 
 
2354
    The following merge types are available:
 
2355
    """
 
2356
    takes_args = ['branch?']
 
2357
    takes_options = ['revision', 'force', 'merge-type', 'reprocess', 'remember',
 
2358
                     Option('show-base', help="Show base revision text in "
 
2359
                            "conflicts"),
 
2360
                     Option('uncommitted', help='Apply uncommitted changes'
 
2361
                            ' from a working copy, instead of branch changes'),
 
2362
                     Option('pull', help='If the destination is already'
 
2363
                             ' completely merged into the source, pull from the'
 
2364
                             ' source rather than merging. When this happens,'
 
2365
                             ' you do not need to commit the result.'),
 
2366
                     ]
 
2367
 
 
2368
    def run(self, branch=None, revision=None, force=False, merge_type=None,
 
2369
            show_base=False, reprocess=False, remember=False, 
 
2370
            uncommitted=False, pull=False):
 
2371
        if merge_type is None:
 
2372
            merge_type = _mod_merge.Merge3Merger
 
2373
 
 
2374
        tree = WorkingTree.open_containing(u'.')[0]
 
2375
 
 
2376
        if branch is not None:
 
2377
            try:
 
2378
                reader = bundle.read_bundle_from_url(branch)
 
2379
            except errors.NotABundle:
 
2380
                pass # Continue on considering this url a Branch
 
2381
            else:
 
2382
                conflicts = merge_bundle(reader, tree, not force, merge_type,
 
2383
                                            reprocess, show_base)
 
2384
                if conflicts == 0:
 
2385
                    return 0
 
2386
                else:
 
2387
                    return 1
 
2388
 
 
2389
        if revision is None \
 
2390
                or len(revision) < 1 or revision[0].needs_branch():
 
2391
            branch = self._get_remembered_parent(tree, branch, 'Merging from')
 
2392
 
 
2393
        if revision is None or len(revision) < 1:
 
2394
            if uncommitted:
 
2395
                base = [branch, -1]
 
2396
                other = [branch, None]
 
2397
            else:
 
2398
                base = [None, None]
 
2399
                other = [branch, -1]
 
2400
            other_branch, path = Branch.open_containing(branch)
 
2401
        else:
 
2402
            if uncommitted:
 
2403
                raise errors.BzrCommandError('Cannot use --uncommitted and'
 
2404
                                             ' --revision at the same time.')
 
2405
            branch = revision[0].get_branch() or branch
 
2406
            if len(revision) == 1:
 
2407
                base = [None, None]
 
2408
                other_branch, path = Branch.open_containing(branch)
 
2409
                revno = revision[0].in_history(other_branch).revno
 
2410
                other = [branch, revno]
 
2411
            else:
 
2412
                assert len(revision) == 2
 
2413
                if None in revision:
 
2414
                    raise errors.BzrCommandError(
 
2415
                        "Merge doesn't permit empty revision specifier.")
 
2416
                base_branch, path = Branch.open_containing(branch)
 
2417
                branch1 = revision[1].get_branch() or branch
 
2418
                other_branch, path1 = Branch.open_containing(branch1)
 
2419
                if revision[0].get_branch() is not None:
 
2420
                    # then path was obtained from it, and is None.
 
2421
                    path = path1
 
2422
 
 
2423
                base = [branch, revision[0].in_history(base_branch).revno]
 
2424
                other = [branch1, revision[1].in_history(other_branch).revno]
 
2425
 
 
2426
        if tree.branch.get_parent() is None or remember:
 
2427
            tree.branch.set_parent(other_branch.base)
 
2428
 
 
2429
        if path != "":
 
2430
            interesting_files = [path]
 
2431
        else:
 
2432
            interesting_files = None
 
2433
        pb = ui.ui_factory.nested_progress_bar()
 
2434
        try:
 
2435
            try:
 
2436
                conflict_count = _merge_helper(
 
2437
                    other, base, check_clean=(not force),
 
2438
                    merge_type=merge_type,
 
2439
                    reprocess=reprocess,
 
2440
                    show_base=show_base,
 
2441
                    pull=pull,
 
2442
                    pb=pb, file_list=interesting_files)
 
2443
            finally:
 
2444
                pb.finished()
 
2445
            if conflict_count != 0:
 
2446
                return 1
 
2447
            else:
 
2448
                return 0
 
2449
        except errors.AmbiguousBase, e:
 
2450
            m = ("sorry, bzr can't determine the right merge base yet\n"
 
2451
                 "candidates are:\n  "
 
2452
                 + "\n  ".join(e.bases)
 
2453
                 + "\n"
 
2454
                 "please specify an explicit base with -r,\n"
 
2455
                 "and (if you want) report this to the bzr developers\n")
 
2456
            log_error(m)
 
2457
 
 
2458
    # TODO: move up to common parent; this isn't merge-specific anymore. 
 
2459
    def _get_remembered_parent(self, tree, supplied_location, verb_string):
 
2460
        """Use tree.branch's parent if none was supplied.
 
2461
 
 
2462
        Report if the remembered location was used.
 
2463
        """
 
2464
        if supplied_location is not None:
 
2465
            return supplied_location
 
2466
        stored_location = tree.branch.get_parent()
 
2467
        mutter("%s", stored_location)
 
2468
        if stored_location is None:
 
2469
            raise errors.BzrCommandError("No location specified or remembered")
 
2470
        display_url = urlutils.unescape_for_display(stored_location, self.outf.encoding)
 
2471
        self.outf.write("%s remembered location %s\n" % (verb_string, display_url))
 
2472
        return stored_location
 
2473
 
 
2474
 
 
2475
class cmd_remerge(Command):
 
2476
    """Redo a merge.
 
2477
 
 
2478
    Use this if you want to try a different merge technique while resolving
 
2479
    conflicts.  Some merge techniques are better than others, and remerge 
 
2480
    lets you try different ones on different files.
 
2481
 
 
2482
    The options for remerge have the same meaning and defaults as the ones for
 
2483
    merge.  The difference is that remerge can (only) be run when there is a
 
2484
    pending merge, and it lets you specify particular files.
 
2485
 
 
2486
    Examples:
 
2487
    $ bzr remerge --show-base
 
2488
        Re-do the merge of all conflicted files, and show the base text in
 
2489
        conflict regions, in addition to the usual THIS and OTHER texts.
 
2490
 
 
2491
    $ bzr remerge --merge-type weave --reprocess foobar
 
2492
        Re-do the merge of "foobar", using the weave merge algorithm, with
 
2493
        additional processing to reduce the size of conflict regions.
 
2494
    
 
2495
    The following merge types are available:"""
 
2496
    takes_args = ['file*']
 
2497
    takes_options = ['merge-type', 'reprocess',
 
2498
                     Option('show-base', help="Show base revision text in "
 
2499
                            "conflicts")]
 
2500
 
 
2501
    def run(self, file_list=None, merge_type=None, show_base=False,
 
2502
            reprocess=False):
 
2503
        if merge_type is None:
 
2504
            merge_type = _mod_merge.Merge3Merger
 
2505
        tree, file_list = tree_files(file_list)
 
2506
        tree.lock_write()
 
2507
        try:
 
2508
            parents = tree.get_parent_ids()
 
2509
            if len(parents) != 2:
 
2510
                raise errors.BzrCommandError("Sorry, remerge only works after normal"
 
2511
                                             " merges.  Not cherrypicking or"
 
2512
                                             " multi-merges.")
 
2513
            repository = tree.branch.repository
 
2514
            base_revision = common_ancestor(parents[0],
 
2515
                                            parents[1], repository)
 
2516
            base_tree = repository.revision_tree(base_revision)
 
2517
            other_tree = repository.revision_tree(parents[1])
 
2518
            interesting_ids = None
 
2519
            new_conflicts = []
 
2520
            conflicts = tree.conflicts()
 
2521
            if file_list is not None:
 
2522
                interesting_ids = set()
 
2523
                for filename in file_list:
 
2524
                    file_id = tree.path2id(filename)
 
2525
                    if file_id is None:
 
2526
                        raise errors.NotVersionedError(filename)
 
2527
                    interesting_ids.add(file_id)
 
2528
                    if tree.kind(file_id) != "directory":
 
2529
                        continue
 
2530
                    
 
2531
                    for name, ie in tree.inventory.iter_entries(file_id):
 
2532
                        interesting_ids.add(ie.file_id)
 
2533
                new_conflicts = conflicts.select_conflicts(tree, file_list)[0]
 
2534
            else:
 
2535
                # Remerge only supports resolving contents conflicts
 
2536
                allowed_conflicts = ('text conflict', 'contents conflict')
 
2537
                restore_files = [c.path for c in conflicts
 
2538
                                 if c.typestring in allowed_conflicts]
 
2539
            _mod_merge.transform_tree(tree, tree.basis_tree(), interesting_ids)
 
2540
            tree.set_conflicts(ConflictList(new_conflicts))
 
2541
            if file_list is not None:
 
2542
                restore_files = file_list
 
2543
            for filename in restore_files:
 
2544
                try:
 
2545
                    restore(tree.abspath(filename))
 
2546
                except errors.NotConflicted:
 
2547
                    pass
 
2548
            conflicts = _mod_merge.merge_inner(
 
2549
                                      tree.branch, other_tree, base_tree,
 
2550
                                      this_tree=tree,
 
2551
                                      interesting_ids=interesting_ids,
 
2552
                                      other_rev_id=parents[1],
 
2553
                                      merge_type=merge_type,
 
2554
                                      show_base=show_base,
 
2555
                                      reprocess=reprocess)
 
2556
        finally:
 
2557
            tree.unlock()
 
2558
        if conflicts > 0:
 
2559
            return 1
 
2560
        else:
 
2561
            return 0
 
2562
 
 
2563
 
 
2564
class cmd_revert(Command):
 
2565
    """Revert files to a previous revision.
 
2566
 
 
2567
    Giving a list of files will revert only those files.  Otherwise, all files
 
2568
    will be reverted.  If the revision is not specified with '--revision', the
 
2569
    last committed revision is used.
 
2570
 
 
2571
    To remove only some changes, without reverting to a prior version, use
 
2572
    merge instead.  For example, "merge . --r-2..-3" will remove the changes
 
2573
    introduced by -2, without affecting the changes introduced by -1.  Or
 
2574
    to remove certain changes on a hunk-by-hunk basis, see the Shelf plugin.
 
2575
    
 
2576
    By default, any files that have been manually changed will be backed up
 
2577
    first.  (Files changed only by merge are not backed up.)  Backup files have
 
2578
    '.~#~' appended to their name, where # is a number.
 
2579
 
 
2580
    When you provide files, you can use their current pathname or the pathname
 
2581
    from the target revision.  So you can use revert to "undelete" a file by
 
2582
    name.  If you name a directory, all the contents of that directory will be
 
2583
    reverted.
 
2584
    """
 
2585
    takes_options = ['revision', 'no-backup']
 
2586
    takes_args = ['file*']
 
2587
    aliases = ['merge-revert']
 
2588
 
 
2589
    def run(self, revision=None, no_backup=False, file_list=None):
 
2590
        if file_list is not None:
 
2591
            if len(file_list) == 0:
 
2592
                raise errors.BzrCommandError("No files specified")
 
2593
        else:
 
2594
            file_list = []
 
2595
        
 
2596
        tree, file_list = tree_files(file_list)
 
2597
        if revision is None:
 
2598
            # FIXME should be tree.last_revision
 
2599
            rev_id = tree.last_revision()
 
2600
        elif len(revision) != 1:
 
2601
            raise errors.BzrCommandError('bzr revert --revision takes exactly 1 argument')
 
2602
        else:
 
2603
            rev_id = revision[0].in_history(tree.branch).rev_id
 
2604
        pb = ui.ui_factory.nested_progress_bar()
 
2605
        try:
 
2606
            tree.revert(file_list, 
 
2607
                        tree.branch.repository.revision_tree(rev_id),
 
2608
                        not no_backup, pb, report_changes=True)
 
2609
        finally:
 
2610
            pb.finished()
 
2611
 
 
2612
 
 
2613
class cmd_assert_fail(Command):
 
2614
    """Test reporting of assertion failures"""
 
2615
    # intended just for use in testing
 
2616
 
 
2617
    hidden = True
 
2618
 
 
2619
    def run(self):
 
2620
        raise AssertionError("always fails")
 
2621
 
 
2622
 
 
2623
class cmd_help(Command):
 
2624
    """Show help on a command or other topic.
 
2625
 
 
2626
    For a list of all available commands, say 'bzr help commands'.
 
2627
    """
 
2628
    takes_options = [Option('long', 'show help on all commands')]
 
2629
    takes_args = ['topic?']
 
2630
    aliases = ['?', '--help', '-?', '-h']
 
2631
    
 
2632
    @display_command
 
2633
    def run(self, topic=None, long=False):
 
2634
        import bzrlib.help
 
2635
        if topic is None and long:
 
2636
            topic = "commands"
 
2637
        bzrlib.help.help(topic)
 
2638
 
 
2639
 
 
2640
class cmd_shell_complete(Command):
 
2641
    """Show appropriate completions for context.
 
2642
 
 
2643
    For a list of all available commands, say 'bzr shell-complete'.
 
2644
    """
 
2645
    takes_args = ['context?']
 
2646
    aliases = ['s-c']
 
2647
    hidden = True
 
2648
    
 
2649
    @display_command
 
2650
    def run(self, context=None):
 
2651
        import shellcomplete
 
2652
        shellcomplete.shellcomplete(context)
 
2653
 
 
2654
 
 
2655
class cmd_fetch(Command):
 
2656
    """Copy in history from another branch but don't merge it.
 
2657
 
 
2658
    This is an internal method used for pull and merge.
 
2659
    """
 
2660
    hidden = True
 
2661
    takes_args = ['from_branch', 'to_branch']
 
2662
    def run(self, from_branch, to_branch):
 
2663
        from bzrlib.fetch import Fetcher
 
2664
        from_b = Branch.open(from_branch)
 
2665
        to_b = Branch.open(to_branch)
 
2666
        Fetcher(to_b, from_b)
 
2667
 
 
2668
 
 
2669
class cmd_missing(Command):
 
2670
    """Show unmerged/unpulled revisions between two branches.
 
2671
 
 
2672
    OTHER_BRANCH may be local or remote.
 
2673
    """
 
2674
    takes_args = ['other_branch?']
 
2675
    takes_options = [Option('reverse', 'Reverse the order of revisions'),
 
2676
                     Option('mine-only', 
 
2677
                            'Display changes in the local branch only'),
 
2678
                     Option('theirs-only', 
 
2679
                            'Display changes in the remote branch only'), 
 
2680
                     'log-format',
 
2681
                     'show-ids',
 
2682
                     'verbose'
 
2683
                     ]
 
2684
    encoding_type = 'replace'
 
2685
 
 
2686
    @display_command
 
2687
    def run(self, other_branch=None, reverse=False, mine_only=False,
 
2688
            theirs_only=False, log_format=None, long=False, short=False, line=False, 
 
2689
            show_ids=False, verbose=False):
 
2690
        from bzrlib.missing import find_unmerged, iter_log_data
 
2691
        from bzrlib.log import log_formatter
 
2692
        local_branch = Branch.open_containing(u".")[0]
 
2693
        parent = local_branch.get_parent()
 
2694
        if other_branch is None:
 
2695
            other_branch = parent
 
2696
            if other_branch is None:
 
2697
                raise errors.BzrCommandError("No peer location known or specified.")
 
2698
            display_url = urlutils.unescape_for_display(parent,
 
2699
                                                        self.outf.encoding)
 
2700
            print "Using last location: " + display_url
 
2701
 
 
2702
        remote_branch = Branch.open(other_branch)
 
2703
        if remote_branch.base == local_branch.base:
 
2704
            remote_branch = local_branch
 
2705
        local_branch.lock_read()
 
2706
        try:
 
2707
            remote_branch.lock_read()
 
2708
            try:
 
2709
                local_extra, remote_extra = find_unmerged(local_branch, remote_branch)
 
2710
                if (log_format is None):
 
2711
                    log_format = log.log_formatter_registry.get_default(
 
2712
                        local_branch)
 
2713
                lf = log_format(to_file=self.outf,
 
2714
                                show_ids=show_ids,
 
2715
                                show_timezone='original')
 
2716
                if reverse is False:
 
2717
                    local_extra.reverse()
 
2718
                    remote_extra.reverse()
 
2719
                if local_extra and not theirs_only:
 
2720
                    print "You have %d extra revision(s):" % len(local_extra)
 
2721
                    for data in iter_log_data(local_extra, local_branch.repository,
 
2722
                                              verbose):
 
2723
                        lf.show(*data)
 
2724
                    printed_local = True
 
2725
                else:
 
2726
                    printed_local = False
 
2727
                if remote_extra and not mine_only:
 
2728
                    if printed_local is True:
 
2729
                        print "\n\n"
 
2730
                    print "You are missing %d revision(s):" % len(remote_extra)
 
2731
                    for data in iter_log_data(remote_extra, remote_branch.repository, 
 
2732
                                              verbose):
 
2733
                        lf.show(*data)
 
2734
                if not remote_extra and not local_extra:
 
2735
                    status_code = 0
 
2736
                    print "Branches are up to date."
 
2737
                else:
 
2738
                    status_code = 1
 
2739
            finally:
 
2740
                remote_branch.unlock()
 
2741
        finally:
 
2742
            local_branch.unlock()
 
2743
        if not status_code and parent is None and other_branch is not None:
 
2744
            local_branch.lock_write()
 
2745
            try:
 
2746
                # handle race conditions - a parent might be set while we run.
 
2747
                if local_branch.get_parent() is None:
 
2748
                    local_branch.set_parent(remote_branch.base)
 
2749
            finally:
 
2750
                local_branch.unlock()
 
2751
        return status_code
 
2752
 
 
2753
 
 
2754
class cmd_plugins(Command):
 
2755
    """List plugins"""
 
2756
    hidden = True
 
2757
    @display_command
 
2758
    def run(self):
 
2759
        import bzrlib.plugin
 
2760
        from inspect import getdoc
 
2761
        for name, plugin in bzrlib.plugin.all_plugins().items():
 
2762
            if getattr(plugin, '__path__', None) is not None:
 
2763
                print plugin.__path__[0]
 
2764
            elif getattr(plugin, '__file__', None) is not None:
 
2765
                print plugin.__file__
 
2766
            else:
 
2767
                print repr(plugin)
 
2768
                
 
2769
            d = getdoc(plugin)
 
2770
            if d:
 
2771
                print '\t', d.split('\n')[0]
 
2772
 
 
2773
 
 
2774
class cmd_testament(Command):
 
2775
    """Show testament (signing-form) of a revision."""
 
2776
    takes_options = ['revision', 
 
2777
                     Option('long', help='Produce long-format testament'), 
 
2778
                     Option('strict', help='Produce a strict-format'
 
2779
                            ' testament')]
 
2780
    takes_args = ['branch?']
 
2781
    @display_command
 
2782
    def run(self, branch=u'.', revision=None, long=False, strict=False):
 
2783
        from bzrlib.testament import Testament, StrictTestament
 
2784
        if strict is True:
 
2785
            testament_class = StrictTestament
 
2786
        else:
 
2787
            testament_class = Testament
 
2788
        b = WorkingTree.open_containing(branch)[0].branch
 
2789
        b.lock_read()
 
2790
        try:
 
2791
            if revision is None:
 
2792
                rev_id = b.last_revision()
 
2793
            else:
 
2794
                rev_id = revision[0].in_history(b).rev_id
 
2795
            t = testament_class.from_revision(b.repository, rev_id)
 
2796
            if long:
 
2797
                sys.stdout.writelines(t.as_text_lines())
 
2798
            else:
 
2799
                sys.stdout.write(t.as_short_text())
 
2800
        finally:
 
2801
            b.unlock()
 
2802
 
 
2803
 
 
2804
class cmd_annotate(Command):
 
2805
    """Show the origin of each line in a file.
 
2806
 
 
2807
    This prints out the given file with an annotation on the left side
 
2808
    indicating which revision, author and date introduced the change.
 
2809
 
 
2810
    If the origin is the same for a run of consecutive lines, it is 
 
2811
    shown only at the top, unless the --all option is given.
 
2812
    """
 
2813
    # TODO: annotate directories; showing when each file was last changed
 
2814
    # TODO: if the working copy is modified, show annotations on that 
 
2815
    #       with new uncommitted lines marked
 
2816
    aliases = ['ann', 'blame', 'praise']
 
2817
    takes_args = ['filename']
 
2818
    takes_options = [Option('all', help='show annotations on all lines'),
 
2819
                     Option('long', help='show date in annotations'),
 
2820
                     'revision',
 
2821
                     'show-ids',
 
2822
                     ]
 
2823
 
 
2824
    @display_command
 
2825
    def run(self, filename, all=False, long=False, revision=None,
 
2826
            show_ids=False):
 
2827
        from bzrlib.annotate import annotate_file
 
2828
        tree, relpath = WorkingTree.open_containing(filename)
 
2829
        branch = tree.branch
 
2830
        branch.lock_read()
 
2831
        try:
 
2832
            if revision is None:
 
2833
                revision_id = branch.last_revision()
 
2834
            elif len(revision) != 1:
 
2835
                raise errors.BzrCommandError('bzr annotate --revision takes exactly 1 argument')
 
2836
            else:
 
2837
                revision_id = revision[0].in_history(branch).rev_id
 
2838
            file_id = tree.inventory.path2id(relpath)
 
2839
            tree = branch.repository.revision_tree(revision_id)
 
2840
            file_version = tree.inventory[file_id].revision
 
2841
            annotate_file(branch, file_version, file_id, long, all, sys.stdout,
 
2842
                          show_ids=show_ids)
 
2843
        finally:
 
2844
            branch.unlock()
 
2845
 
 
2846
 
 
2847
class cmd_re_sign(Command):
 
2848
    """Create a digital signature for an existing revision."""
 
2849
    # TODO be able to replace existing ones.
 
2850
 
 
2851
    hidden = True # is this right ?
 
2852
    takes_args = ['revision_id*']
 
2853
    takes_options = ['revision']
 
2854
    
 
2855
    def run(self, revision_id_list=None, revision=None):
 
2856
        import bzrlib.gpg as gpg
 
2857
        if revision_id_list is not None and revision is not None:
 
2858
            raise errors.BzrCommandError('You can only supply one of revision_id or --revision')
 
2859
        if revision_id_list is None and revision is None:
 
2860
            raise errors.BzrCommandError('You must supply either --revision or a revision_id')
 
2861
        b = WorkingTree.open_containing(u'.')[0].branch
 
2862
        gpg_strategy = gpg.GPGStrategy(b.get_config())
 
2863
        if revision_id_list is not None:
 
2864
            for revision_id in revision_id_list:
 
2865
                b.repository.sign_revision(revision_id, gpg_strategy)
 
2866
        elif revision is not None:
 
2867
            if len(revision) == 1:
 
2868
                revno, rev_id = revision[0].in_history(b)
 
2869
                b.repository.sign_revision(rev_id, gpg_strategy)
 
2870
            elif len(revision) == 2:
 
2871
                # are they both on rh- if so we can walk between them
 
2872
                # might be nice to have a range helper for arbitrary
 
2873
                # revision paths. hmm.
 
2874
                from_revno, from_revid = revision[0].in_history(b)
 
2875
                to_revno, to_revid = revision[1].in_history(b)
 
2876
                if to_revid is None:
 
2877
                    to_revno = b.revno()
 
2878
                if from_revno is None or to_revno is None:
 
2879
                    raise errors.BzrCommandError('Cannot sign a range of non-revision-history revisions')
 
2880
                for revno in range(from_revno, to_revno + 1):
 
2881
                    b.repository.sign_revision(b.get_rev_id(revno), 
 
2882
                                               gpg_strategy)
 
2883
            else:
 
2884
                raise errors.BzrCommandError('Please supply either one revision, or a range.')
 
2885
 
 
2886
 
 
2887
class cmd_bind(Command):
 
2888
    """Convert the current branch into a checkout of the supplied branch.
 
2889
 
 
2890
    Once converted into a checkout, commits must succeed on the master branch
 
2891
    before they will be applied to the local branch.
 
2892
 
 
2893
    See "help checkouts" for more information on checkouts.
 
2894
    """
 
2895
 
 
2896
    takes_args = ['location']
 
2897
    takes_options = []
 
2898
 
 
2899
    def run(self, location=None):
 
2900
        b, relpath = Branch.open_containing(u'.')
 
2901
        b_other = Branch.open(location)
 
2902
        try:
 
2903
            b.bind(b_other)
 
2904
        except errors.DivergedBranches:
 
2905
            raise errors.BzrCommandError('These branches have diverged.'
 
2906
                                         ' Try merging, and then bind again.')
 
2907
 
 
2908
 
 
2909
class cmd_unbind(Command):
 
2910
    """Convert the current checkout into a regular branch.
 
2911
 
 
2912
    After unbinding, the local branch is considered independent and subsequent
 
2913
    commits will be local only.
 
2914
 
 
2915
    See "help checkouts" for more information on checkouts.
 
2916
    """
 
2917
 
 
2918
    takes_args = []
 
2919
    takes_options = []
 
2920
 
 
2921
    def run(self):
 
2922
        b, relpath = Branch.open_containing(u'.')
 
2923
        if not b.unbind():
 
2924
            raise errors.BzrCommandError('Local branch is not bound')
 
2925
 
 
2926
 
 
2927
class cmd_uncommit(Command):
 
2928
    """Remove the last committed revision.
 
2929
 
 
2930
    --verbose will print out what is being removed.
 
2931
    --dry-run will go through all the motions, but not actually
 
2932
    remove anything.
 
2933
    
 
2934
    In the future, uncommit will create a revision bundle, which can then
 
2935
    be re-applied.
 
2936
    """
 
2937
 
 
2938
    # TODO: jam 20060108 Add an option to allow uncommit to remove
 
2939
    # unreferenced information in 'branch-as-repository' branches.
 
2940
    # TODO: jam 20060108 Add the ability for uncommit to remove unreferenced
 
2941
    # information in shared branches as well.
 
2942
    takes_options = ['verbose', 'revision',
 
2943
                    Option('dry-run', help='Don\'t actually make changes'),
 
2944
                    Option('force', help='Say yes to all questions.')]
 
2945
    takes_args = ['location?']
 
2946
    aliases = []
 
2947
 
 
2948
    def run(self, location=None,
 
2949
            dry_run=False, verbose=False,
 
2950
            revision=None, force=False):
 
2951
        from bzrlib.log import log_formatter, show_log
 
2952
        import sys
 
2953
        from bzrlib.uncommit import uncommit
 
2954
 
 
2955
        if location is None:
 
2956
            location = u'.'
 
2957
        control, relpath = bzrdir.BzrDir.open_containing(location)
 
2958
        try:
 
2959
            tree = control.open_workingtree()
 
2960
            b = tree.branch
 
2961
        except (errors.NoWorkingTree, errors.NotLocalUrl):
 
2962
            tree = None
 
2963
            b = control.open_branch()
 
2964
 
 
2965
        rev_id = None
 
2966
        if revision is None:
 
2967
            revno = b.revno()
 
2968
        else:
 
2969
            # 'bzr uncommit -r 10' actually means uncommit
 
2970
            # so that the final tree is at revno 10.
 
2971
            # but bzrlib.uncommit.uncommit() actually uncommits
 
2972
            # the revisions that are supplied.
 
2973
            # So we need to offset it by one
 
2974
            revno = revision[0].in_history(b).revno+1
 
2975
 
 
2976
        if revno <= b.revno():
 
2977
            rev_id = b.get_rev_id(revno)
 
2978
        if rev_id is None:
 
2979
            self.outf.write('No revisions to uncommit.\n')
 
2980
            return 1
 
2981
 
 
2982
        lf = log_formatter('short',
 
2983
                           to_file=self.outf,
 
2984
                           show_timezone='original')
 
2985
 
 
2986
        show_log(b,
 
2987
                 lf,
 
2988
                 verbose=False,
 
2989
                 direction='forward',
 
2990
                 start_revision=revno,
 
2991
                 end_revision=b.revno())
 
2992
 
 
2993
        if dry_run:
 
2994
            print 'Dry-run, pretending to remove the above revisions.'
 
2995
            if not force:
 
2996
                val = raw_input('Press <enter> to continue')
 
2997
        else:
 
2998
            print 'The above revision(s) will be removed.'
 
2999
            if not force:
 
3000
                val = raw_input('Are you sure [y/N]? ')
 
3001
                if val.lower() not in ('y', 'yes'):
 
3002
                    print 'Canceled'
 
3003
                    return 0
 
3004
 
 
3005
        uncommit(b, tree=tree, dry_run=dry_run, verbose=verbose,
 
3006
                revno=revno)
 
3007
 
 
3008
 
 
3009
class cmd_break_lock(Command):
 
3010
    """Break a dead lock on a repository, branch or working directory.
 
3011
 
 
3012
    CAUTION: Locks should only be broken when you are sure that the process
 
3013
    holding the lock has been stopped.
 
3014
 
 
3015
    You can get information on what locks are open via the 'bzr info' command.
 
3016
    
 
3017
    example:
 
3018
        bzr break-lock
 
3019
    """
 
3020
    takes_args = ['location?']
 
3021
 
 
3022
    def run(self, location=None, show=False):
 
3023
        if location is None:
 
3024
            location = u'.'
 
3025
        control, relpath = bzrdir.BzrDir.open_containing(location)
 
3026
        try:
 
3027
            control.break_lock()
 
3028
        except NotImplementedError:
 
3029
            pass
 
3030
        
 
3031
 
 
3032
class cmd_wait_until_signalled(Command):
 
3033
    """Test helper for test_start_and_stop_bzr_subprocess_send_signal.
 
3034
 
 
3035
    This just prints a line to signal when it is ready, then blocks on stdin.
 
3036
    """
 
3037
 
 
3038
    hidden = True
 
3039
 
 
3040
    def run(self):
 
3041
        sys.stdout.write("running\n")
 
3042
        sys.stdout.flush()
 
3043
        sys.stdin.readline()
 
3044
 
 
3045
 
 
3046
class cmd_serve(Command):
 
3047
    """Run the bzr server."""
 
3048
 
 
3049
    aliases = ['server']
 
3050
 
 
3051
    takes_options = [
 
3052
        Option('inet',
 
3053
               help='serve on stdin/out for use from inetd or sshd'),
 
3054
        Option('port',
 
3055
               help='listen for connections on nominated port of the form '
 
3056
                    '[hostname:]portnumber. Passing 0 as the port number will '
 
3057
                    'result in a dynamically allocated port.',
 
3058
               type=str),
 
3059
        Option('directory',
 
3060
               help='serve contents of directory',
 
3061
               type=unicode),
 
3062
        Option('allow-writes',
 
3063
               help='By default the server is a readonly server. Supplying '
 
3064
                    '--allow-writes enables write access to the contents of '
 
3065
                    'the served directory and below. '
 
3066
                ),
 
3067
        ]
 
3068
 
 
3069
    def run(self, port=None, inet=False, directory=None, allow_writes=False):
 
3070
        from bzrlib.transport import smart
 
3071
        from bzrlib.transport import get_transport
 
3072
        if directory is None:
 
3073
            directory = os.getcwd()
 
3074
        url = urlutils.local_path_to_url(directory)
 
3075
        if not allow_writes:
 
3076
            url = 'readonly+' + url
 
3077
        t = get_transport(url)
 
3078
        if inet:
 
3079
            server = smart.SmartServerPipeStreamMedium(sys.stdin, sys.stdout, t)
 
3080
        elif port is not None:
 
3081
            if ':' in port:
 
3082
                host, port = port.split(':')
 
3083
            else:
 
3084
                host = '127.0.0.1'
 
3085
            server = smart.SmartTCPServer(t, host=host, port=int(port))
 
3086
            print 'listening on port: ', server.port
 
3087
            sys.stdout.flush()
 
3088
        else:
 
3089
            raise errors.BzrCommandError("bzr serve requires one of --inet or --port")
 
3090
        server.serve()
 
3091
 
 
3092
 
 
3093
# command-line interpretation helper for merge-related commands
 
3094
def _merge_helper(other_revision, base_revision,
 
3095
                  check_clean=True, ignore_zero=False,
 
3096
                  this_dir=None, backup_files=False,
 
3097
                  merge_type=None,
 
3098
                  file_list=None, show_base=False, reprocess=False,
 
3099
                  pull=False,
 
3100
                  pb=DummyProgress()):
 
3101
    """Merge changes into a tree.
 
3102
 
 
3103
    base_revision
 
3104
        list(path, revno) Base for three-way merge.  
 
3105
        If [None, None] then a base will be automatically determined.
 
3106
    other_revision
 
3107
        list(path, revno) Other revision for three-way merge.
 
3108
    this_dir
 
3109
        Directory to merge changes into; '.' by default.
 
3110
    check_clean
 
3111
        If true, this_dir must have no uncommitted changes before the
 
3112
        merge begins.
 
3113
    ignore_zero - If true, suppress the "zero conflicts" message when 
 
3114
        there are no conflicts; should be set when doing something we expect
 
3115
        to complete perfectly.
 
3116
    file_list - If supplied, merge only changes to selected files.
 
3117
 
 
3118
    All available ancestors of other_revision and base_revision are
 
3119
    automatically pulled into the branch.
 
3120
 
 
3121
    The revno may be -1 to indicate the last revision on the branch, which is
 
3122
    the typical case.
 
3123
 
 
3124
    This function is intended for use from the command line; programmatic
 
3125
    clients might prefer to call merge.merge_inner(), which has less magic 
 
3126
    behavior.
 
3127
    """
 
3128
    # Loading it late, so that we don't always have to import bzrlib.merge
 
3129
    if merge_type is None:
 
3130
        merge_type = _mod_merge.Merge3Merger
 
3131
    if this_dir is None:
 
3132
        this_dir = u'.'
 
3133
    this_tree = WorkingTree.open_containing(this_dir)[0]
 
3134
    if show_base and not merge_type is _mod_merge.Merge3Merger:
 
3135
        raise errors.BzrCommandError("Show-base is not supported for this merge"
 
3136
                                     " type. %s" % merge_type)
 
3137
    if reprocess and not merge_type.supports_reprocess:
 
3138
        raise errors.BzrCommandError("Conflict reduction is not supported for merge"
 
3139
                                     " type %s." % merge_type)
 
3140
    if reprocess and show_base:
 
3141
        raise errors.BzrCommandError("Cannot do conflict reduction and show base.")
 
3142
    try:
 
3143
        merger = _mod_merge.Merger(this_tree.branch, this_tree=this_tree,
 
3144
                                   pb=pb)
 
3145
        merger.pp = ProgressPhase("Merge phase", 5, pb)
 
3146
        merger.pp.next_phase()
 
3147
        merger.check_basis(check_clean)
 
3148
        merger.set_other(other_revision)
 
3149
        merger.pp.next_phase()
 
3150
        merger.set_base(base_revision)
 
3151
        if merger.base_rev_id == merger.other_rev_id:
 
3152
            note('Nothing to do.')
 
3153
            return 0
 
3154
        if file_list is None:
 
3155
            if pull and merger.base_rev_id == merger.this_rev_id:
 
3156
                count = merger.this_tree.pull(merger.this_branch,
 
3157
                        False, merger.other_rev_id)
 
3158
                note('%d revision(s) pulled.' % (count,))
 
3159
                return 0
 
3160
        merger.backup_files = backup_files
 
3161
        merger.merge_type = merge_type 
 
3162
        merger.set_interesting_files(file_list)
 
3163
        merger.show_base = show_base 
 
3164
        merger.reprocess = reprocess
 
3165
        conflicts = merger.do_merge()
 
3166
        if file_list is None:
 
3167
            merger.set_pending()
 
3168
    finally:
 
3169
        pb.clear()
 
3170
    return conflicts
 
3171
 
 
3172
 
 
3173
# Compatibility
 
3174
merge = _merge_helper
 
3175
 
 
3176
 
 
3177
# these get imported and then picked up by the scan for cmd_*
 
3178
# TODO: Some more consistent way to split command definitions across files;
 
3179
# we do need to load at least some information about them to know of 
 
3180
# aliases.  ideally we would avoid loading the implementation until the
 
3181
# details were needed.
 
3182
from bzrlib.cmd_version_info import cmd_version_info
 
3183
from bzrlib.conflicts import cmd_resolve, cmd_conflicts, restore
 
3184
from bzrlib.bundle.commands import cmd_bundle_revisions
 
3185
from bzrlib.sign_my_commits import cmd_sign_my_commits
 
3186
from bzrlib.weave_commands import cmd_weave_list, cmd_weave_join, \
 
3187
        cmd_weave_plan_merge, cmd_weave_merge_text