~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/builtins.py

  • Committer: Robert Collins
  • Date: 2006-03-01 03:26:23 UTC
  • mto: (1594.2.4 integration)
  • mto: This revision was merged to the branch mainline in revision 1596.
  • Revision ID: robertc@robertcollins.net-20060301032623-9d3c073e102f2239
Move WeaveStore down into bzrlib.store.versioned.weave.

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
17
"""builtin bzr commands"""
18
18
 
 
19
 
 
20
import errno
19
21
import os
20
 
 
21
 
from bzrlib.lazy_import import lazy_import
22
 
lazy_import(globals(), """
23
 
import codecs
24
 
import errno
 
22
from shutil import rmtree
25
23
import sys
26
 
import tempfile
27
24
 
28
25
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
 
    )
 
26
import bzrlib.branch
47
27
from bzrlib.branch import Branch
48
 
from bzrlib.bundle.apply_bundle import install_bundle, merge_bundle
49
 
from bzrlib.conflicts import ConflictList
 
28
import bzrlib.bzrdir as bzrdir
 
29
from bzrlib.commands import Command, display_command
50
30
from bzrlib.revision import common_ancestor
 
31
import bzrlib.errors as errors
 
32
from bzrlib.errors import (BzrError, BzrCheckError, BzrCommandError, 
 
33
                           NotBranchError, DivergedBranches, NotConflicted,
 
34
                           NoSuchFile, NoWorkingTree, FileInWrongBranch)
 
35
from bzrlib.log import show_one_log
 
36
from bzrlib.merge import Merge3Merger
 
37
from bzrlib.option import Option
 
38
from bzrlib.progress import DummyProgress
51
39
from bzrlib.revisionspec import RevisionSpec
 
40
import bzrlib.trace
 
41
from bzrlib.trace import mutter, note, log_error, warning, is_quiet
 
42
from bzrlib.transport.local import LocalTransport
 
43
import bzrlib.ui
52
44
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
45
 
60
46
 
61
47
def tree_files(file_list, default_branch=u'.'):
62
48
    try:
63
49
        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.
 
50
    except FileInWrongBranch, e:
 
51
        raise BzrCommandError("%s is not in the same branch as %s" %
 
52
                             (e.path, file_list[0]))
 
53
 
71
54
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]
 
55
    """\
 
56
    Return a branch and list of branch-relative paths.
 
57
    If supplied file_list is empty or None, the branch default will be used,
 
58
    and returned file_list will match the original.
85
59
    """
86
60
    if file_list is None or len(file_list) == 0:
87
61
        return WorkingTree.open_containing(default_branch)[0], file_list
88
 
    tree = WorkingTree.open_containing(osutils.realpath(file_list[0]))[0]
 
62
    tree = WorkingTree.open_containing(file_list[0])[0]
89
63
    new_list = []
90
64
    for filename in file_list:
91
65
        try:
92
 
            new_list.append(tree.relpath(osutils.dereference_path(filename)))
 
66
            new_list.append(tree.relpath(filename))
93
67
        except errors.PathNotChild:
94
 
            raise errors.FileInWrongBranch(tree.branch, filename)
 
68
            raise FileInWrongBranch(tree.branch, filename)
95
69
    return tree, new_list
96
70
 
97
71
 
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
72
# TODO: Make sure no commands unconditionally use the working directory as a
113
73
# branch.  If a filename argument is used, the first of them should be used to
114
74
# specify the branch.  (Perhaps this can be factored out into some kind of
136
96
    modified
137
97
        Text has changed since the previous revision.
138
98
 
139
 
    kind changed
140
 
        File kind has been changed (e.g. from file to directory).
 
99
    unchanged
 
100
        Nothing about this file has changed since the previous revision.
 
101
        Only shown with --all.
141
102
 
142
103
    unknown
143
104
        Not versioned and not matching an ignore pattern.
144
105
 
145
106
    To see ignored files use 'bzr ignored'.  For details in the
146
107
    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
108
 
168
109
    If no arguments are specified, the status of the entire working
169
110
    directory is shown.  Otherwise, only the status of the specified
177
118
    # TODO: --no-recurse, --recurse options
178
119
    
179
120
    takes_args = ['file*']
180
 
    takes_options = ['show-ids', 'revision', 'short']
 
121
    takes_options = ['all', 'show-ids', 'revision']
181
122
    aliases = ['st', 'stat']
182
 
 
183
 
    encoding_type = 'replace'
184
123
    
185
124
    @display_command
186
 
    def run(self, show_ids=False, file_list=None, revision=None, short=False):
 
125
    def run(self, all=False, show_ids=False, file_list=None, revision=None):
 
126
        tree, file_list = tree_files(file_list)
 
127
            
187
128
        from bzrlib.status import show_tree_status
188
 
 
189
 
        tree, file_list = tree_files(file_list)
190
 
            
191
 
        show_tree_status(tree, show_ids=show_ids,
192
 
                         specific_files=file_list, revision=revision,
193
 
                         to_file=self.outf,
194
 
                         short=short)
 
129
        show_tree_status(tree, show_unchanged=all, show_ids=show_ids,
 
130
                         specific_files=file_list, revision=revision)
195
131
 
196
132
 
197
133
class cmd_cat_revision(Command):
204
140
    hidden = True
205
141
    takes_args = ['revision_id?']
206
142
    takes_options = ['revision']
207
 
    # cat-revision is more for frontends so should be exact
208
 
    encoding = 'strict'
209
143
    
210
144
    @display_command
211
145
    def run(self, revision_id=None, revision=None):
212
146
 
213
147
        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')
 
148
            raise BzrCommandError('You can only supply one of revision_id or --revision')
216
149
        if revision_id is None and revision is None:
217
 
            raise errors.BzrCommandError('You must supply either'
218
 
                                         ' --revision or a revision_id')
 
150
            raise BzrCommandError('You must supply either --revision or a revision_id')
219
151
        b = WorkingTree.open_containing(u'.')[0].branch
220
 
 
221
 
        # TODO: jam 20060112 should cat-revision always output utf-8?
222
152
        if revision_id is not None:
223
 
            self.outf.write(b.repository.get_revision_xml(revision_id).decode('utf-8'))
 
153
            sys.stdout.write(b.repository.get_revision_xml(revision_id))
224
154
        elif revision is not None:
225
155
            for rev in revision:
226
156
                if rev is None:
227
 
                    raise errors.BzrCommandError('You cannot specify a NULL'
228
 
                                                 ' revision.')
 
157
                    raise BzrCommandError('You cannot specify a NULL revision.')
229
158
                revno, rev_id = rev.in_history(b)
230
 
                self.outf.write(b.repository.get_revision_xml(rev_id).decode('utf-8'))
 
159
                sys.stdout.write(b.repository.get_revision_xml(rev_id))
231
160
    
232
161
 
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
162
class cmd_revno(Command):
263
163
    """Show current revision number.
264
164
 
265
 
    This is equal to the number of revisions on this branch.
266
 
    """
267
 
 
 
165
    This is equal to the number of revisions on this branch."""
268
166
    takes_args = ['location?']
269
 
 
270
167
    @display_command
271
168
    def run(self, location=u'.'):
272
 
        self.outf.write(str(Branch.open_containing(location)[0].revno()))
273
 
        self.outf.write('\n')
 
169
        print Branch.open_containing(location)[0].revno()
274
170
 
275
171
 
276
172
class cmd_revision_info(Command):
279
175
    hidden = True
280
176
    takes_args = ['revision_info*']
281
177
    takes_options = ['revision']
282
 
 
283
178
    @display_command
284
179
    def run(self, revision=None, revision_info_list=[]):
285
180
 
288
183
            revs.extend(revision)
289
184
        if revision_info_list is not None:
290
185
            for rev in revision_info_list:
291
 
                revs.append(RevisionSpec.from_string(rev))
 
186
                revs.append(RevisionSpec(rev))
292
187
        if len(revs) == 0:
293
 
            raise errors.BzrCommandError('You must supply a revision identifier')
 
188
            raise BzrCommandError('You must supply a revision identifier')
294
189
 
295
190
        b = WorkingTree.open_containing(u'.')[0].branch
296
191
 
322
217
 
323
218
    Adding a file whose parent directory is not versioned will
324
219
    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
 
220
    you should never need to explictly add a directory, they'll just
326
221
    get added when you add a file in the directory.
327
222
 
328
223
    --dry-run will show which files would be added, but not actually 
329
224
    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
225
    """
335
226
    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'
 
227
    takes_options = ['no-recurse', 'dry-run', 'verbose']
340
228
 
341
 
    def run(self, file_list, no_recurse=False, dry_run=False, verbose=False,
342
 
            file_ids_from=None):
 
229
    def run(self, file_list, no_recurse=False, dry_run=False, verbose=False):
343
230
        import bzrlib.add
344
231
 
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()))
 
232
        if dry_run:
 
233
            if is_quiet():
 
234
                # This is pointless, but I'd rather not raise an error
 
235
                action = bzrlib.add.add_action_null
 
236
            else:
 
237
                action = bzrlib.add.add_action_print
 
238
        elif is_quiet():
 
239
            action = bzrlib.add.add_action_add
356
240
        else:
357
 
            action = bzrlib.add.AddAction(to_file=self.outf,
358
 
                should_print=(not is_quiet()))
 
241
            action = bzrlib.add.add_action_add_and_print
359
242
 
360
 
        added, ignored = bzrlib.add.smart_add(file_list, not no_recurse,
361
 
                                              action=action, save=not dry_run)
 
243
        added, ignored = bzrlib.add.smart_add(file_list, not no_recurse, 
 
244
                                              action)
362
245
        if len(ignored) > 0:
363
 
            if verbose:
364
 
                for glob in sorted(ignored.keys()):
 
246
            for glob in sorted(ignored.keys()):
 
247
                match_len = len(ignored[glob])
 
248
                if verbose:
365
249
                    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")
 
250
                        print "ignored %s matching \"%s\"" % (path, glob)
 
251
                else:
 
252
                    print "ignored %d file(s) matching \"%s\"" % (match_len,
 
253
                                                              glob)
 
254
            print "If you wish to add some of these files, please add them"\
 
255
                " by name."
375
256
 
376
257
 
377
258
class cmd_mkdir(Command):
379
260
 
380
261
    This is equivalent to creating the directory and then adding it.
381
262
    """
382
 
 
383
263
    takes_args = ['dir+']
384
 
    encoding_type = 'replace'
385
264
 
386
265
    def run(self, dir_list):
387
266
        for d in dir_list:
388
267
            os.mkdir(d)
389
268
            wt, dd = WorkingTree.open_containing(d)
390
269
            wt.add([dd])
391
 
            self.outf.write('added %s\n' % d)
 
270
            print 'added', d
392
271
 
393
272
 
394
273
class cmd_relpath(Command):
395
274
    """Show path of a file relative to root"""
396
 
 
397
275
    takes_args = ['filename']
398
276
    hidden = True
399
277
    
400
278
    @display_command
401
279
    def run(self, filename):
402
 
        # TODO: jam 20050106 Can relpath return a munged path if
403
 
        #       sys.stdout encoding cannot represent it?
404
280
        tree, relpath = WorkingTree.open_containing(filename)
405
 
        self.outf.write(relpath)
406
 
        self.outf.write('\n')
 
281
        print relpath
407
282
 
408
283
 
409
284
class cmd_inventory(Command):
410
285
    """Show inventory of the current working copy or a revision.
411
286
 
412
287
    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
 
288
    type using the --kind option.  For example; --kind file.
419
289
    """
420
 
 
421
 
    hidden = True
422
 
 
423
290
    takes_options = ['revision', 'show-ids', 'kind']
424
 
 
425
 
    takes_args = ['file*']
426
 
 
 
291
    
427
292
    @display_command
428
 
    def run(self, revision=None, show_ids=False, kind=None, file_list=None):
 
293
    def run(self, revision=None, show_ids=False, kind=None):
429
294
        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:
 
295
            raise BzrCommandError('invalid kind specified')
 
296
        tree = WorkingTree.open_containing(u'.')[0]
 
297
        if revision is None:
 
298
            inv = tree.read_working_inventory()
 
299
        else:
 
300
            if len(revision) > 1:
 
301
                raise BzrCommandError('bzr inventory --revision takes'
 
302
                    ' exactly one revision identifier')
 
303
            inv = tree.branch.repository.get_revision_inventory(
 
304
                revision[0].in_history(tree.branch).rev_id)
 
305
 
 
306
        for path, entry in inv.entries():
464
307
            if kind and kind != entry.kind:
465
308
                continue
466
309
            if show_ids:
467
 
                self.outf.write('%-50s %s\n' % (path, entry.file_id))
 
310
                print '%-50s %s' % (path, entry.file_id)
468
311
            else:
469
 
                self.outf.write(path)
470
 
                self.outf.write('\n')
 
312
                print path
 
313
 
 
314
 
 
315
class cmd_move(Command):
 
316
    """Move files to a different directory.
 
317
 
 
318
    examples:
 
319
        bzr move *.txt doc
 
320
 
 
321
    The destination must be a versioned directory in the same branch.
 
322
    """
 
323
    takes_args = ['source$', 'dest']
 
324
    def run(self, source_list, dest):
 
325
        tree, source_list = tree_files(source_list)
 
326
        # TODO: glob expansion on windows?
 
327
        tree.move(source_list, tree.relpath(dest))
 
328
 
 
329
 
 
330
class cmd_rename(Command):
 
331
    """Change the name of an entry.
 
332
 
 
333
    examples:
 
334
      bzr rename frob.c frobber.c
 
335
      bzr rename src/frob.c lib/frob.c
 
336
 
 
337
    It is an error if the destination name exists.
 
338
 
 
339
    See also the 'move' command, which moves files into a different
 
340
    directory without changing their name.
 
341
    """
 
342
    # TODO: Some way to rename multiple files without invoking 
 
343
    # bzr for each one?"""
 
344
    takes_args = ['from_name', 'to_name']
 
345
    
 
346
    def run(self, from_name, to_name):
 
347
        tree, (from_name, to_name) = tree_files((from_name, to_name))
 
348
        tree.rename_one(from_name, to_name)
471
349
 
472
350
 
473
351
class cmd_mv(Command):
479
357
 
480
358
    If the last argument is a versioned directory, all the other names
481
359
    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.
 
360
    and the file is changed to a new name, which must not already exist.
489
361
 
490
362
    Files cannot be moved between branches.
491
363
    """
492
 
 
493
364
    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
 
 
 
365
    def run(self, names_list):
504
366
        if len(names_list) < 2:
505
 
            raise errors.BzrCommandError("missing file argument")
 
367
            raise BzrCommandError("missing file argument")
506
368
        tree, rel_names = tree_files(names_list)
507
369
        
508
370
        if os.path.isdir(names_list[-1]):
509
371
            # 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)
 
372
            for pair in tree.move(rel_names[:-1], rel_names[-1]):
 
373
                print "%s => %s" % pair
512
374
        else:
513
375
            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]))
 
376
                raise BzrCommandError('to mv multiple files the destination '
 
377
                                      'must be a versioned directory')
 
378
            tree.rename_one(rel_names[0], rel_names[1])
 
379
            print "%s => %s" % (rel_names[0], rel_names[1])
519
380
            
520
381
    
521
382
class cmd_pull(Command):
522
 
    """Turn this branch into a mirror of another branch.
 
383
    """Pull any changes from another branch into the current one.
 
384
 
 
385
    If there is no default location set, the first pull will set it.  After
 
386
    that, you can omit the location to use the default.  To change the
 
387
    default, use --remember.
523
388
 
524
389
    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.
 
390
    considered diverged if both branches have had commits without first
 
391
    pulling from the other.
527
392
 
528
 
    If branches have diverged, you can use 'bzr merge' to integrate the changes
 
393
    If branches have diverged, you can use 'bzr merge' to pull the text changes
529
394
    from one into the other.  Once one branch has merged, the other should
530
395
    be able to pull it again.
531
396
 
532
397
    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.
 
398
    match the remote one, use --overwrite.
539
399
    """
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
 
        ]
 
