~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/builtins.py

Exclude more files from dumb-rsync upload

Show diffs side-by-side

added added

removed removed

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