~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/builtins.py

  • Committer: Robert Collins
  • Date: 2005-10-06 22:15:52 UTC
  • mfrom: (1185.13.2)
  • mto: This revision was merged to the branch mainline in revision 1420.
  • Revision ID: robertc@robertcollins.net-20051006221552-9b15c96fa504e0ad
mergeĀ fromĀ upstream

Show diffs side-by-side

added added

removed removed

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