400
    takes_options = ['remember', 'overwrite', 'revision', 'verbose']
549
401
    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()
 
402
 
 
403
    def run(self, location=None, remember=False, overwrite=False, revision=None, verbose=False):
 
404
        # FIXME: too much stuff is in the command class        
 
405
        tree_to = WorkingTree.open_containing(u'.')[0]
 
406
        stored_loc = tree_to.branch.get_parent()
573
407
        if location is None:
574
408
            if stored_loc is None:
575
 
                raise errors.BzrCommandError("No pull location known or"
576
 
                                             " specified.")
 
409
                raise BzrCommandError("No pull location known or specified.")
577
410
            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)
 
411
                print "Using saved location: %s" % stored_loc
581
412
                location = stored_loc
582
413
 
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
 
414
        br_from = Branch.open(location)
 
415
        br_to = tree_to.branch
 
416
 
593
417
        if revision is None:
594
 
            if reader is not None:
595
 
                rev_id = reader.target
 
418
            rev_id = None
596
419
        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)
 
420
            rev_id = revision[0].in_history(br_from).rev_id
 
421
        else:
 
422
            raise BzrCommandError('bzr pull --revision takes one value.')
 
423
 
 
424
        old_rh = br_to.revision_history()
 
425
        count = tree_to.pull(br_from, overwrite, rev_id)
 
426
 
 
427
        if br_to.get_parent() is None or remember:
 
428
            br_to.set_parent(location)
614
429
        note('%d revision(s) pulled.' % (count,))
615
430
 
616
431
        if verbose:
617
 
            new_rh = branch_to.revision_history()
 
432
            new_rh = tree_to.branch.revision_history()
618
433
            if old_rh != new_rh:
619
434
                # Something changed
620
435
                from bzrlib.log import show_changed_revisions
621
 
                show_changed_revisions(branch_to, old_rh, new_rh,
622
 
                                       to_file=self.outf)
 
436
                show_changed_revisions(tree_to.branch, old_rh, new_rh)
623
437
 
624
438
 
625
439
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.
 
440
    """Push this branch into another branch.
 
441
    
 
442
    The remote branch will not have its working tree populated because this
 
443
    is both expensive, and may not be supported on the remote file system.
 
444
    
 
445
    Some smart servers or protocols *may* put the working tree in place.
 
446
 
 
447
    If there is no default push location set, the first push will set it.
 
448
    After that, you can omit the location to use the default.  To change the
 
449
    default, use --remember.
633
450
 
634
451
    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.
 
452
    considered diverged if the branch being pushed to is not an older version
 
453
    of this branch.
637
454
 
638
455
    If branches have diverged, you can use 'bzr push --overwrite' to replace
639
 
    the other branch completely, discarding its unmerged changes.
 
456
    the other branch completely.
640
457
    
641
458
    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.
 
459
    do a merge (see bzr help merge) from the other branch, and commit that
 
460
    before doing a 'push --overwrite'.
649
461
    """
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
 
        ]
 
462
    takes_options = ['remember', 'overwrite', 
 
463
                     Option('create-prefix', 
 
464
                            help='Create the path leading up to the branch '
 
465
                                 'if it does not already exist')]
667
466
    takes_args = ['location?']
668
 
    encoding_type = 'replace'
669
467
 
670
468
    def run(self, location=None, remember=False, overwrite=False,
671
 
            create_prefix=False, verbose=False,
672
 
            use_existing_dir=False,
673
 
            directory=None):
 
469
            create_prefix=False, verbose=False):
674
470
        # FIXME: Way too big!  Put this into a function called from the
675
471
        # command.
676
 
        if directory is None:
677
 
            directory = '.'
678
 
        br_from = Branch.open_containing(directory)[0]
679
 
        stored_loc = br_from.get_push_location()
 
472
        from bzrlib.transport import get_transport
 
473
        
 
474
        tree_from = WorkingTree.open_containing(u'.')[0]
 
475
        br_from = tree_from.branch
 
476
        stored_loc = tree_from.branch.get_push_location()
680
477
        if location is None:
681
478
            if stored_loc is None:
682
 
                raise errors.BzrCommandError("No push location known or specified.")
 
479
                raise BzrCommandError("No push location known or specified.")
683
480
            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)
 
481
                print "Using saved location: %s" % stored_loc
687
482
                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
483
        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?
 
484
            br_to = Branch.open(location)
 
485
        except NotBranchError:
 
486
            # create a branch.
 
487
            transport = get_transport(location).clone('..')
 
488
            if not create_prefix:
707
489
                try:
708
 
                    repository_to = dir_to.find_repository()
709
 
                except errors.NoRepositoryPresent:
710
 
                    pass
 
490
                    transport.mkdir(transport.relpath(location))
 
491
                except NoSuchFile:
 
492
                    raise BzrCommandError("Parent directory of %s "
 
493
                                          "does not exist." % location)
711
494
            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
 
495
                current = transport.base
 
496
                needed = [(transport, transport.relpath(location))]
753
497
                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()
 
498
                    try:
 
499
                        transport, relpath = needed[-1]
 
500
                        transport.mkdir(relpath)
 
501
                        needed.pop()
 
502
                    except NoSuchFile:
 
503
                        new_transport = transport.clone('..')
 
504
                        needed.append((new_transport,
 
505
                                       new_transport.relpath(transport.base)))
 
506
                        if new_transport.base == transport.base:
 
507
                            raise BzrCommandError("Could not creeate "
 
508
                                                  "path prefix.")
 
509
            br_to = bzrlib.bzrdir.BzrDir.create_branch_convenience(location)
 
510
        old_rh = br_to.revision_history()
 
511
        try:
791
512
            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".')
 
513
                tree_to = br_to.working_tree()
 
514
            except NoWorkingTree:
 
515
                # TODO: This should be updated for branches which don't have a
 
516
                # working tree, as opposed to ones where we just couldn't 
 
517
                # update the tree.
 
518
                warning('Unable to update the working tree of: %s' % (br_to.base,))
 
519
                count = br_to.pull(br_from, overwrite)
 
520
            else:
 
521
                count = tree_to.pull(br_from, overwrite)
 
522
        except DivergedBranches:
 
523
            raise BzrCommandError("These branches have diverged."
 
524
                                  "  Try a merge then push with overwrite.")
 
525
        if br_from.get_push_location() is None or remember:
 
526
            br_from.set_push_location(location)
810
527
        note('%d revision(s) pushed.' % (count,))
811
528
 
812
529
        if verbose:
814
531
            if old_rh != new_rh:
815
532
                # Something changed
816
533
                from bzrlib.log import show_changed_revisions
817
 
                show_changed_revisions(br_to, old_rh, new_rh,
818
 
                                       to_file=self.outf)
 
534
                show_changed_revisions(br_to, old_rh, new_rh)
819
535
 
820
536
 
821
537
class cmd_branch(Command):
839
555
        if revision is None:
840
556
            revision = [None]
841
557
        elif len(revision) > 1:
842
 
            raise errors.BzrCommandError(
 
558
            raise BzrCommandError(
843
559
                'bzr branch --revision takes exactly 1 revision value')
844
 
 
845
 
        br_from = Branch.open(from_location)
 
560
        try:
 
561
            br_from = Branch.open(from_location)
 
562
        except OSError, e:
 
563
            if e.errno == errno.ENOENT:
 
564
                raise BzrCommandError('Source location "%s" does not'
 
565
                                      ' exist.' % to_location)
 
566
            else:
 
567
                raise
846
568
        br_from.lock_read()
847
569
        try:
848
570
            if basis is not None:
861
583
                name = None
862
584
            else:
863
585
                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)
 
586
            try:
 
587
                os.mkdir(to_location)
 
588
            except OSError, e:
 
589
                if e.errno == errno.EEXIST:
 
590
                    raise BzrCommandError('Target directory "%s" already'
 
591
                                          ' exists.' % to_location)
 
592
                if e.errno == errno.ENOENT:
 
593
                    raise BzrCommandError('Parent of "%s" does not exist.' %
 
594
                                          to_location)
 
595
                else:
 
596
                    raise
 
597
            try:
 
598
                dir = br_from.bzrdir.sprout(to_location, revision_id, basis_dir)
878
599
                branch = dir.open_branch()
879
 
            except errors.NoSuchRevision:
880
 
                to_transport.delete_tree('.')
 
600
            except bzrlib.errors.NoSuchRevision:
 
601
                rmtree(to_location)
881
602
                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)
 
603
                raise BzrCommandError(msg)
 
604
            except bzrlib.errors.UnlistableBranch:
 
605
                rmtree(to_location)
 
606
                msg = "The branch %s cannot be used as a --basis"
 
607
                raise BzrCommandError(msg)
887
608
            if name:
888
609
                branch.control_files.put_utf8('branch-name', name)
 
610
 
889
611
            note('Branched %d revision(s).' % branch.revno())
890
612
        finally:
891
613
            br_from.unlock()
894
616
class cmd_checkout(Command):
895
617
    """Create a new checkout of an existing branch.
896
618
 
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
619
    If the TO_LOCATION is omitted, the last component of the BRANCH_LOCATION will
903
620
    be used.  In other words, "checkout ../foo/bar" will attempt to create ./bar.
904
621
 
909
626
 
910
627
    --basis is to speed up checking out from remote branches.  When specified, it
911
628
    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.
 
629
    branch being checked out. [Not implemented yet.]
915
630
    """
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']
 
631
    takes_args = ['branch_location', 'to_location?']
 
632
    takes_options = ['revision'] # , 'basis']
927
633
 
928
 
    def run(self, branch_location=None, to_location=None, revision=None, basis=None,
929
 
            lightweight=False):
 
634
    def run(self, branch_location, to_location=None, revision=None, basis=None):
930
635
        if revision is None:
931
636
            revision = [None]
932
637
        elif len(revision) > 1:
933
 
            raise errors.BzrCommandError(
 
638
            raise BzrCommandError(
934
639
                '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
640
        source = Branch.open(branch_location)
939
641
        if len(revision) == 1 and revision[0] is not None:
940
642
            revision_id = revision[0].in_history(source)[1]
942
644
            revision_id = None
943
645
        if to_location is None:
944
646
            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
647
        try:
956
648
            os.mkdir(to_location)
957
649
        except OSError, e:
958
650
            if e.errno == errno.EEXIST:
959
 
                raise errors.BzrCommandError('Target directory "%s" already'
960
 
                                             ' exists.' % to_location)
 
651
                raise BzrCommandError('Target directory "%s" already'
 
652
                                      ' exists.' % to_location)
961
653
            if e.errno == errno.ENOENT:
962
 
                raise errors.BzrCommandError('Parent of "%s" does not exist.'
963
 
                                             % to_location)
 
654
                raise BzrCommandError('Parent of "%s" does not exist.' %
 
655
                                      to_location)
964
656
            else:
965
657
                raise
966
 
        source.create_checkout(to_location, revision_id, lightweight)
 
658
        checkout = bzrdir.BzrDirMetaFormat1().initialize(to_location)
 
659
        bzrlib.branch.BranchReferenceFormat().initialize(checkout, source)
 
660
        checkout.create_workingtree(revision_id)
967
661
 
968
662
 
969
663
class cmd_renames(Command):
979
673
        tree = WorkingTree.open_containing(dir)[0]
980
674
        old_inv = tree.basis_tree().inventory
981
675
        new_inv = tree.read_working_inventory()
982
 
        renames = list(_mod_tree.find_renames(old_inv, new_inv))
 
676
 
 
677
        renames = list(bzrlib.tree.find_renames(old_inv, new_inv))
983
678
        renames.sort()
984
679
        for old_name, new_name in renames:
985
 
            self.outf.write("%s => %s\n" % (old_name, new_name))
 
680
            print "%s => %s" % (old_name, new_name)        
986
681
 
987
682
 
988
683
class cmd_update(Command):
989
684
    """Update a tree to have the latest code committed to its branch.
990
685
    
991
686
    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.
 
687
    conflicts. If you have any uncommitted changes, you will still 
 
688
    need to commit them after the update.
997
689
    """
998
690
    takes_args = ['dir?']
999
 
    aliases = ['up']
1000
691
 
1001
692
    def run(self, dir='.'):
1002
693
        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()
 
694
        tree.lock_write()
1008
695
        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
 
696
            if tree.last_revision() == tree.branch.last_revision():
 
697
                note("Tree is up to date.")
 
698
                return
1018
699
            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'.")
 
700
            note('Updated to revision %d.' %
 
701
                 (tree.branch.revision_id_to_revno(tree.last_revision()),))
1024
702
            if conflicts != 0:
1025
703
                return 1
1026
704
            else:
1030
708
 
1031
709
 
1032
710
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
 
 
 
711
    """Show statistical information about a branch."""
 
712
    takes_args = ['branch?']
 
713
    
1044
714
    @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)
 
715
    def run(self, branch=None):
 
716
        import bzrlib.info
 
717
        bzrlib.info.show_bzrdir_info(bzrdir.BzrDir.open_containing(branch)[0])
1049
718
 
1050
719
 
1051
720
class cmd_remove(Command):
1053
722
 
1054
723
    This makes bzr stop tracking changes to a versioned file.  It does
1055
724
    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
725
    """
1062
 
    takes_args = ['file*']
1063
 
    takes_options = ['verbose', Option('new', help='remove newly-added files')]
 
726
    takes_args = ['file+']
 
727
    takes_options = ['verbose']
1064
728
    aliases = ['rm']
1065
 
    encoding_type = 'replace'
1066
729
    
1067
 
    def run(self, file_list, verbose=False, new=False):
 
730
    def run(self, file_list, verbose=False):
1068
731
        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)
 
732
        tree.remove(file_list, verbose=verbose)
1080
733
 
1081
734
 
1082
735
class cmd_file_id(Command):
1086
739
    same through all revisions where the file exists, even when it is
1087
740
    moved or renamed.
1088
741
    """
1089
 
 
1090
742
    hidden = True
1091
743
    takes_args = ['filename']
1092
 
 
1093
744
    @display_command
1094
745
    def run(self, filename):
1095
746
        tree, relpath = WorkingTree.open_containing(filename)
1096
 
        i = tree.path2id(relpath)
1097
 
        if i is None:
1098
 
            raise errors.NotVersionedError(filename)
 
747
        i = tree.inventory.path2id(relpath)
 
748
        if i == None:
 
749
            raise BzrError("%r is not a versioned file" % filename)
1099
750
        else:
1100
 
            self.outf.write(i + '\n')
 
751
            print i
1101
752
 
1102
753
 
1103
754
class cmd_file_path(Command):
1104
755
    """Print path of file_ids to a file or directory.
1105
756
 
1106
757
    This prints one line for each directory down to the target,
1107
 
    starting at the branch root.
1108
 
    """
1109
 
 
 
758
    starting at the branch root."""
1110
759
    hidden = True
1111
760
    takes_args = ['filename']
1112
 
 
1113
761
    @display_command
1114
762
    def run(self, filename):
1115
763
        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)
 
764
        inv = tree.inventory
 
765
        fid = inv.path2id(relpath)
 
766
        if fid == None:
 
767
            raise BzrError("%r is not a versioned file" % filename)
 
768
        for fip in inv.get_idpath(fid):
 
769
            print fip
1149
770
 
1150
771
 
1151
772
class cmd_revision_history(Command):
1152
 
    """Display the list of revision ids on a branch."""
1153
 
    takes_args = ['location?']
1154
 
 
 
773
    """Display list of revision ids on this branch."""
1155
774
    hidden = True
1156
 
 
1157
775
    @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')
 
776
    def run(self):
 
777
        branch = WorkingTree.open_containing(u'.')[0].branch
 
778
        for patchid in branch.revision_history():
 
779
            print patchid
1163
780
 
1164
781
 
1165
782
class cmd_ancestry(Command):
1166
783
    """List all revisions merged into this branch."""
1167
 
    takes_args = ['location?']
1168
 
 
1169
784
    hidden = True
1170
 
 
1171
785
    @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')
 
786
    def run(self):
 
787
        tree = WorkingTree.open_containing(u'.')[0]
 
788
        b = tree.branch
 
789
        # FIXME. should be tree.last_revision
 
790
        for revision_id in b.repository.get_ancestry(b.last_revision()):
 
791
            print revision_id
1187
792
 
1188
793
 
1189
794
class cmd_init(Command):
1192
797
    Use this to create an empty branch, or before importing an
1193
798
    existing project.
1194
799
 
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
800
    Recipe for importing a tree of files:
1204
801
        cd ~/project
1205
802
        bzr init
1208
805
        bzr commit -m 'imported project'
1209
806
    """
1210
807
    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')
 
808
    def run(self, location=None):
 
809
        from bzrlib.branch import Branch
1227
810
        if location is None:
1228
811
            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
812
        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)
 
813
            # The path has to exist to initialize a
 
814
            # branch inside of it.
 
815
            # Just using os.mkdir, since I don't
 
816
            # believe that we want to create a bunch of
 
817
            # locations if the user supplies an extended path
 
818
            if not os.path.exists(location):
 
819
                os.mkdir(location)
 
820
        bzrdir.BzrDir.create_standalone_workingtree(location)
1308
821
 
1309
822
 
1310
823
class cmd_diff(Command):
1311
 
    """Show differences in the working tree or between revisions.
 
824
    """Show differences in working tree.
1312
825
    
1313
826
    If files are listed, only the changes in those files are listed.
1314
827
    Otherwise, all changes for the tree are listed.
1315
828
 
1316
 
    "bzr diff -p1" is equivalent to "bzr diff --prefix old/:new/", and
1317
 
    produces patches suitable for "patch -p1".
1318
 
 
1319
829
    examples:
1320
830
        bzr diff
1321
 
            Shows the difference in the working tree versus the last commit
1322
831
        bzr diff -r1
1323
 
            Difference between the working tree and revision 1
1324
832
        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
833
    """
 
834
    # TODO: Allow diff across branches.
1333
835
    # TODO: Option to use external diff command; could be GNU diff, wdiff,
1334
836
    #       or a graphical diff.
1335
837
 
1336
838
    # TODO: Python difflib is not exactly the same as unidiff; should
1337
839
    #       either fix it up or prefer to use an external diff.
1338
840
 
 
841
    # TODO: If a directory is given, diff everything under that.
 
842
 
1339
843
    # TODO: Selected-file diff is inefficient and doesn't show you
1340
844
    #       deleted files.
1341
845
 
1342
846
    # TODO: This probably handles non-Unix newlines poorly.
1343
 
 
 
847
    
1344
848
    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
 
        ]
 
849
    takes_options = ['revision', 'diff-options']
1351
850
    aliases = ['di', 'dif']
1352
 
    encoding_type = 'exact'
1353
851
 
1354
852
    @display_command
1355
 
    def run(self, revision=None, file_list=None, diff_options=None,
1356
 
            prefix=None):
 
853
    def run(self, revision=None, file_list=None, diff_options=None):
1357
854
        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')
1375
 
        
1376
855
        try:
1377
856
            tree1, file_list = internal_tree_files(file_list)
1378
857
            tree2 = None
1379
858
            b = None
1380
859
            b2 = None
1381
 
        except errors.FileInWrongBranch:
 
860
        except FileInWrongBranch:
1382
861
            if len(file_list) != 2:
1383
 
                raise errors.BzrCommandError("Files are in different branches")
 
862
                raise BzrCommandError("Files are in different branches")
1384
863
 
1385
864
            tree1, file1 = WorkingTree.open_containing(file_list[0])
1386
865
            tree2, file2 = WorkingTree.open_containing(file_list[1])
1387
866
            if file1 != "" or file2 != "":
1388
867
                # FIXME diff those two files. rbc 20051123
1389
 
                raise errors.BzrCommandError("Files are in different branches")
 
868
                raise BzrCommandError("Files are in different branches")
1390
869
            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)
 
870
        if revision is not None:
 
871
            if tree2 is not None:
 
872
                raise BzrCommandError("Can't specify -r with two branches")
 
873
            if (len(revision) == 1) or (revision[1].spec is None):
 
874
                return diff_cmd_helper(tree1, file_list, diff_options,
 
875
                                       revision[0])
 
876
            elif len(revision) == 2:
 
877
                return diff_cmd_helper(tree1, file_list, diff_options,
 
878
                                       revision[0], revision[1])
 
879
            else:
 
880
                raise BzrCommandError('bzr diff --revision takes exactly one or two revision identifiers')
 
881
        else:
 
882
            if tree2 is not None:
 
883
                return show_diff_trees(tree1, tree2, sys.stdout, 
 
884
                                       specific_files=file_list,
 
885
                                       external_diff_options=diff_options)
 
886
            else:
 
887
                return diff_cmd_helper(tree1, file_list, diff_options)
1417
888
 
1418
889
 
1419
890
class cmd_deleted(Command):
1425
896
    # directories with readdir, rather than stating each one.  Same
1426
897
    # level of effort but possibly much less IO.  (Or possibly not,
1427
898
    # if the directories are very large...)
1428
 
    takes_options = ['show-ids']
1429
 
 
1430
899
    @display_command
1431
900
    def run(self, show_ids=False):
1432
901
        tree = WorkingTree.open_containing(u'.')[0]
1433
902
        old = tree.basis_tree()
1434
903
        for path, ie in old.inventory.iter_entries():
1435
904
            if not tree.has_id(ie.file_id):
1436
 
                self.outf.write(path)
1437
905
                if show_ids:
1438
 
                    self.outf.write(' ')
1439
 
                    self.outf.write(ie.file_id)
1440
 
                self.outf.write('\n')
 
906
                    print '%-50s %s' % (path, ie.file_id)
 
907
                else:
 
908
                    print path
1441
909
 
1442
910
 
1443
911
class cmd_modified(Command):
1444
 
    """List files modified in working tree.
1445
 
 
1446
 
    See also: "bzr status".
1447
 
    """
1448
 
 
 
912
    """List files modified in working tree."""
1449
913
    hidden = True
1450
 
 
1451
914
    @display_command
1452
915
    def run(self):
 
916
        from bzrlib.delta import compare_trees
 
917
 
1453
918
        tree = WorkingTree.open_containing(u'.')[0]
1454
 
        td = tree.changes_from(tree.basis_tree())
 
919
        td = compare_trees(tree.basis_tree(), tree)
 
920
 
1455
921
        for path, id, kind, text_modified, meta_modified in td.modified:
1456
 
            self.outf.write(path + '\n')
 
922
            print path
 
923
 
1457
924
 
1458
925
 
1459
926
class cmd_added(Command):
1460
 
    """List files added in working tree.
1461
 
 
1462
 
    See also: "bzr status".
1463
 
    """
1464
 
 
 
927
    """List files added in working tree."""
1465
928
    hidden = True
1466
 
 
1467
929
    @display_command
1468
930
    def run(self):
1469
931
        wt = WorkingTree.open_containing(u'.')[0]
1472
934
        for file_id in inv:
1473
935
            if file_id in basis_inv:
1474
936
                continue
1475
 
            if inv.is_root(file_id) and len(basis_inv) == 0:
1476
 
                continue
1477
937
            path = inv.id2path(file_id)
1478
 
            if not os.access(osutils.abspath(path), os.F_OK):
 
938
            if not os.access(bzrlib.osutils.abspath(path), os.F_OK):
1479
939
                continue
1480
 
            self.outf.write(path + '\n')
1481
 
 
 
940
            print path
 
941
                
 
942
        
1482
943
 
1483
944
class cmd_root(Command):
1484
945
    """Show the tree root directory.
1490
951
    def run(self, filename=None):
1491
952
        """Print the branch root."""
1492
953
        tree = WorkingTree.open_containing(filename)[0]
1493
 
        self.outf.write(tree.basedir + '\n')
 
954
        print tree.basedir
1494
955
 
1495
956
 
1496
957
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.
 
958
    """Show log of this branch.
1500
959
 
1501
960
    To request a range of logs, you can use the command -r begin..end
1502
961
    -r revision requests a specific revision, -r ..end or -r begin.. are
1503
962
    also valid.
1504
 
 
1505
 
    examples:
1506
 
        bzr log
1507
 
        bzr log foo.c
1508
 
        bzr log -r -10.. http://server/branch
1509
963
    """
1510
964
 
1511
965
    # TODO: Make --revision support uuid: and hash: [future tag:] notation.
1512
966
 
1513
 
    takes_args = ['location?']
 
967
    takes_args = ['filename?']
1514
968
    takes_options = [Option('forward', 
1515
969
                            help='show from oldest to newest'),
1516
 
                     'timezone', 
1517
 
                     Option('verbose', 
1518
 
                             short_name='v',
1519
 
                             help='show files changed in each revision'),
 
970
                     'timezone', 'verbose', 
1520
971
                     'show-ids', 'revision',
1521
972
                     'log-format',
 
973
                     'line', 'long', 
1522
974
                     Option('message',
1523
 
                            short_name='m',
1524
975
                            help='show revisions whose message matches this regexp',
1525
976
                            type=str),
 
977
                     'short',
1526
978
                     ]
1527
 
    encoding_type = 'replace'
1528
 
 
1529
979
    @display_command
1530
 
    def run(self, location=None, timezone='original',
 
980
    def run(self, filename=None, timezone='original',
1531
981
            verbose=False,
1532
982
            show_ids=False,
1533
983
            forward=False,
1534
984
            revision=None,
1535
985
            log_format=None,
1536
 
            message=None):
1537
 
        from bzrlib.log import show_log
 
986
            message=None,
 
987
            long=False,
 
988
            short=False,
 
989
            line=False):
 
990
        from bzrlib.log import log_formatter, show_log
 
991
        import codecs
1538
992
        assert message is None or isinstance(message, basestring), \
1539
993
            "invalid message argument %r" % message
1540
994
        direction = (forward and 'forward') or 'reverse'
1541
995
        
1542
996
        # log everything
1543
997
        file_id = None
1544
 
        if location:
 
998
        if filename:
1545
999
            # find the file id to log:
1546
1000
 
1547
 
            tree, b, fp = bzrdir.BzrDir.open_containing_tree_or_branch(
1548
 
                location)
 
1001
            dir, fp = bzrdir.BzrDir.open_containing(filename)
 
1002
            b = dir.open_branch()
1549
1003
            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)
 
1004
                try:
 
1005
                    # might be a tree:
 
1006
                    inv = dir.open_workingtree().inventory
 
1007
                except (errors.NotBranchError, errors.NotLocalUrl):
 
1008
                    # either no tree, or is remote.
 
1009
                    inv = b.basis_tree().inventory
 
1010
                file_id = inv.path2id(fp)
1557
1011
        else:
1558
1012
            # local dir only
1559
1013
            # 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)
 
1014
            dir, relpath = bzrdir.BzrDir.open_containing('.')
1566
1015
            b = dir.open_branch()
1567
1016
 
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()
 
1017
        if revision is None:
 
1018
            rev1 = None
 
1019
            rev2 = None
 
1020
        elif len(revision) == 1:
 
1021
            rev1 = rev2 = revision[0].in_history(b).revno
 
1022
        elif len(revision) == 2:
 
1023
            if revision[0].spec is None:
 
1024
                # missing begin-range means first revision
 
1025
                rev1 = 1
 
1026
            else:
 
1027
                rev1 = revision[0].in_history(b).revno
 
1028
 
 
1029
            if revision[1].spec is None:
 
1030
                # missing end-range means last known revision
 
1031
                rev2 = b.revno()
 
1032
            else:
 
1033
                rev2 = revision[1].in_history(b).revno
 
1034
        else:
 
1035
            raise BzrCommandError('bzr log --revision takes one or two values.')
 
1036
 
 
1037
        # By this point, the revision numbers are converted to the +ve
 
1038
        # form if they were supplied in the -ve form, so we can do
 
1039
        # this comparison in relative safety
 
1040
        if rev1 > rev2:
 
1041
            (rev2, rev1) = (rev1, rev2)
 
1042
 
 
1043
        mutter('encoding log as %r', bzrlib.user_encoding)
 
1044
 
 
1045
        # use 'replace' so that we don't abort if trying to write out
 
1046
        # in e.g. the default C locale.
 
1047
        outf = codecs.getwriter(bzrlib.user_encoding)(sys.stdout, errors='replace')
 
1048
 
 
1049
        if (log_format == None):
 
1050
            default = bzrlib.config.BranchConfig(b).log_format()
 
1051
            log_format = get_log_format(long=long, short=short, line=line, default=default)
 
1052
 
 
1053
        lf = log_formatter(log_format,
 
1054
                           show_ids=show_ids,
 
1055
                           to_file=outf,
 
1056
                           show_timezone=timezone)
 
1057
 
 
1058
        show_log(b,
 
1059
                 lf,
 
1060
                 file_id,
 
1061
                 verbose=verbose,
 
1062
                 direction=direction,
 
1063
                 start_revision=rev1,
 
1064
                 end_revision=rev2,
 
1065
                 search=message)
1620
1066
 
1621
1067
 
1622
1068
def get_log_format(long=False, short=False, line=False, default='long'):
1633
1079
class cmd_touching_revisions(Command):
1634
1080
    """Return revision-ids which affected a particular file.
1635
1081
 
1636
 
    A more user-friendly interface is "bzr log FILE".
1637
 
    """
1638
 
 
 
1082
    A more user-friendly interface is "bzr log FILE"."""
1639
1083
    hidden = True
1640
1084
    takes_args = ["filename"]
1641
 
 
1642
1085
    @display_command
1643
1086
    def run(self, filename):
1644
1087
        tree, relpath = WorkingTree.open_containing(filename)
1645
1088
        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))
 
1089
        inv = tree.read_working_inventory()
 
1090
        file_id = inv.path2id(relpath)
 
1091
        for revno, revision_id, what in bzrlib.log.find_touching_revisions(b, file_id):
 
1092
            print "%6d %s" % (revno, what)
1649
1093
 
1650
1094
 
1651
1095
class cmd_ls(Command):
1652
1096
    """List files in a tree.
1653
1097
    """
1654
 
 
1655
 
    takes_args = ['path?']
1656
1098
    # TODO: Take a revision or remote path and list that tree instead.
 
1099
    hidden = True
1657
1100
    takes_options = ['verbose', 'revision',
1658
1101
                     Option('non-recursive',
1659
1102
                            help='don\'t recurse into sub-directories'),
1664
1107
                     Option('ignored', help='Print ignored files'),
1665
1108
 
1666
1109
                     Option('null', help='Null separate the files'),
1667
 
                     'kind', 'show-ids'
1668
1110
                    ]
1669
1111
    @display_command
1670
1112
    def run(self, revision=None, verbose=False, 
1671
1113
            non_recursive=False, from_root=False,
1672
1114
            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')
 
1115
            null=False):
1677
1116
 
1678
1117
        if verbose and null:
1679
 
            raise errors.BzrCommandError('Cannot set both --verbose and --null')
 
1118
            raise BzrCommandError('Cannot set both --verbose and --null')
1680
1119
        all = not (unknown or versioned or ignored)
1681
1120
 
1682
1121
        selection = {'I':ignored, '?':unknown, 'V':versioned}
1683
1122
 
1684
 
        if path is None:
1685
 
            fs_path = '.'
1686
 
            prefix = ''
1687
 
        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)
 
1123
        tree, relpath = WorkingTree.open_containing(u'.')
1695
1124
        if from_root:
1696
1125
            relpath = u''
1697
1126
        elif relpath:
1698
1127
            relpath += '/'
1699
1128
        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()
1704
 
 
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()
 
1129
            tree = tree.branch.repository.revision_tree(
 
1130
                revision[0].in_history(tree.branch).rev_id)
 
1131
        for fp, fc, kind, fid, entry in tree.list_files():
 
1132
            if fp.startswith(relpath):
 
1133
                fp = fp[len(relpath):]
 
1134
                if non_recursive and '/' in fp:
 
1135
                    continue
 
1136
                if not all and not selection[fc]:
 
1137
                    continue
 
1138
                if verbose:
 
1139
                    kindch = entry.kind_character()
 
1140
                    print '%-8s %s%s' % (fc, fp, kindch)
 
1141
                elif null:
 
1142
                    sys.stdout.write(fp)
 
1143
                    sys.stdout.write('\0')
 
1144
                    sys.stdout.flush()
 
1145
                else:
 
1146
                    print fp
1740
1147
 
1741
1148
 
1742
1149
class cmd_unknowns(Command):
1743
 
    """List unknown files.
1744
 
 
1745
 
    See also: "bzr ls --unknown".
1746
 
    """
1747
 
 
1748
 
    hidden = True
1749
 
 
 
1150
    """List unknown files."""
1750
1151
    @display_command
1751
1152
    def run(self):
 
1153
        from bzrlib.osutils import quotefn
1752
1154
        for f in WorkingTree.open_containing(u'.')[0].unknowns():
1753
 
            self.outf.write(osutils.quotefn(f) + '\n')
 
1155
            print quotefn(f)
1754
1156
 
1755
1157
 
1756
1158
class cmd_ignore(Command):
1757
 
    """Ignore specified files or patterns.
 
1159
    """Ignore a command or pattern.
1758
1160
 
1759
1161
    To remove patterns from the ignore list, edit the .bzrignore file.
1760
1162
 
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.
 
1163
    If the pattern contains a slash, it is compared to the whole path
 
1164
    from the branch root.  Otherwise, it is compared to only the last
 
1165
    component of the path.  To match a file only in the root directory,
 
1166
    prepend './'.
 
1167
 
 
1168
    Ignore patterns are case-insensitive on case-insensitive systems.
 
1169
 
 
1170
    Note: wildcards must be quoted from the shell on Unix.
1782
1171
 
1783
1172
    examples:
1784
1173
        bzr ignore ./Makefile
1785
1174
        bzr ignore '*.class'
1786
 
        bzr ignore 'lib/**/*.o'
1787
 
        bzr ignore 'RE:lib/.*\.o'
1788
1175
    """
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
 
                     ]
 
1176
    # TODO: Complain if the filename is absolute
 
1177
    takes_args = ['name_pattern']
1794
1178
    
1795
 
    def run(self, name_pattern_list=None, old_default_rules=None):
 
1179
    def run(self, name_pattern):
1796
1180
        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")
 
1181
        import os.path
 
1182
 
1809
1183
        tree, relpath = WorkingTree.open_containing(u'.')
1810
1184
        ifn = tree.abspath('.bzrignore')
 
1185
 
1811
1186
        if os.path.exists(ifn):
1812
1187
            f = open(ifn, 'rt')
1813
1188
            try:
1822
1197
 
1823
1198
        if igns and igns[-1] != '\n':
1824
1199
            igns += '\n'
1825
 
        for name_pattern in name_pattern_list:
1826
 
            igns += name_pattern.rstrip('/') + '\n'
 
1200
        igns += name_pattern + '\n'
1827
1201
 
1828
 
        f = AtomicFile(ifn, 'wb')
1829
1202
        try:
 
1203
            f = AtomicFile(ifn, 'wt')
1830
1204
            f.write(igns.encode('utf-8'))
1831
1205
            f.commit()
1832
1206
        finally:
1833
1207
            f.close()
1834
1208
 
1835
 
        if not tree.path2id('.bzrignore'):
 
1209
        inv = tree.inventory
 
1210
        if inv.path2id('.bzrignore'):
 
1211
            mutter('.bzrignore is already versioned')
 
1212
        else:
 
1213
            mutter('need to make new .bzrignore file versioned')
1836
1214
            tree.add(['.bzrignore'])
1837
1215
 
1838
1216
 
1843
1221
    @display_command
1844
1222
    def run(self):
1845
1223
        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()
 
1224
        for path, file_class, kind, file_id, entry in tree.list_files():
 
1225
            if file_class != 'I':
 
1226
                continue
 
1227
            ## XXX: Slightly inefficient since this was already calculated
 
1228
            pat = tree.is_ignored(path)
 
1229
            print '%-50s %s' % (path, pat)
1856
1230
 
1857
1231
 
1858
1232
class cmd_lookup_revision(Command):
1869
1243
        try:
1870
1244
            revno = int(revno)
1871
1245
        except ValueError:
1872
 
            raise errors.BzrCommandError("not a valid revision-number: %r" % revno)
 
1246
            raise BzrCommandError("not a valid revision-number: %r" % revno)
1873
1247
 
1874
1248
        print WorkingTree.open_containing(u'.')[0].branch.get_rev_id(revno)
1875
1249
 
1886
1260
    Root may be the top directory for tar, tgz and tbz2 formats. If none
1887
1261
    is given, the top directory will be the root name of the file.
1888
1262
 
1889
 
    If branch is omitted then the branch containing the CWD will be used.
1890
 
 
1891
1263
    Note: export of tree with non-ascii filenames to zip is not supported.
1892
1264
 
1893
1265
     Supported formats       Autodetected by extension
1898
1270
         tgz                      .tar.gz, .tgz
1899
1271
         zip                          .zip
1900
1272
    """
1901
 
    takes_args = ['dest', 'branch?']
 
1273
    takes_args = ['dest']
1902
1274
    takes_options = ['revision', 'format', 'root']
1903
 
    def run(self, dest, branch=None, revision=None, format=None, root=None):
 
1275
    def run(self, dest, revision=None, format=None, root=None):
 
1276
        import os.path
1904
1277
        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
 
            
 
1278
        tree = WorkingTree.open_containing(u'.')[0]
 
1279
        b = tree.branch
1912
1280
        if revision is None:
1913
1281
            # should be tree.last_revision  FIXME
1914
1282
            rev_id = b.last_revision()
1915
1283
        else:
1916
1284
            if len(revision) != 1:
1917
 
                raise errors.BzrCommandError('bzr export --revision takes exactly 1 argument')
 
1285
                raise BzrError('bzr export --revision takes exactly 1 argument')
1918
1286
            rev_id = revision[0].in_history(b).rev_id
1919
1287
        t = b.repository.revision_tree(rev_id)
1920
1288
        try:
1921
1289
            export(t, dest, format, root)
1922
1290
        except errors.NoSuchExportFormat, e:
1923
 
            raise errors.BzrCommandError('Unsupported export format: %s' % e.format)
 
1291
            raise BzrCommandError('Unsupported export format: %s' % e.format)
1924
1292
 
1925
1293
 
1926
1294
class cmd_cat(Command):
1927
1295
    """Write a file's text from a previous revision."""
1928
1296
 
1929
 
    takes_options = ['revision', 'name-from-revision']
 
1297
    takes_options = ['revision']
1930
1298
    takes_args = ['filename']
1931
 
    encoding_type = 'exact'
1932
1299
 
1933
1300
    @display_command
1934
 
    def run(self, filename, revision=None, name_from_revision=False):
 
1301
    def run(self, filename, revision=None):
1935
1302
        if revision is not None and len(revision) != 1:
1936
 
            raise errors.BzrCommandError("bzr cat --revision takes exactly"
1937
 
                                        " one number")
1938
 
 
 
1303
            raise BzrCommandError("bzr cat --revision takes exactly one number")
1939
1304
        tree = None
1940
1305
        try:
1941
1306
            tree, relpath = WorkingTree.open_containing(filename)
1942
1307
            b = tree.branch
1943
 
        except (errors.NotBranchError, errors.NotLocalUrl):
 
1308
        except NotBranchError:
1944
1309
            pass
1945
1310
 
1946
 
        if revision is not None and revision[0].get_branch() is not None:
1947
 
            b = Branch.open(revision[0].get_branch())
1948
1311
        if tree is None:
1949
1312
            b, relpath = Branch.open_containing(filename)
1950
 
            tree = b.basis_tree()
1951
1313
        if revision is None:
1952
1314
            revision_id = b.last_revision()
1953
1315
        else:
1954
1316
            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))
 
1317
        b.print_file(relpath, revision_id)
1973
1318
 
1974
1319
 
1975
1320
class cmd_local_time_offset(Command):
1977
1322
    hidden = True    
1978
1323
    @display_command
1979
1324
    def run(self):
1980
 
        print osutils.local_time_offset()
 
1325
        print bzrlib.osutils.local_time_offset()
1981
1326
 
1982
1327
 
1983
1328
 
2008
1353
                     Option('unchanged',
2009
1354
                            help='commit even if nothing has changed'),
2010
1355
                     Option('file', type=str, 
2011
 
                            short_name='F',
2012
1356
                            argname='msgfile',
2013
1357
                            help='file containing commit message'),
2014
1358
                     Option('strict',
2015
1359
                            help="refuse to commit if there are unknown "
2016
1360
                            "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
1361
                     ]
2024
1362
    aliases = ['ci', 'checkin']
2025
1363
 
2026
1364
    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)
 
1365
            unchanged=False, strict=False):
2029
1366
        from bzrlib.errors import (PointlessCommit, ConflictsInTree,
2030
1367
                StrictCommitFailed)
2031
1368
        from bzrlib.msgeditor import edit_commit_message, \
2032
1369
                make_commit_message_template
 
1370
        from tempfile import TemporaryFile
 
1371
        import codecs
2033
1372
 
2034
1373
        # TODO: Need a blackbox test for invoking the external editor; may be
2035
1374
        # slightly problematic to run this cross-platform.
2036
1375
 
2037
1376
        # TODO: do more checks that the commit will succeed before 
2038
1377
        # spending the user's valuable time typing a commit message.
 
1378
        #
 
1379
        # TODO: if the commit *does* happen to fail, then save the commit 
 
1380
        # message to a temporary file where it can be recovered
2039
1381
        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
 
1382
        if message is None and not file:
 
1383
            template = make_commit_message_template(tree, selected_list)
 
1384
            message = edit_commit_message(template)
 
1385
            if message is None:
 
1386
                raise BzrCommandError("please specify a commit message"
 
1387
                                      " with either --message or --file")
 
1388
        elif message and file:
 
1389
            raise BzrCommandError("please specify either --message or --file")
2067
1390
        
2068
 
        if verbose:
2069
 
            reporter = ReportCommitToLog()
2070
 
        else:
2071
 
            reporter = NullCommitReporter()
 
1391
        if file:
 
1392
            import codecs
 
1393
            message = codecs.open(file, 'rt', bzrlib.user_encoding).read()
2072
1394
 
 
1395
        if message == "":
 
1396
                raise BzrCommandError("empty commit message specified")
 
1397
            
2073
1398
        try:
2074
 
            tree.commit(message_callback=get_message,
2075
 
                        specific_files=selected_list,
2076
 
                        allow_pointless=unchanged, strict=strict, local=local,
2077
 
                        reporter=reporter)
 
1399
            tree.commit(message, specific_files=selected_list,
 
1400
                        allow_pointless=unchanged, strict=strict)
2078
1401
        except PointlessCommit:
2079
1402
            # FIXME: This should really happen before the file is read in;
2080
1403
            # perhaps prepare the commit; get the message; then actually commit
2081
 
            raise errors.BzrCommandError("no changes to commit."
2082
 
                              " use --unchanged to commit anyhow")
 
1404
            raise BzrCommandError("no changes to commit",
 
1405
                                  ["use --unchanged to commit anyhow"])
2083
1406
        except ConflictsInTree:
2084
 
            raise errors.BzrCommandError('Conflicts detected in working '
2085
 
                'tree.  Use "bzr conflicts" to list, "bzr resolve FILE" to'
2086
 
                ' resolve.')
 
1407
            raise BzrCommandError("Conflicts detected in working tree.  "
 
1408
                'Use "bzr conflicts" to list, "bzr resolve FILE" to resolve.')
2087
1409
        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.')
 
1410
            raise BzrCommandError("Commit refused because there are unknown "
 
1411
                                  "files in the working tree.")
 
1412
        note('Committed revision %d.' % (tree.branch.revno(),))
2095
1413
 
2096
1414
 
2097
1415
class cmd_check(Command):
2113
1431
        check(branch, verbose)
2114
1432
 
2115
1433
 
 
1434
class cmd_scan_cache(Command):
 
1435
    hidden = True
 
1436
    def run(self):
 
1437
        from bzrlib.hashcache import HashCache
 
1438
 
 
1439
        c = HashCache(u'.')
 
1440
        c.read()
 
1441
        c.scan()
 
1442
            
 
1443
        print '%6d stats' % c.stat_count
 
1444
        print '%6d in hashcache' % len(c._cache)
 
1445
        print '%6d files removed from cache' % c.removed_count
 
1446
        print '%6d hashes updated' % c.update_count
 
1447
        print '%6d files changed too recently to cache' % c.danger_count
 
1448
 
 
1449
        if c.needs_write:
 
1450
            c.write()
 
1451
 
 
1452
 
 
1453
def get_format_type(typestring):
 
1454
    """Parse and return a format specifier."""
 
1455
    if typestring == "metadir":
 
1456
        return bzrdir.BzrDirMetaFormat1()
 
1457
    if typestring == "knit":
 
1458
        format = bzrdir.BzrDirMetaFormat1()
 
1459
        format.repository_format = bzrlib.repository.RepositoryFormatKnit1()
 
1460
        return format
 
1461
    msg = "No known bzr-dir format %s. Supported types are: metadir\n" %\
 
1462
        (typestring)
 
1463
    raise BzrCommandError(msg)
 
1464
 
 
1465
 
2116
1466
class cmd_upgrade(Command):
2117
1467
    """Upgrade branch storage to current format.
2118
1468
 
2122
1472
    """
2123
1473
    takes_args = ['url?']
2124
1474
    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'),
 
1475
                     Option('format', 
 
1476
                            help='Upgrade to a specific format rather than the'
 
1477
                                 ' current default format. Currently this '
 
1478
                                 ' option only accepts =metadir',
 
1479
                            type=get_format_type),
2131
1480
                    ]
2132
1481
 
2133
1482
 
2134
1483
    def run(self, url='.', format=None):
2135
1484
        from bzrlib.upgrade import upgrade
2136
 
        if format is None:
2137
 
            format = bzrdir.format_registry.make_bzrdir('default')
2138
1485
        upgrade(url, format)
2139
1486
 
2140
1487
 
2141
1488
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'
 
1489
    """Show bzr user id."""
 
1490
    takes_options = ['email']
2156
1491
    
2157
1492
    @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.
 
1493
    def run(self, email=False):
2172
1494
        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)
 
1495
            b = WorkingTree.open_containing(u'.')[0].branch
 
1496
            config = bzrlib.config.BranchConfig(b)
 
1497
        except NotBranchError:
 
1498
            config = bzrlib.config.GlobalConfig()
2177
1499
        
2178
 
        # use global config unless --branch given
2179
 
        if branch:
2180
 
            c = Branch.open_containing('.')[0].get_config()
 
1500
        if email:
 
1501
            print config.user_email()
2181
1502
        else:
2182
 
            c = config.GlobalConfig()
2183
 
        c.set_user_option('email', name)
 
1503
            print config.username()
2184
1504
 
2185
1505
 
2186
1506
class cmd_nick(Command):
2205
1525
class cmd_selftest(Command):
2206
1526
    """Run internal test suite.
2207
1527
    
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.
 
1528
    This creates temporary test directories in the working directory,
 
1529
    but not existing data is affected.  These directories are deleted
 
1530
    if the tests pass, or left behind to help in debugging if they
 
1531
    fail and --keep-output is specified.
2212
1532
    
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.
 
1533
    If arguments are given, they are regular expressions that say
 
1534
    which tests should run.
2220
1535
 
2221
1536
    If the global option '--no-plugins' is given, plugins are not loaded
2222
1537
    before running the selftests.  This has two effects: features provided or
2223
1538
    modified by plugins will not be tested, and tests provided by plugins will
2224
1539
    not be run.
2225
1540
 
2226
 
    examples::
 
1541
    examples:
2227
1542
        bzr selftest ignore
2228
 
            run only tests relating to 'ignore'
2229
1543
        bzr --no-plugins selftest -v
2230
 
            disable plugins and list tests as they're run
2231
1544
    """
2232
1545
    # TODO: --list should give a list of all available tests
2233
1546
 
2241
1554
        if typestring == "memory":
2242
1555
            from bzrlib.transport.memory import MemoryServer
2243
1556
            return MemoryServer
2244
 
        if typestring == "fakenfs":
2245
 
            from bzrlib.transport.fakenfs import FakeNFSServer
2246
 
            return FakeNFSServer
2247
1557
        msg = "No known transport type %s. Supported types are: sftp\n" %\
2248
1558
            (typestring)
2249
 
        raise errors.BzrCommandError(msg)
 
1559
        raise BzrCommandError(msg)
2250
1560
 
2251
1561
    hidden = True
2252
1562
    takes_args = ['testspecs*']
2258
1568
                            help='Use a different transport by default '
2259
1569
                                 'throughout the test suite.',
2260
1570
                            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'
 
1571
                    ]
2276
1572
 
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):
 
1573
    def run(self, testspecs_list=None, verbose=False, one=False,
 
1574
            keep_output=False, transport=None):
2281
1575
        import bzrlib.ui
2282
1576
        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
 
1577
        # we don't want progress meters from the tests to go to the
 
1578
        # real output; and we don't want log messages cluttering up
 
1579
        # the real logs.
 
1580
        save_ui = bzrlib.ui.ui_factory
 
1581
        bzrlib.trace.info('running tests...')
2311
1582
        try:
 
1583
            bzrlib.ui.ui_factory = bzrlib.ui.SilentUIFactory()
 
1584
            if testspecs_list is not None:
 
1585
                pattern = '|'.join(testspecs_list)
 
1586
            else:
 
1587
                pattern = ".*"
2312
1588
            result = selftest(verbose=verbose, 
2313
1589
                              pattern=pattern,
2314
1590
                              stop_on_failure=one, 
2315
1591
                              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
 
                              )
 
1592
                              transport=transport)
 
1593
            if result:
 
1594
                bzrlib.trace.info('tests passed')
 
1595
            else:
 
1596
                bzrlib.trace.info('tests failed')
 
1597
            return int(not result)
2322
1598
        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)
 
1599
            bzrlib.ui.ui_factory = save_ui
 
1600
 
 
1601
 
 
1602
def _get_bzr_branch():
 
1603
    """If bzr is run from a branch, return Branch or None"""
 
1604
    import bzrlib.errors
 
1605
    from bzrlib.branch import Branch
 
1606
    from bzrlib.osutils import abspath
 
1607
    from os.path import dirname
 
1608
    
 
1609
    try:
 
1610
        branch = Branch.open(dirname(abspath(dirname(__file__))))
 
1611
        return branch
 
1612
    except bzrlib.errors.BzrError:
 
1613
        return None
 
1614
    
 
1615
 
 
1616
def show_version():
 
1617
    print "bzr (bazaar-ng) %s" % bzrlib.__version__
 
1618
    # is bzrlib itself in a branch?
 
1619
    branch = _get_bzr_branch()
 
1620
    if branch:
 
1621
        rh = branch.revision_history()
 
1622
        revno = len(rh)
 
1623
        print "  bzr checkout, revision %d" % (revno,)
 
1624
        print "  nick: %s" % (branch.nick,)
 
1625
        if rh:
 
1626
            print "  revid: %s" % (rh[-1],)
 
1627
    print bzrlib.__copyright__
 
1628
    print "http://bazaar-ng.org/"
 
1629
    print
 
1630
    print "bzr comes with ABSOLUTELY NO WARRANTY.  bzr is free software, and"
 
1631
    print "you may use, modify and redistribute it under the terms of the GNU"
 
1632
    print "General Public License version 2 or later."
2330
1633
 
2331
1634
 
2332
1635
class cmd_version(Command):
2333
1636
    """Show version of bzr."""
2334
 
 
2335
1637
    @display_command
2336
1638
    def run(self):
2337
 
        from bzrlib.version import show_version
2338
1639
        show_version()
2339
1640
 
2340
 
 
2341
1641
class cmd_rocks(Command):
2342
1642
    """Statement of optimism."""
2343
 
 
2344
1643
    hidden = True
2345
 
 
2346
1644
    @display_command
2347
1645
    def run(self):
2348
1646
        print "it sure does!"
2349
1647
 
2350
1648
 
2351
1649
class cmd_find_merge_base(Command):
2352
 
    """Find and print a base revision for merging two branches."""
 
1650
    """Find and print a base revision for merging two branches.
 
1651
    """
2353
1652
    # TODO: Options to specify revisions on either side, as if
2354
1653
    #       merging only part of the history.
2355
1654
    takes_args = ['branch', 'other']
2357
1656
    
2358
1657
    @display_command
2359
1658
    def run(self, branch, other):
2360
 
        from bzrlib.revision import MultipleRevisionSources
 
1659
        from bzrlib.revision import common_ancestor, MultipleRevisionSources
2361
1660
        
2362
1661
        branch1 = Branch.open_containing(branch)[0]
2363
1662
        branch2 = Branch.open_containing(other)[0]
2364
1663
 
 
1664
        history_1 = branch1.revision_history()
 
1665
        history_2 = branch2.revision_history()
 
1666
 
2365
1667
        last1 = branch1.last_revision()
2366
1668
        last2 = branch2.last_revision()
2367
1669
 
2371
1673
        base_rev_id = common_ancestor(last1, last2, source)
2372
1674
 
2373
1675
        print 'merge base is revision %s' % base_rev_id
 
1676
        
 
1677
        return
 
1678
 
 
1679
        if base_revno is None:
 
1680
            raise bzrlib.errors.UnrelatedBranches()
 
1681
 
 
1682
        print ' r%-6d in %s' % (base_revno, branch)
 
1683
 
 
1684
        other_revno = branch2.revision_id_to_revno(base_revid)
 
1685
        
 
1686
        print ' r%-6d in %s' % (other_revno, other)
 
1687
 
2374
1688
 
2375
1689
 
2376
1690
class cmd_merge(Command):
2377
1691
    """Perform a three-way merge.
2378
1692
    
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.
 
1693
    The branch is the branch you will merge from.  By default, it will
 
1694
    merge the latest revision.  If you specify a revision, that
 
1695
    revision will be merged.  If you specify two revisions, the first
 
1696
    will be used as a BASE, and the second one as OTHER.  Revision
 
1697
    numbers are always relative to the specified branch.
2384
1698
 
2385
 
    By default, bzr will try to merge in all new work from the other
 
1699
    By default bzr will try to merge in all new work from the other
2386
1700
    branch, automatically determining an appropriate base.  If this
2387
1701
    fails, you may need to give an explicit base.
2388
1702
    
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
1703
    Examples:
2406
1704
 
2407
1705
    To merge the latest revision from bzr.dev
2415
1713
    
2416
1714
    merge refuses to run if there are any uncommitted changes, unless
2417
1715
    --force is given.
2418
 
 
2419
 
    The following merge types are available:
2420
1716
    """
2421
1717
    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
 
    ]
 
1718
    takes_options = ['revision', 'force', 'merge-type', 'reprocess',
 
1719
                     Option('show-base', help="Show base revision text in "
 
1720
                            "conflicts")]
2438
1721
 
2439
1722
    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
 
            ):
 
1723
            show_base=False, reprocess=False):
2444
1724
        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
 
1725
            merge_type = Merge3Merger
 
1726
        if branch is None:
 
1727
            branch = WorkingTree.open_containing(u'.')[0].branch.get_parent()
 
1728
            if branch is None:
 
1729
                raise BzrCommandError("No merge location known or specified.")
2468
1730
            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
 
 
 
1731
                print "Using saved location: %s" % branch 
2480
1732
        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)
 
1733
            base = [None, None]
 
1734
            other = [branch, -1]
2488
1735
        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
1736
            if len(revision) == 1:
2494
1737
                base = [None, None]
2495
 
                other_branch, path = Branch.open_containing(branch)
 
1738
                other_branch = Branch.open_containing(branch)[0]
2496
1739
                revno = revision[0].in_history(other_branch).revno
2497
1740
                other = [branch, revno]
2498
1741
            else:
2499
1742
                assert len(revision) == 2
2500
1743
                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()
 
1744
                    raise BzrCommandError(
 
1745
                        "Merge doesn't permit that revision specifier.")
 
1746
                b = Branch.open_containing(branch)[0]
 
1747
 
 
1748
                base = [branch, revision[0].in_history(b).revno]
 
1749
                other = [branch, revision[1].in_history(b).revno]
 
1750
 
2521
1751
        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()
 
1752
            conflict_count = merge(other, base, check_clean=(not force),
 
1753
                                   merge_type=merge_type, reprocess=reprocess,
 
1754
                                   show_base=show_base, 
 
1755
                                   pb=bzrlib.ui.ui_factory.progress_bar())
2534
1756
            if conflict_count != 0:
2535
1757
                return 1
2536
1758
            else:
2537
1759
                return 0
2538
 
        except errors.AmbiguousBase, e:
 
1760
        except bzrlib.errors.AmbiguousBase, e:
2539
1761
            m = ("sorry, bzr can't determine the right merge base yet\n"
2540
1762
                 "candidates are:\n  "
2541
1763
                 + "\n  ".join(e.bases)
2544
1766
                 "and (if you want) report this to the bzr developers\n")
2545
1767
            log_error(m)
2546
1768
 
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
1769
 
2564
1770
class cmd_remerge(Command):
2565
1771
    """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:"""
 
1772
    """
2585
1773
    takes_args = ['file*']
2586
1774
    takes_options = ['merge-type', 'reprocess',
2587
1775
                     Option('show-base', help="Show base revision text in "
2589
1777
 
2590
1778
    def run(self, file_list=None, merge_type=None, show_base=False,
2591
1779
            reprocess=False):
 
1780
        from bzrlib.merge import merge_inner, transform_tree
2592
1781
        if merge_type is None:
2593
 
            merge_type = _mod_merge.Merge3Merger
 
1782
            merge_type = Merge3Merger
2594
1783
        tree, file_list = tree_files(file_list)
2595
1784
        tree.lock_write()
2596
1785
        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.")
 
1786
            pending_merges = tree.pending_merges() 
 
1787
            if len(pending_merges) != 1:
 
1788
                raise BzrCommandError("Sorry, remerge only works after normal"
 
1789
                                      + " merges.  Not cherrypicking or"
 
1790
                                      + "multi-merges.")
2602
1791
            repository = tree.branch.repository
2603
 
            base_revision = common_ancestor(parents[0],
2604
 
                                            parents[1], repository)
 
1792
            base_revision = common_ancestor(tree.branch.last_revision(), 
 
1793
                                            pending_merges[0], repository)
2605
1794
            base_tree = repository.revision_tree(base_revision)
2606
 
            other_tree = repository.revision_tree(parents[1])
 
1795
            other_tree = repository.revision_tree(pending_merges[0])
2607
1796
            interesting_ids = None
2608
 
            new_conflicts = []
2609
 
            conflicts = tree.conflicts()
2610
1797
            if file_list is not None:
2611
1798
                interesting_ids = set()
2612
1799
                for filename in file_list:
2613
1800
                    file_id = tree.path2id(filename)
2614
 
                    if file_id is None:
2615
 
                        raise errors.NotVersionedError(filename)
2616
1801
                    interesting_ids.add(file_id)
2617
1802
                    if tree.kind(file_id) != "directory":
2618
1803
                        continue
2619
1804
                    
2620
1805
                    for name, ie in tree.inventory.iter_entries(file_id):
2621
1806
                        interesting_ids.add(ie.file_id)
2622
 
                new_conflicts = conflicts.select_conflicts(tree, file_list)[0]
 
1807
            transform_tree(tree, tree.basis_tree(), interesting_ids)
 
1808
            if file_list is None:
 
1809
                restore_files = list(tree.iter_conflicts())
2623
1810
            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
1811
                restore_files = file_list
2632
1812
            for filename in restore_files:
2633
1813
                try:
2634
1814
                    restore(tree.abspath(filename))
2635
 
                except errors.NotConflicted:
 
1815
                except NotConflicted:
2636
1816
                    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)
 
1817
            conflicts =  merge_inner(tree.branch, other_tree, base_tree, 
 
1818
                                     interesting_ids = interesting_ids, 
 
1819
                                     other_rev_id=pending_merges[0], 
 
1820
                                     merge_type=merge_type, 
 
1821
                                     show_base=show_base,
 
1822
                                     reprocess=reprocess)
2645
1823
        finally:
2646
1824
            tree.unlock()
2647
1825
        if conflicts > 0:
2649
1827
        else:
2650
1828
            return 0
2651
1829
 
2652
 
 
2653
1830
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.
 
1831
    """Reverse all changes since the last commit.
 
1832
 
 
1833
    Only versioned files are affected.  Specify filenames to revert only 
 
1834
    those files.  By default, any files that are changed will be backed up
 
1835
    first.  Backup files have a '~' appended to their name.
2673
1836
    """
2674
1837
    takes_options = ['revision', 'no-backup']
2675
1838
    takes_args = ['file*']
2676
1839
    aliases = ['merge-revert']
2677
1840
 
2678
1841
    def run(self, revision=None, no_backup=False, file_list=None):
 
1842
        from bzrlib.commands import parse_spec
2679
1843
        if file_list is not None:
2680
1844
            if len(file_list) == 0:
2681
 
                raise errors.BzrCommandError("No files specified")
 
1845
                raise BzrCommandError("No files specified")
2682
1846
        else:
2683
1847
            file_list = []
2684
1848
        
2685
1849
        tree, file_list = tree_files(file_list)
2686
1850
        if revision is None:
2687
1851
            # FIXME should be tree.last_revision
2688
 
            rev_id = tree.last_revision()
 
1852
            rev_id = tree.branch.last_revision()
2689
1853
        elif len(revision) != 1:
2690
 
            raise errors.BzrCommandError('bzr revert --revision takes exactly 1 argument')
 
1854
            raise BzrCommandError('bzr revert --revision takes exactly 1 argument')
2691
1855
        else:
2692
1856
            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()
 
1857
        tree.revert(file_list, tree.branch.repository.revision_tree(rev_id),
 
1858
                    not no_backup, bzrlib.ui.ui_factory.progress_bar())
2700
1859
 
2701
1860
 
2702
1861
class cmd_assert_fail(Command):
2703
1862
    """Test reporting of assertion failures"""
2704
 
    # intended just for use in testing
2705
 
 
2706
1863
    hidden = True
2707
 
 
2708
1864
    def run(self):
2709
 
        raise AssertionError("always fails")
 
1865
        assert False, "always fails"
2710
1866
 
2711
1867
 
2712
1868
class cmd_help(Command):
2713
1869
    """Show help on a command or other topic.
2714
1870
 
2715
 
    For a list of all available commands, say 'bzr help commands'.
2716
 
    """
 
1871
    For a list of all available commands, say 'bzr help commands'."""
2717
1872
    takes_options = [Option('long', 'show help on all commands')]
2718
1873
    takes_args = ['topic?']
2719
 
    aliases = ['?', '--help', '-?', '-h']
 
1874
    aliases = ['?']
2720
1875
    
2721
1876
    @display_command
2722
1877
    def run(self, topic=None, long=False):
2723
 
        import bzrlib.help
 
1878
        import help
2724
1879
        if topic is None and long:
2725
1880
            topic = "commands"
2726
 
        bzrlib.help.help(topic)
 
1881
        help.help(topic)
2727
1882
 
2728
1883
 
2729
1884
class cmd_shell_complete(Command):
2730
1885
    """Show appropriate completions for context.
2731
1886
 
2732
 
    For a list of all available commands, say 'bzr shell-complete'.
2733
 
    """
 
1887
    For a list of all available commands, say 'bzr shell-complete'."""
2734
1888
    takes_args = ['context?']
2735
1889
    aliases = ['s-c']
2736
1890
    hidden = True
2744
1898
class cmd_fetch(Command):
2745
1899
    """Copy in history from another branch but don't merge it.
2746
1900
 
2747
 
    This is an internal method used for pull and merge.
2748
 
    """
 
1901
    This is an internal method used for pull and merge."""
2749
1902
    hidden = True
2750
1903
    takes_args = ['from_branch', 'to_branch']
2751
1904
    def run(self, from_branch, to_branch):
2752
1905
        from bzrlib.fetch import Fetcher
 
1906
        from bzrlib.branch import Branch
2753
1907
        from_b = Branch.open(from_branch)
2754
1908
        to_b = Branch.open(to_branch)
2755
1909
        Fetcher(to_b, from_b)
2758
1912
class cmd_missing(Command):
2759
1913
    """Show unmerged/unpulled revisions between two branches.
2760
1914
 
2761
 
    OTHER_BRANCH may be local or remote.
2762
 
    """
 
1915
    OTHER_BRANCH may be local or remote."""
2763
1916
    takes_args = ['other_branch?']
2764
1917
    takes_options = [Option('reverse', 'Reverse the order of revisions'),
2765
1918
                     Option('mine-only', 
2767
1920
                     Option('theirs-only', 
2768
1921
                            'Display changes in the remote branch only'), 
2769
1922
                     'log-format',
 
1923
                     'line',
 
1924
                     'long', 
 
1925
                     'short',
2770
1926
                     'show-ids',
2771
1927
                     'verbose'
2772
1928
                     ]
2773
 
    encoding_type = 'replace'
2774
1929
 
2775
 
    @display_command
2776
1930
    def run(self, other_branch=None, reverse=False, mine_only=False,
2777
1931
            theirs_only=False, log_format=None, long=False, short=False, line=False, 
2778
1932
            show_ids=False, verbose=False):
2779
1933
        from bzrlib.missing import find_unmerged, iter_log_data
2780
1934
        from bzrlib.log import log_formatter
2781
 
        local_branch = Branch.open_containing(u".")[0]
 
1935
        local_branch = bzrlib.branch.Branch.open_containing(u".")[0]
2782
1936
        parent = local_branch.get_parent()
2783
1937
        if other_branch is None:
2784
1938
            other_branch = parent
2785
1939
            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()
 
1940
                raise BzrCommandError("No missing location known or specified.")
 
1941
            print "Using last location: " + local_branch.get_parent()
 
1942
        remote_branch = bzrlib.branch.Branch.open(other_branch)
 
1943
        local_extra, remote_extra = find_unmerged(local_branch, remote_branch)
 
1944
        if (log_format == None):
 
1945
            default = bzrlib.config.BranchConfig(local_branch).log_format()
 
1946
            log_format = get_log_format(long=long, short=short, line=line, default=default)
 
1947
        lf = log_formatter(log_format, sys.stdout,
 
1948
                           show_ids=show_ids,
 
1949
                           show_timezone='original')
 
1950
        if reverse is False:
 
1951
            local_extra.reverse()
 
1952
            remote_extra.reverse()
 
1953
        if local_extra and not theirs_only:
 
1954
            print "You have %d extra revision(s):" % len(local_extra)
 
1955
            for data in iter_log_data(local_extra, local_branch.repository,
 
1956
                                      verbose):
 
1957
                lf.show(*data)
 
1958
            printed_local = True
 
1959
        else:
 
1960
            printed_local = False
 
1961
        if remote_extra and not mine_only:
 
1962
            if printed_local is True:
 
1963
                print "\n\n"
 
1964
            print "You are missing %d revision(s):" % len(remote_extra)
 
1965
            for data in iter_log_data(remote_extra, remote_branch.repository, 
 
1966
                                      verbose):
 
1967
                lf.show(*data)
 
1968
        if not remote_extra and not local_extra:
 
1969
            status_code = 0
 
1970
            print "Branches are up to date."
 
1971
        else:
 
1972
            status_code = 1
 
1973
        if parent is None and other_branch is not None:
 
1974
            local_branch.set_parent(other_branch)
2840
1975
        return status_code
2841
1976
 
2842
1977
 
2848
1983
        import bzrlib.plugin
2849
1984
        from inspect import getdoc
2850
1985
        for name, plugin in bzrlib.plugin.all_plugins().items():
2851
 
            if getattr(plugin, '__path__', None) is not None:
 
1986
            if hasattr(plugin, '__path__'):
2852
1987
                print plugin.__path__[0]
2853
 
            elif getattr(plugin, '__file__', None) is not None:
 
1988
            elif hasattr(plugin, '__file__'):
2854
1989
                print plugin.__file__
2855
1990
            else:
2856
 
                print repr(plugin)
 
1991
                print `plugin`
2857
1992
                
2858
1993
            d = getdoc(plugin)
2859
1994
            if d:
2862
1997
 
2863
1998
class cmd_testament(Command):
2864
1999
    """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')]
 
2000
    takes_options = ['revision', 'long']
2869
2001
    takes_args = ['branch?']
2870
2002
    @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
 
2003
    def run(self, branch=u'.', revision=None, long=False):
 
2004
        from bzrlib.testament import Testament
2877
2005
        b = WorkingTree.open_containing(branch)[0].branch
2878
2006
        b.lock_read()
2879
2007
        try:
2881
2009
                rev_id = b.last_revision()
2882
2010
            else:
2883
2011
                rev_id = revision[0].in_history(b).rev_id
2884
 
            t = testament_class.from_revision(b.repository, rev_id)
 
2012
            t = Testament.from_revision(b.repository, rev_id)
2885
2013
            if long:
2886
2014
                sys.stdout.writelines(t.as_text_lines())
2887
2015
            else:
2900
2028
    shown only at the top, unless the --all option is given.
2901
2029
    """
2902
2030
    # TODO: annotate directories; showing when each file was last changed
 
2031
    # TODO: annotate a previous version of a file
2903
2032
    # TODO: if the working copy is modified, show annotations on that 
2904
2033
    #       with new uncommitted lines marked
2905
 
    aliases = ['ann', 'blame', 'praise']
 
2034
    aliases = ['blame', 'praise']
2906
2035
    takes_args = ['filename']
2907
2036
    takes_options = [Option('all', help='show annotations on all lines'),
2908
2037
                     Option('long', help='show date in annotations'),
2909
 
                     'revision',
2910
 
                     'show-ids',
2911
2038
                     ]
2912
2039
 
2913
2040
    @display_command
2914
 
    def run(self, filename, all=False, long=False, revision=None,
2915
 
            show_ids=False):
 
2041
    def run(self, filename, all=False, long=False):
2916
2042
        from bzrlib.annotate import annotate_file
2917
2043
        tree, relpath = WorkingTree.open_containing(filename)
2918
2044
        branch = tree.branch
2919
2045
        branch.lock_read()
2920
2046
        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)
 
2047
            file_id = tree.inventory.path2id(relpath)
 
2048
            tree = branch.repository.revision_tree(branch.last_revision())
2929
2049
            file_version = tree.inventory[file_id].revision
2930
 
            annotate_file(branch, file_version, file_id, long, all, sys.stdout,
2931
 
                          show_ids=show_ids)
 
2050
            annotate_file(branch, file_version, file_id, long, all, sys.stdout)
2932
2051
        finally:
2933
2052
            branch.unlock()
2934
2053
 
2942
2061
    takes_options = ['revision']
2943
2062
    
2944
2063
    def run(self, revision_id_list=None, revision=None):
 
2064
        import bzrlib.config as config
2945
2065
        import bzrlib.gpg as gpg
2946
2066
        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')
 
2067
            raise BzrCommandError('You can only supply one of revision_id or --revision')
2948
2068
        if revision_id_list is None and revision is None:
2949
 
            raise errors.BzrCommandError('You must supply either --revision or a revision_id')
 
2069
            raise BzrCommandError('You must supply either --revision or a revision_id')
2950
2070
        b = WorkingTree.open_containing(u'.')[0].branch
2951
 
        gpg_strategy = gpg.GPGStrategy(b.get_config())
 
2071
        gpg_strategy = gpg.GPGStrategy(config.BranchConfig(b))
2952
2072
        if revision_id_list is not None:
2953
2073
            for revision_id in revision_id_list:
2954
2074
                b.repository.sign_revision(revision_id, gpg_strategy)
2965
2085
                if to_revid is None:
2966
2086
                    to_revno = b.revno()
2967
2087
                if from_revno is None or to_revno is None:
2968
 
                    raise errors.BzrCommandError('Cannot sign a range of non-revision-history revisions')
 
2088
                    raise BzrCommandError('Cannot sign a range of non-revision-history revisions')
2969
2089
                for revno in range(from_revno, to_revno + 1):
2970
2090
                    b.repository.sign_revision(b.get_rev_id(revno), 
2971
2091
                                               gpg_strategy)
2972
2092
            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):
 
2093
                raise BzrCommandError('Please supply either one revision, or a range.')
 
2094
 
 
2095
 
 
2096
class cmd_uncommit(bzrlib.commands.Command):
3027
2097
    """Remove the last committed revision.
3028
2098
 
 
2099
    By supplying the --all flag, it will not only remove the entry 
 
2100
    from revision_history, but also remove all of the entries in the
 
2101
    stores.
 
2102
 
3029
2103
    --verbose will print out what is being removed.
3030
2104
    --dry-run will go through all the motions, but not actually
3031
2105
    remove anything.
3032
2106
    
3033
 
    In the future, uncommit will create a revision bundle, which can then
 
2107
    In the future, uncommit will create a changeset, which can then
3034
2108
    be re-applied.
 
2109
 
 
2110
    TODO: jam 20060108 Add an option to allow uncommit to remove unreferenced
 
2111
              information in 'branch-as-repostory' branches.
 
2112
    TODO: jam 20060108 Add the ability for uncommit to remove unreferenced
 
2113
              information in shared branches as well.
3035
2114
    """
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
2115
    takes_options = ['verbose', 'revision',
3042
2116
                    Option('dry-run', help='Don\'t actually make changes'),
3043
2117
                    Option('force', help='Say yes to all questions.')]
3044
2118
    takes_args = ['location?']
3045
2119
    aliases = []
3046
2120
 
3047
 
    def run(self, location=None,
 
2121
    def run(self, location=None, 
3048
2122
            dry_run=False, verbose=False,
3049
2123
            revision=None, force=False):
3050
 
        from bzrlib.log import log_formatter, show_log
 
2124
        from bzrlib.branch import Branch
 
2125
        from bzrlib.log import log_formatter
3051
2126
        import sys
3052
2127
        from bzrlib.uncommit import uncommit
3053
2128
 
3054
2129
        if location is None:
3055
2130
            location = u'.'
3056
2131
        control, relpath = bzrdir.BzrDir.open_containing(location)
 
2132
        b = control.open_branch()
3057
2133
        try:
3058
2134
            tree = control.open_workingtree()
3059
 
            b = tree.branch
3060
2135
        except (errors.NoWorkingTree, errors.NotLocalUrl):
3061
2136
            tree = None
3062
 
            b = control.open_branch()
3063
2137
 
3064
 
        rev_id = None
3065
2138
        if revision is None:
3066
2139
            revno = b.revno()
 
2140
            rev_id = b.last_revision()
3067
2141
        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)
 
2142
            revno, rev_id = revision[0].in_history(b)
3077
2143
        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())
 
2144
            print 'No revisions to uncommit.'
 
2145
 
 
2146
        for r in range(revno, b.revno()+1):
 
2147
            rev_id = b.get_rev_id(r)
 
2148
            lf = log_formatter('short', to_file=sys.stdout,show_timezone='original')
 
2149
            lf.show(r, b.repository.get_revision(rev_id), None)
3091
2150
 
3092
2151
        if dry_run:
3093
2152
            print 'Dry-run, pretending to remove the above revisions.'
3105
2164
                revno=revno)
3106
2165
 
3107
2166
 
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):
 
2167
def merge(other_revision, base_revision,
 
2168
          check_clean=True, ignore_zero=False,
 
2169
          this_dir=None, backup_files=False, merge_type=Merge3Merger,
 
2170
          file_list=None, show_base=False, reprocess=False, 
 
2171
          pb=DummyProgress()):
3201
2172
    """Merge changes into a tree.
3202
2173
 
3203
2174
    base_revision
3225
2196
    clients might prefer to call merge.merge_inner(), which has less magic 
3226
2197
    behavior.
3227
2198
    """
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
 
2199
    from bzrlib.merge import Merger
3231
2200
    if this_dir is None:
3232
2201
        this_dir = u'.'
3233
2202
    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)
 
2203
    if show_base and not merge_type is Merge3Merger:
 
2204
        raise BzrCommandError("Show-base is not supported for this merge"
 
2205
                              " type. %s" % merge_type)
 
2206
    if reprocess and not merge_type is Merge3Merger:
 
2207
        raise BzrCommandError("Reprocess is not supported for this merge"
 
2208
                              " type. %s" % merge_type)
3240
2209
    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()
 
2210
        raise BzrCommandError("Cannot reprocess and show base.")
 
2211
    merger = Merger(this_tree.branch, this_tree=this_tree, pb=pb)
 
2212
    merger.check_basis(check_clean)
 
2213
    merger.set_other(other_revision)
 
2214
    merger.set_base(base_revision)
 
2215
    if merger.base_rev_id == merger.other_rev_id:
 
2216
        note('Nothing to do.')
 
2217
        return 0
 
2218
    merger.backup_files = backup_files
 
2219
    merger.merge_type = merge_type 
 
2220
    merger.set_interesting_files(file_list)
 
2221
    merger.show_base = show_base 
 
2222
    merger.reprocess = reprocess
 
2223
    conflicts = merger.do_merge()
 
2224
    merger.set_pending()
3278
2225
    return conflicts
3279
2226
 
3280
2227
 
3281
 
# Compatibility
3282
 
merge = _merge_helper
3283
 
 
3284
 
 
3285
2228
# these get imported and then picked up by the scan for cmd_*
3286
2229
# TODO: Some more consistent way to split command definitions across files;
3287
2230
# 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
 
2231
# aliases.
3291
2232
from bzrlib.conflicts import cmd_resolve, cmd_conflicts, restore
3292
 
from bzrlib.bundle.commands import cmd_bundle_revisions
3293
2233
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