~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/builtins.py

  • Committer: Canonical.com Patch Queue Manager
  • Date: 2006-06-03 20:18:35 UTC
  • mfrom: (1185.82.137 w-changeset)
  • Revision ID: pqm@pqm.ubuntu.com-20060603201835-1c9a1725641ccd24
Implement bundles

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
# Copyright (C) 2004, 2005, 2006 by Canonical Ltd
2
 
#
 
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
17
17
"""builtin bzr commands"""
18
18
 
19
19
 
20
 
import codecs
21
20
import errno
22
21
import os
23
 
import os.path
24
22
import sys
25
23
 
26
24
import bzrlib
27
 
from bzrlib import (
28
 
    branch,
29
 
    bundle,
30
 
    bzrdir,
31
 
    config,
32
 
    errors,
33
 
    ignores,
34
 
    log,
35
 
    osutils,
36
 
    repository,
37
 
    transport,
38
 
    ui,
39
 
    urlutils,
40
 
    )
41
 
from bzrlib.branch import Branch, BranchReferenceFormat
42
 
from bzrlib.bundle import read_bundle_from_url
43
 
from bzrlib.bundle.apply_bundle import install_bundle, merge_bundle
44
 
from bzrlib.conflicts import ConflictList
 
25
import bzrlib.branch
 
26
from bzrlib.branch import Branch
 
27
import bzrlib.bzrdir as bzrdir
 
28
from bzrlib.bundle.read_bundle import BundleReader
 
29
from bzrlib.bundle.apply_bundle import merge_bundle
45
30
from bzrlib.commands import Command, display_command
 
31
import bzrlib.errors as errors
46
32
from bzrlib.errors import (BzrError, BzrCheckError, BzrCommandError, 
47
33
                           NotBranchError, DivergedBranches, NotConflicted,
48
34
                           NoSuchFile, NoWorkingTree, FileInWrongBranch,
49
 
                           NotVersionedError, NotABundle)
 
35
                           NotVersionedError, BadBundle)
 
36
from bzrlib.log import show_one_log
50
37
from bzrlib.merge import Merge3Merger
51
38
from bzrlib.option import Option
52
39
from bzrlib.progress import DummyProgress, ProgressPhase
53
40
from bzrlib.revision import common_ancestor
54
41
from bzrlib.revisionspec import RevisionSpec
55
 
from bzrlib.trace import mutter, note, log_error, warning, is_quiet, info
 
42
import bzrlib.trace
 
43
from bzrlib.trace import mutter, note, log_error, warning, is_quiet
56
44
from bzrlib.transport.local import LocalTransport
 
45
import bzrlib.ui
57
46
from bzrlib.workingtree import WorkingTree
58
47
 
59
48
 
101
90
        return bzrdir.BzrDirMetaFormat1()
102
91
    if typestring == "metaweave":
103
92
        format = bzrdir.BzrDirMetaFormat1()
104
 
        format.repository_format = repository.RepositoryFormat7()
 
93
        format.repository_format = bzrlib.repository.RepositoryFormat7()
105
94
        return format
106
95
    if typestring == "knit":
107
96
        format = bzrdir.BzrDirMetaFormat1()
108
 
        format.repository_format = repository.RepositoryFormatKnit1()
 
97
        format.repository_format = bzrlib.repository.RepositoryFormatKnit1()
109
98
        return format
110
99
    msg = "Unknown bzr format %s. Current formats are: default, knit,\n" \
111
100
          "metaweave and weave" % typestring
139
128
    modified
140
129
        Text has changed since the previous revision.
141
130
 
 
131
    unchanged
 
132
        Nothing about this file has changed since the previous revision.
 
133
        Only shown with --all.
 
134
 
142
135
    unknown
143
136
        Not versioned and not matching an ignore pattern.
144
137
 
157
150
    # TODO: --no-recurse, --recurse options
158
151
    
159
152
    takes_args = ['file*']
160
 
    takes_options = ['show-ids', 'revision']
 
153
    takes_options = ['all', 'show-ids', 'revision']
161
154
    aliases = ['st', 'stat']
162
 
 
163
 
    encoding_type = 'replace'
164
155
    
165
156
    @display_command
166
 
    def run(self, show_ids=False, file_list=None, revision=None):
 
157
    def run(self, all=False, show_ids=False, file_list=None, revision=None):
 
158
        tree, file_list = tree_files(file_list)
 
159
            
167
160
        from bzrlib.status import show_tree_status
168
 
 
169
 
        tree, file_list = tree_files(file_list)
170
 
            
171
 
        show_tree_status(tree, show_ids=show_ids,
172
 
                         specific_files=file_list, revision=revision,
173
 
                         to_file=self.outf)
 
161
        show_tree_status(tree, show_unchanged=all, show_ids=show_ids,
 
162
                         specific_files=file_list, revision=revision)
174
163
 
175
164
 
176
165
class cmd_cat_revision(Command):
183
172
    hidden = True
184
173
    takes_args = ['revision_id?']
185
174
    takes_options = ['revision']
186
 
    # cat-revision is more for frontends so should be exact
187
 
    encoding = 'strict'
188
175
    
189
176
    @display_command
190
177
    def run(self, revision_id=None, revision=None):
194
181
        if revision_id is None and revision is None:
195
182
            raise BzrCommandError('You must supply either --revision or a revision_id')
196
183
        b = WorkingTree.open_containing(u'.')[0].branch
197
 
 
198
 
        # TODO: jam 20060112 should cat-revision always output utf-8?
199
184
        if revision_id is not None:
200
 
            self.outf.write(b.repository.get_revision_xml(revision_id).decode('utf-8'))
 
185
            sys.stdout.write(b.repository.get_revision_xml(revision_id))
201
186
        elif revision is not None:
202
187
            for rev in revision:
203
188
                if rev is None:
204
189
                    raise BzrCommandError('You cannot specify a NULL revision.')
205
190
                revno, rev_id = rev.in_history(b)
206
 
                self.outf.write(b.repository.get_revision_xml(rev_id).decode('utf-8'))
 
191
                sys.stdout.write(b.repository.get_revision_xml(rev_id))
207
192
    
208
193
 
209
194
class cmd_revno(Command):
210
195
    """Show current revision number.
211
196
 
212
 
    This is equal to the number of revisions on this branch.
213
 
    """
214
 
 
 
197
    This is equal to the number of revisions on this branch."""
215
198
    takes_args = ['location?']
216
 
 
217
199
    @display_command
218
200
    def run(self, location=u'.'):
219
 
        self.outf.write(str(Branch.open_containing(location)[0].revno()))
220
 
        self.outf.write('\n')
 
201
        print Branch.open_containing(location)[0].revno()
221
202
 
222
203
 
223
204
class cmd_revision_info(Command):
226
207
    hidden = True
227
208
    takes_args = ['revision_info*']
228
209
    takes_options = ['revision']
229
 
 
230
210
    @display_command
231
211
    def run(self, revision=None, revision_info_list=[]):
232
212
 
269
249
 
270
250
    Adding a file whose parent directory is not versioned will
271
251
    implicitly add the parent, and so on up to the root. This means
272
 
    you should never need to explicitly add a directory, they'll just
 
252
    you should never need to explictly add a directory, they'll just
273
253
    get added when you add a file in the directory.
274
254
 
275
255
    --dry-run will show which files would be added, but not actually 
277
257
    """
278
258
    takes_args = ['file*']
279
259
    takes_options = ['no-recurse', 'dry-run', 'verbose']
280
 
    encoding_type = 'replace'
281
260
 
282
261
    def run(self, file_list, no_recurse=False, dry_run=False, verbose=False):
283
262
        import bzrlib.add
284
263
 
285
 
        action = bzrlib.add.AddAction(to_file=self.outf,
286
 
            should_print=(not is_quiet()))
 
264
        if dry_run:
 
265
            if is_quiet():
 
266
                # This is pointless, but I'd rather not raise an error
 
267
                action = bzrlib.add.add_action_null
 
268
            else:
 
269
                action = bzrlib.add.add_action_print
 
270
        elif is_quiet():
 
271
            action = bzrlib.add.add_action_add
 
272
        else:
 
273
            action = bzrlib.add.add_action_add_and_print
287
274
 
288
275
        added, ignored = bzrlib.add.smart_add(file_list, not no_recurse, 
289
 
                                              action=action, save=not dry_run)
 
276
                                              action)
290
277
        if len(ignored) > 0:
291
278
            if verbose:
292
279
                for glob in sorted(ignored.keys()):
293
280
                    for path in ignored[glob]:
294
 
                        self.outf.write("ignored %s matching \"%s\"\n" 
295
 
                                        % (path, glob))
 
281
                        print "ignored %s matching \"%s\"" % (path, glob)
296
282
            else:
297
283
                match_len = 0
298
284
                for glob, paths in ignored.items():
299
285
                    match_len += len(paths)
300
 
                self.outf.write("ignored %d file(s).\n" % match_len)
301
 
            self.outf.write("If you wish to add some of these files,"
302
 
                            " please add them by name.\n")
 
286
                print "ignored %d file(s)." % match_len
 
287
            print "If you wish to add some of these files, please add them"\
 
288
                " by name."
303
289
 
304
290
 
305
291
class cmd_mkdir(Command):
307
293
 
308
294
    This is equivalent to creating the directory and then adding it.
309
295
    """
310
 
 
311
296
    takes_args = ['dir+']
312
 
    encoding_type = 'replace'
313
297
 
314
298
    def run(self, dir_list):
315
299
        for d in dir_list:
316
300
            os.mkdir(d)
317
301
            wt, dd = WorkingTree.open_containing(d)
318
302
            wt.add([dd])
319
 
            self.outf.write('added %s\n' % d)
 
303
            print 'added', d
320
304
 
321
305
 
322
306
class cmd_relpath(Command):
323
307
    """Show path of a file relative to root"""
324
 
 
325
308
    takes_args = ['filename']
326
309
    hidden = True
327
310
    
328
311
    @display_command
329
312
    def run(self, filename):
330
 
        # TODO: jam 20050106 Can relpath return a munged path if
331
 
        #       sys.stdout encoding cannot represent it?
332
313
        tree, relpath = WorkingTree.open_containing(filename)
333
 
        self.outf.write(relpath)
334
 
        self.outf.write('\n')
 
314
        print relpath
335
315
 
336
316
 
337
317
class cmd_inventory(Command):
340
320
    It is possible to limit the output to a particular entry
341
321
    type using the --kind option.  For example; --kind file.
342
322
    """
343
 
 
344
323
    takes_options = ['revision', 'show-ids', 'kind']
345
324
    
346
325
    @display_command
361
340
            if kind and kind != entry.kind:
362
341
                continue
363
342
            if show_ids:
364
 
                self.outf.write('%-50s %s\n' % (path, entry.file_id))
 
343
                print '%-50s %s' % (path, entry.file_id)
365
344
            else:
366
 
                self.outf.write(path)
367
 
                self.outf.write('\n')
 
345
                print path
368
346
 
369
347
 
370
348
class cmd_mv(Command):
380
358
 
381
359
    Files cannot be moved between branches.
382
360
    """
383
 
 
384
361
    takes_args = ['names*']
385
362
    aliases = ['move', 'rename']
386
 
    encoding_type = 'replace'
387
363
 
388
364
    def run(self, names_list):
389
 
        if names_list is None:
390
 
            names_list = []
391
 
 
392
365
        if len(names_list) < 2:
393
366
            raise BzrCommandError("missing file argument")
394
367
        tree, rel_names = tree_files(names_list)
396
369
        if os.path.isdir(names_list[-1]):
397
370
            # move into existing directory
398
371
            for pair in tree.move(rel_names[:-1], rel_names[-1]):
399
 
                self.outf.write("%s => %s\n" % pair)
 
372
                print "%s => %s" % pair
400
373
        else:
401
374
            if len(names_list) != 2:
402
375
                raise BzrCommandError('to mv multiple files the destination '
403
376
                                      'must be a versioned directory')
404
377
            tree.rename_one(rel_names[0], rel_names[1])
405
 
            self.outf.write("%s => %s\n" % (rel_names[0], rel_names[1]))
 
378
            print "%s => %s" % (rel_names[0], rel_names[1])
406
379
            
407
380
    
408
381
class cmd_pull(Command):
416
389
    from one into the other.  Once one branch has merged, the other should
417
390
    be able to pull it again.
418
391
 
 
392
    If branches have diverged, you can use 'bzr merge' to pull the text changes
 
393
    from one into the other.  Once one branch has merged, the other should
 
394
    be able to pull it again.
 
395
 
419
396
    If you want to forget your local changes and just update your branch to
420
397
    match the remote one, use pull --overwrite.
421
398
 
422
399
    If there is no default location set, the first pull will set it.  After
423
400
    that, you can omit the location to use the default.  To change the
424
 
    default, use --remember. The value will only be saved if the remote
425
 
    location can be accessed.
 
401
    default, use --remember.
426
402
    """
427
 
 
428
403
    takes_options = ['remember', 'overwrite', 'revision', 'verbose']
429
404
    takes_args = ['location?']
430
 
    encoding_type = 'replace'
431
405
 
432
406
    def run(self, location=None, remember=False, overwrite=False, revision=None, verbose=False):
433
407
        # FIXME: too much stuff is in the command class
436
410
            branch_to = tree_to.branch
437
411
        except NoWorkingTree:
438
412
            tree_to = None
439
 
            branch_to = Branch.open_containing(u'.')[0]
440
 
 
441
 
        reader = None
442
 
        if location is not None:
443
 
            try:
444
 
                reader = bundle.read_bundle_from_url(location)
445
 
            except NotABundle:
446
 
                pass # Continue on considering this url a Branch
447
 
 
 
413
            branch_to = Branch.open_containing(u'.')[0] 
448
414
        stored_loc = branch_to.get_parent()
449
415
        if location is None:
450
416
            if stored_loc is None:
451
417
                raise BzrCommandError("No pull location known or specified.")
452
418
            else:
453
 
                display_url = urlutils.unescape_for_display(stored_loc,
454
 
                        self.outf.encoding)
455
 
                self.outf.write("Using saved location: %s\n" % display_url)
 
419
                print "Using saved location: %s" % stored_loc
456
420
                location = stored_loc
457
421
 
458
 
 
459
 
        if reader is not None:
460
 
            install_bundle(branch_to.repository, reader)
461
 
            branch_from = branch_to
462
 
        else:
463
 
            branch_from = Branch.open(location)
464
 
 
465
 
            if branch_to.get_parent() is None or remember:
466
 
                branch_to.set_parent(branch_from.base)
467
 
 
468
 
        rev_id = None
 
422
        if branch_to.get_parent() is None or remember:
 
423
            branch_to.set_parent(location)
 
424
 
 
425
        branch_from = Branch.open(location)
 
426
 
469
427
        if revision is None:
470
 
            if reader is not None:
471
 
                rev_id = reader.target
 
428
            rev_id = None
472
429
        elif len(revision) == 1:
473
430
            rev_id = revision[0].in_history(branch_from).rev_id
474
431
        else:
486
443
            if old_rh != new_rh:
487
444
                # Something changed
488
445
                from bzrlib.log import show_changed_revisions
489
 
                show_changed_revisions(branch_to, old_rh, new_rh,
490
 
                                       to_file=self.outf)
 
446
                show_changed_revisions(branch_to, old_rh, new_rh)
491
447
 
492
448
 
493
449
class cmd_push(Command):
512
468
 
513
469
    If there is no default push location set, the first push will set it.
514
470
    After that, you can omit the location to use the default.  To change the
515
 
    default, use --remember. The value will only be saved if the remote
516
 
    location can be accessed.
 
471
    default, use --remember.
517
472
    """
518
 
 
519
 
    takes_options = ['remember', 'overwrite', 'verbose',
 
473
    takes_options = ['remember', 'overwrite', 
520
474
                     Option('create-prefix', 
521
475
                            help='Create the path leading up to the branch '
522
476
                                 'if it does not already exist')]
523
477
    takes_args = ['location?']
524
 
    encoding_type = 'replace'
525
478
 
526
479
    def run(self, location=None, remember=False, overwrite=False,
527
480
            create_prefix=False, verbose=False):
528
481
        # FIXME: Way too big!  Put this into a function called from the
529
482
        # command.
 
483
        from bzrlib.transport import get_transport
530
484
        
531
485
        br_from = Branch.open_containing('.')[0]
532
486
        stored_loc = br_from.get_push_location()
534
488
            if stored_loc is None:
535
489
                raise BzrCommandError("No push location known or specified.")
536
490
            else:
537
 
                display_url = urlutils.unescape_for_display(stored_loc,
538
 
                        self.outf.encoding)
539
 
                self.outf.write("Using saved location: %s\n" % display_url)
 
491
                print "Using saved location: %s" % stored_loc
540
492
                location = stored_loc
541
 
 
542
 
        to_transport = transport.get_transport(location)
543
 
        location_url = to_transport.base
544
 
 
545
 
        old_rh = []
 
493
        if br_from.get_push_location() is None or remember:
 
494
            br_from.set_push_location(location)
546
495
        try:
547
 
            dir_to = bzrdir.BzrDir.open(location_url)
 
496
            dir_to = bzrlib.bzrdir.BzrDir.open(location)
548
497
            br_to = dir_to.open_branch()
549
498
        except NotBranchError:
550
499
            # create a branch.
551
 
            to_transport = to_transport.clone('..')
 
500
            transport = get_transport(location).clone('..')
552
501
            if not create_prefix:
553
502
                try:
554
 
                    relurl = to_transport.relpath(location_url)
555
 
                    mutter('creating directory %s => %s', location_url, relurl)
556
 
                    to_transport.mkdir(relurl)
 
503
                    transport.mkdir(transport.relpath(location))
557
504
                except NoSuchFile:
558
505
                    raise BzrCommandError("Parent directory of %s "
559
506
                                          "does not exist." % location)
560
507
            else:
561
 
                current = to_transport.base
562
 
                needed = [(to_transport, to_transport.relpath(location_url))]
 
508
                current = transport.base
 
509
                needed = [(transport, transport.relpath(location))]
563
510
                while needed:
564
511
                    try:
565
 
                        to_transport, relpath = needed[-1]
566
 
                        to_transport.mkdir(relpath)
 
512
                        transport, relpath = needed[-1]
 
513
                        transport.mkdir(relpath)
567
514
                        needed.pop()
568
515
                    except NoSuchFile:
569
 
                        new_transport = to_transport.clone('..')
 
516
                        new_transport = transport.clone('..')
570
517
                        needed.append((new_transport,
571
 
                                       new_transport.relpath(to_transport.base)))
572
 
                        if new_transport.base == to_transport.base:
 
518
                                       new_transport.relpath(transport.base)))
 
519
                        if new_transport.base == transport.base:
573
520
                            raise BzrCommandError("Could not create "
574
521
                                                  "path prefix.")
575
 
            dir_to = br_from.bzrdir.clone(location_url,
 
522
            dir_to = br_from.bzrdir.clone(location,
576
523
                revision_id=br_from.last_revision())
577
524
            br_to = dir_to.open_branch()
578
525
            count = len(br_to.revision_history())
579
 
            # We successfully created the target, remember it
580
 
            if br_from.get_push_location() is None or remember:
581
 
                br_from.set_push_location(br_to.base)
582
526
        else:
583
 
            # We were able to connect to the remote location, so remember it
584
 
            # we don't need to successfully push because of possible divergence.
585
 
            if br_from.get_push_location() is None or remember:
586
 
                br_from.set_push_location(br_to.base)
587
527
            old_rh = br_to.revision_history()
588
528
            try:
589
529
                try:
606
546
            if old_rh != new_rh:
607
547
                # Something changed
608
548
                from bzrlib.log import show_changed_revisions
609
 
                show_changed_revisions(br_to, old_rh, new_rh,
610
 
                                       to_file=self.outf)
 
549
                show_changed_revisions(br_to, old_rh, new_rh)
611
550
 
612
551
 
613
552
class cmd_branch(Command):
628
567
    aliases = ['get', 'clone']
629
568
 
630
569
    def run(self, from_location, to_location=None, revision=None, basis=None):
 
570
        from bzrlib.osutils import rmtree
631
571
        if revision is None:
632
572
            revision = [None]
633
573
        elif len(revision) > 1:
659
599
                name = None
660
600
            else:
661
601
                name = os.path.basename(to_location) + '\n'
662
 
 
663
 
            to_transport = transport.get_transport(to_location)
664
602
            try:
665
 
                to_transport.mkdir('.')
666
 
            except errors.FileExists:
667
 
                raise BzrCommandError('Target directory "%s" already'
668
 
                                      ' exists.' % to_location)
669
 
            except errors.NoSuchFile:
670
 
                raise BzrCommandError('Parent of "%s" does not exist.' %
671
 
                                      to_location)
 
603
                os.mkdir(to_location)
 
604
            except OSError, e:
 
605
                if e.errno == errno.EEXIST:
 
606
                    raise BzrCommandError('Target directory "%s" already'
 
607
                                          ' exists.' % to_location)
 
608
                if e.errno == errno.ENOENT:
 
609
                    raise BzrCommandError('Parent of "%s" does not exist.' %
 
610
                                          to_location)
 
611
                else:
 
612
                    raise
672
613
            try:
673
614
                # preserve whatever source format we have.
674
 
                dir = br_from.bzrdir.sprout(to_transport.base,
675
 
                        revision_id, basis_dir)
 
615
                dir = br_from.bzrdir.sprout(to_location, revision_id, basis_dir)
676
616
                branch = dir.open_branch()
677
 
            except errors.NoSuchRevision:
678
 
                to_transport.delete_tree('.')
 
617
            except bzrlib.errors.NoSuchRevision:
 
618
                rmtree(to_location)
679
619
                msg = "The branch %s has no revision %s." % (from_location, revision[0])
680
620
                raise BzrCommandError(msg)
681
 
            except errors.UnlistableBranch:
682
 
                osutils.rmtree(to_location)
 
621
            except bzrlib.errors.UnlistableBranch:
 
622
                rmtree(to_location)
683
623
                msg = "The branch %s cannot be used as a --basis" % (basis,)
684
624
                raise BzrCommandError(msg)
685
625
            if name:
686
626
                branch.control_files.put_utf8('branch-name', name)
 
627
 
687
628
            note('Branched %d revision(s).' % branch.revno())
688
629
        finally:
689
630
            br_from.unlock()
719
660
                                 "such access, and also support local commits."
720
661
                            ),
721
662
                     ]
722
 
    aliases = ['co']
723
663
 
724
664
    def run(self, branch_location=None, to_location=None, revision=None, basis=None,
725
665
            lightweight=False):
729
669
            raise BzrCommandError(
730
670
                'bzr checkout --revision takes exactly 1 revision value')
731
671
        if branch_location is None:
732
 
            branch_location = osutils.getcwd()
 
672
            branch_location = bzrlib.osutils.getcwd()
733
673
            to_location = branch_location
734
674
        source = Branch.open(branch_location)
735
675
        if len(revision) == 1 and revision[0] is not None:
741
681
        # if the source and to_location are the same, 
742
682
        # and there is no working tree,
743
683
        # then reconstitute a branch
744
 
        if (osutils.abspath(to_location) == 
745
 
            osutils.abspath(branch_location)):
 
684
        if (bzrlib.osutils.abspath(to_location) == 
 
685
            bzrlib.osutils.abspath(branch_location)):
746
686
            try:
747
687
                source.bzrdir.open_workingtree()
748
688
            except errors.NoWorkingTree:
759
699
                                      to_location)
760
700
            else:
761
701
                raise
762
 
        old_format = bzrdir.BzrDirFormat.get_default_format()
763
 
        bzrdir.BzrDirFormat.set_default_format(bzrdir.BzrDirMetaFormat1())
 
702
        old_format = bzrlib.bzrdir.BzrDirFormat.get_default_format()
 
703
        bzrlib.bzrdir.BzrDirFormat.set_default_format(bzrdir.BzrDirMetaFormat1())
764
704
        try:
765
 
            source.create_checkout(to_location, revision_id, lightweight)
 
705
            if lightweight:
 
706
                checkout = bzrdir.BzrDirMetaFormat1().initialize(to_location)
 
707
                bzrlib.branch.BranchReferenceFormat().initialize(checkout, source)
 
708
            else:
 
709
                checkout_branch =  bzrlib.bzrdir.BzrDir.create_branch_convenience(
 
710
                    to_location, force_new_tree=False)
 
711
                checkout = checkout_branch.bzrdir
 
712
                checkout_branch.bind(source)
 
713
                if revision_id is not None:
 
714
                    rh = checkout_branch.revision_history()
 
715
                    checkout_branch.set_revision_history(rh[:rh.index(revision_id) + 1])
 
716
            checkout.create_workingtree(revision_id)
766
717
        finally:
767
 
            bzrdir.BzrDirFormat.set_default_format(old_format)
 
718
            bzrlib.bzrdir.BzrDirFormat.set_default_format(old_format)
768
719
 
769
720
 
770
721
class cmd_renames(Command):
777
728
 
778
729
    @display_command
779
730
    def run(self, dir=u'.'):
780
 
        from bzrlib.tree import find_renames
781
731
        tree = WorkingTree.open_containing(dir)[0]
782
732
        old_inv = tree.basis_tree().inventory
783
733
        new_inv = tree.read_working_inventory()
784
 
        renames = list(find_renames(old_inv, new_inv))
 
734
 
 
735
        renames = list(bzrlib.tree.find_renames(old_inv, new_inv))
785
736
        renames.sort()
786
737
        for old_name, new_name in renames:
787
 
            self.outf.write("%s => %s\n" % (old_name, new_name))
 
738
            print "%s => %s" % (old_name, new_name)        
788
739
 
789
740
 
790
741
class cmd_update(Command):
798
749
    'bzr revert' instead of 'bzr commit' after the update.
799
750
    """
800
751
    takes_args = ['dir?']
801
 
    aliases = ['up']
802
752
 
803
753
    def run(self, dir='.'):
804
754
        tree = WorkingTree.open_containing(dir)[0]
805
755
        tree.lock_write()
806
 
        existing_pending_merges = tree.pending_merges()
807
756
        try:
808
 
            last_rev = tree.last_revision() 
809
 
            if last_rev == tree.branch.last_revision():
 
757
            if tree.last_revision() == tree.branch.last_revision():
810
758
                # may be up to date, check master too.
811
759
                master = tree.branch.get_master_branch()
812
 
                if master is None or last_rev == master.last_revision():
813
 
                    revno = tree.branch.revision_id_to_revno(last_rev)
814
 
                    note("Tree is up to date at revision %d." % (revno,))
815
 
                    return 0
 
760
                if master is None or master.last_revision == tree.last_revision():
 
761
                    note("Tree is up to date.")
 
762
                    return
816
763
            conflicts = tree.update()
817
 
            revno = tree.branch.revision_id_to_revno(tree.last_revision())
818
 
            note('Updated to revision %d.' % (revno,))
819
 
            if tree.pending_merges() != existing_pending_merges:
820
 
                note('Your local commits will now show as pending merges with '
821
 
                     "'bzr status', and can be committed with 'bzr commit'.")
 
764
            note('Updated to revision %d.' %
 
765
                 (tree.branch.revision_id_to_revno(tree.last_revision()),))
822
766
            if conflicts != 0:
823
767
                return 1
824
768
            else:
860
804
    takes_args = ['file*']
861
805
    takes_options = ['verbose', Option('new', help='remove newly-added files')]
862
806
    aliases = ['rm']
863
 
    encoding_type = 'replace'
864
807
    
865
808
    def run(self, file_list, verbose=False, new=False):
866
809
        tree, file_list = tree_files(file_list)
869
812
                raise BzrCommandError('Specify one or more files to remove, or'
870
813
                                      ' use --new.')
871
814
        else:
872
 
            added = tree.changes_from(tree.basis_tree(),
873
 
                specific_files=file_list).added
874
 
            file_list = sorted([f[0] for f in added], reverse=True)
 
815
            from bzrlib.delta import compare_trees
 
816
            added = [compare_trees(tree.basis_tree(), tree,
 
817
                                   specific_files=file_list).added]
 
818
            file_list = sorted([f[0] for f in added[0]], reverse=True)
875
819
            if len(file_list) == 0:
876
820
                raise BzrCommandError('No matching files.')
877
 
        tree.remove(file_list, verbose=verbose, to_file=self.outf)
 
821
        tree.remove(file_list, verbose=verbose)
878
822
 
879
823
 
880
824
class cmd_file_id(Command):
884
828
    same through all revisions where the file exists, even when it is
885
829
    moved or renamed.
886
830
    """
887
 
 
888
831
    hidden = True
889
832
    takes_args = ['filename']
890
 
 
891
833
    @display_command
892
834
    def run(self, filename):
893
835
        tree, relpath = WorkingTree.open_containing(filename)
895
837
        if i == None:
896
838
            raise BzrError("%r is not a versioned file" % filename)
897
839
        else:
898
 
            self.outf.write(i + '\n')
 
840
            print i
899
841
 
900
842
 
901
843
class cmd_file_path(Command):
902
844
    """Print path of file_ids to a file or directory.
903
845
 
904
846
    This prints one line for each directory down to the target,
905
 
    starting at the branch root.
906
 
    """
907
 
 
 
847
    starting at the branch root."""
908
848
    hidden = True
909
849
    takes_args = ['filename']
910
 
 
911
850
    @display_command
912
851
    def run(self, filename):
913
852
        tree, relpath = WorkingTree.open_containing(filename)
916
855
        if fid == None:
917
856
            raise BzrError("%r is not a versioned file" % filename)
918
857
        for fip in inv.get_idpath(fid):
919
 
            self.outf.write(fip + '\n')
 
858
            print fip
920
859
 
921
860
 
922
861
class cmd_reconcile(Command):
941
880
 
942
881
    def run(self, branch="."):
943
882
        from bzrlib.reconcile import reconcile
944
 
        dir = bzrdir.BzrDir.open(branch)
 
883
        dir = bzrlib.bzrdir.BzrDir.open(branch)
945
884
        reconcile(dir)
946
885
 
947
886
 
948
887
class cmd_revision_history(Command):
949
 
    """Display the list of revision ids on a branch."""
950
 
    takes_args = ['location?']
951
 
 
 
888
    """Display list of revision ids on this branch."""
952
889
    hidden = True
953
 
 
954
890
    @display_command
955
 
    def run(self, location="."):
956
 
        branch = Branch.open_containing(location)[0]
957
 
        for revid in branch.revision_history():
958
 
            self.outf.write(revid)
959
 
            self.outf.write('\n')
 
891
    def run(self):
 
892
        branch = WorkingTree.open_containing(u'.')[0].branch
 
893
        for patchid in branch.revision_history():
 
894
            print patchid
960
895
 
961
896
 
962
897
class cmd_ancestry(Command):
963
898
    """List all revisions merged into this branch."""
964
 
    takes_args = ['location?']
965
 
 
966
899
    hidden = True
967
 
 
968
900
    @display_command
969
 
    def run(self, location="."):
970
 
        try:
971
 
            wt = WorkingTree.open_containing(location)[0]
972
 
        except errors.NoWorkingTree:
973
 
            b = Branch.open(location)
974
 
            last_revision = b.last_revision()
975
 
        else:
976
 
            b = wt.branch
977
 
            last_revision = wt.last_revision()
978
 
 
979
 
        revision_ids = b.repository.get_ancestry(last_revision)
 
901
    def run(self):
 
902
        tree = WorkingTree.open_containing(u'.')[0]
 
903
        b = tree.branch
 
904
        # FIXME. should be tree.last_revision
 
905
        revision_ids = b.repository.get_ancestry(b.last_revision())
980
906
        assert revision_ids[0] == None
981
907
        revision_ids.pop(0)
982
908
        for revision_id in revision_ids:
983
 
            self.outf.write(revision_id + '\n')
 
909
            print revision_id
984
910
 
985
911
 
986
912
class cmd_init(Command):
1014
940
                            type=get_format_type),
1015
941
                     ]
1016
942
    def run(self, location=None, format=None):
 
943
        from bzrlib.branch import Branch
1017
944
        if format is None:
1018
945
            format = get_format_type('default')
1019
946
        if location is None:
1020
947
            location = u'.'
1021
 
 
1022
 
        to_transport = transport.get_transport(location)
1023
 
 
1024
 
        # The path has to exist to initialize a
1025
 
        # branch inside of it.
1026
 
        # Just using os.mkdir, since I don't
1027
 
        # believe that we want to create a bunch of
1028
 
        # locations if the user supplies an extended path
1029
 
        # TODO: create-prefix
1030
 
        try:
1031
 
            to_transport.mkdir('.')
1032
 
        except errors.FileExists:
1033
 
            pass
1034
 
                    
 
948
        else:
 
949
            # The path has to exist to initialize a
 
950
            # branch inside of it.
 
951
            # Just using os.mkdir, since I don't
 
952
            # believe that we want to create a bunch of
 
953
            # locations if the user supplies an extended path
 
954
            if not os.path.exists(location):
 
955
                os.mkdir(location)
1035
956
        try:
1036
957
            existing_bzrdir = bzrdir.BzrDir.open(location)
1037
958
        except NotBranchError:
1039
960
            bzrdir.BzrDir.create_branch_convenience(location, format=format)
1040
961
        else:
1041
962
            if existing_bzrdir.has_branch():
1042
 
                if (isinstance(to_transport, LocalTransport)
1043
 
                    and not existing_bzrdir.has_workingtree()):
1044
 
                        raise errors.BranchExistsWithoutWorkingTree(location)
1045
 
                raise errors.AlreadyBranchError(location)
 
963
                if existing_bzrdir.has_workingtree():
 
964
                    raise errors.AlreadyBranchError(location)
 
965
                else:
 
966
                    raise errors.BranchExistsWithoutWorkingTree(location)
1046
967
            else:
1047
968
                existing_bzrdir.create_branch()
1048
969
                existing_bzrdir.create_workingtree()
1074
995
                             ' a working tree')]
1075
996
    aliases = ["init-repo"]
1076
997
    def run(self, location, format=None, trees=False):
 
998
        from bzrlib.transport import get_transport
1077
999
        if format is None:
1078
1000
            format = get_format_type('default')
1079
 
 
1080
 
        if location is None:
1081
 
            location = '.'
1082
 
 
1083
 
        to_transport = transport.get_transport(location)
1084
 
        try:
1085
 
            to_transport.mkdir('.')
1086
 
        except errors.FileExists:
1087
 
            pass
1088
 
 
1089
 
        newdir = format.initialize_on_transport(to_transport)
 
1001
        transport = get_transport(location)
 
1002
        if not transport.has('.'):
 
1003
            transport.mkdir('')
 
1004
        newdir = format.initialize_on_transport(transport)
1090
1005
        repo = newdir.create_repository(shared=True)
1091
1006
        repo.set_make_working_trees(trees)
1092
1007
 
1093
1008
 
1094
1009
class cmd_diff(Command):
1095
 
    """Show differences in the working tree or between revisions.
 
1010
    """Show differences in working tree.
1096
1011
    
1097
1012
    If files are listed, only the changes in those files are listed.
1098
1013
    Otherwise, all changes for the tree are listed.
1102
1017
 
1103
1018
    examples:
1104
1019
        bzr diff
1105
 
            Shows the difference in the working tree versus the last commit
1106
1020
        bzr diff -r1
1107
 
            Difference between the working tree and revision 1
1108
1021
        bzr diff -r1..2
1109
 
            Difference between revision 2 and revision 1
1110
1022
        bzr diff --diff-prefix old/:new/
1111
 
            Same as 'bzr diff' but prefix paths with old/ and new/
1112
1023
        bzr diff bzr.mine bzr.dev
1113
 
            Show the differences between the two working trees
1114
1024
        bzr diff foo.c
1115
 
            Show just the differences for 'foo.c'
1116
1025
    """
1117
1026
    # TODO: Option to use external diff command; could be GNU diff, wdiff,
1118
1027
    #       or a graphical diff.
1128
1037
    takes_args = ['file*']
1129
1038
    takes_options = ['revision', 'diff-options', 'prefix']
1130
1039
    aliases = ['di', 'dif']
1131
 
    encoding_type = 'exact'
1132
1040
 
1133
1041
    @display_command
1134
1042
    def run(self, revision=None, file_list=None, diff_options=None,
1162
1070
                # FIXME diff those two files. rbc 20051123
1163
1071
                raise BzrCommandError("Files are in different branches")
1164
1072
            file_list = None
1165
 
        except NotBranchError:
1166
 
            if (revision is not None and len(revision) == 2
1167
 
                and not revision[0].needs_branch()
1168
 
                and not revision[1].needs_branch()):
1169
 
                # If both revision specs include a branch, we can
1170
 
                # diff them without needing a local working tree
1171
 
                tree1, tree2 = None, None
1172
 
            else:
1173
 
                raise
1174
1073
        if revision is not None:
1175
1074
            if tree2 is not None:
1176
1075
                raise BzrCommandError("Can't specify -r with two branches")
1204
1103
    # directories with readdir, rather than stating each one.  Same
1205
1104
    # level of effort but possibly much less IO.  (Or possibly not,
1206
1105
    # if the directories are very large...)
1207
 
    takes_options = ['show-ids']
1208
 
 
1209
1106
    @display_command
1210
1107
    def run(self, show_ids=False):
1211
1108
        tree = WorkingTree.open_containing(u'.')[0]
1212
1109
        old = tree.basis_tree()
1213
1110
        for path, ie in old.inventory.iter_entries():
1214
1111
            if not tree.has_id(ie.file_id):
1215
 
                self.outf.write(path)
1216
1112
                if show_ids:
1217
 
                    self.outf.write(' ')
1218
 
                    self.outf.write(ie.file_id)
1219
 
                self.outf.write('\n')
 
1113
                    print '%-50s %s' % (path, ie.file_id)
 
1114
                else:
 
1115
                    print path
1220
1116
 
1221
1117
 
1222
1118
class cmd_modified(Command):
1224
1120
    hidden = True
1225
1121
    @display_command
1226
1122
    def run(self):
 
1123
        from bzrlib.delta import compare_trees
 
1124
 
1227
1125
        tree = WorkingTree.open_containing(u'.')[0]
1228
 
        td = tree.changes_from(tree.basis_tree())
 
1126
        td = compare_trees(tree.basis_tree(), tree)
 
1127
 
1229
1128
        for path, id, kind, text_modified, meta_modified in td.modified:
1230
 
            self.outf.write(path + '\n')
 
1129
            print path
 
1130
 
1231
1131
 
1232
1132
 
1233
1133
class cmd_added(Command):
1242
1142
            if file_id in basis_inv:
1243
1143
                continue
1244
1144
            path = inv.id2path(file_id)
1245
 
            if not os.access(osutils.abspath(path), os.F_OK):
 
1145
            if not os.access(bzrlib.osutils.abspath(path), os.F_OK):
1246
1146
                continue
1247
 
            self.outf.write(path + '\n')
1248
 
 
 
1147
            print path
 
1148
                
 
1149
        
1249
1150
 
1250
1151
class cmd_root(Command):
1251
1152
    """Show the tree root directory.
1257
1158
    def run(self, filename=None):
1258
1159
        """Print the branch root."""
1259
1160
        tree = WorkingTree.open_containing(filename)[0]
1260
 
        self.outf.write(tree.basedir + '\n')
 
1161
        print tree.basedir
1261
1162
 
1262
1163
 
1263
1164
class cmd_log(Command):
1291
1192
                            type=str),
1292
1193
                     'short',
1293
1194
                     ]
1294
 
    encoding_type = 'replace'
1295
 
 
1296
1195
    @display_command
1297
1196
    def run(self, location=None, timezone='original',
1298
1197
            verbose=False,
1305
1204
            short=False,
1306
1205
            line=False):
1307
1206
        from bzrlib.log import log_formatter, show_log
 
1207
        import codecs
1308
1208
        assert message is None or isinstance(message, basestring), \
1309
1209
            "invalid message argument %r" % message
1310
1210
        direction = (forward and 'forward') or 'reverse'
1356
1256
        if rev1 > rev2:
1357
1257
            (rev2, rev1) = (rev1, rev2)
1358
1258
 
 
1259
        mutter('encoding log as %r', bzrlib.user_encoding)
 
1260
 
 
1261
        # use 'replace' so that we don't abort if trying to write out
 
1262
        # in e.g. the default C locale.
 
1263
        outf = codecs.getwriter(bzrlib.user_encoding)(sys.stdout, errors='replace')
 
1264
 
1359
1265
        if (log_format == None):
1360
 
            default = b.get_config().log_format()
1361
 
            log_format = get_log_format(long=long, short=short, line=line, 
1362
 
                                        default=default)
 
1266
            default = bzrlib.config.BranchConfig(b).log_format()
 
1267
            log_format = get_log_format(long=long, short=short, line=line, default=default)
 
1268
 
1363
1269
        lf = log_formatter(log_format,
1364
1270
                           show_ids=show_ids,
1365
 
                           to_file=self.outf,
 
1271
                           to_file=outf,
1366
1272
                           show_timezone=timezone)
1367
1273
 
1368
1274
        show_log(b,
1389
1295
class cmd_touching_revisions(Command):
1390
1296
    """Return revision-ids which affected a particular file.
1391
1297
 
1392
 
    A more user-friendly interface is "bzr log FILE".
1393
 
    """
1394
 
 
 
1298
    A more user-friendly interface is "bzr log FILE"."""
1395
1299
    hidden = True
1396
1300
    takes_args = ["filename"]
1397
 
 
1398
1301
    @display_command
1399
1302
    def run(self, filename):
1400
1303
        tree, relpath = WorkingTree.open_containing(filename)
1401
1304
        b = tree.branch
1402
1305
        inv = tree.read_working_inventory()
1403
1306
        file_id = inv.path2id(relpath)
1404
 
        for revno, revision_id, what in log.find_touching_revisions(b, file_id):
1405
 
            self.outf.write("%6d %s\n" % (revno, what))
 
1307
        for revno, revision_id, what in bzrlib.log.find_touching_revisions(b, file_id):
 
1308
            print "%6d %s" % (revno, what)
1406
1309
 
1407
1310
 
1408
1311
class cmd_ls(Command):
1441
1344
        if revision is not None:
1442
1345
            tree = tree.branch.repository.revision_tree(
1443
1346
                revision[0].in_history(tree.branch).rev_id)
1444
 
 
1445
1347
        for fp, fc, kind, fid, entry in tree.list_files():
1446
1348
            if fp.startswith(relpath):
1447
1349
                fp = fp[len(relpath):]
1451
1353
                    continue
1452
1354
                if verbose:
1453
1355
                    kindch = entry.kind_character()
1454
 
                    self.outf.write('%-8s %s%s\n' % (fc, fp, kindch))
 
1356
                    print '%-8s %s%s' % (fc, fp, kindch)
1455
1357
                elif null:
1456
 
                    self.outf.write(fp + '\0')
1457
 
                    self.outf.flush()
 
1358
                    sys.stdout.write(fp)
 
1359
                    sys.stdout.write('\0')
 
1360
                    sys.stdout.flush()
1458
1361
                else:
1459
 
                    self.outf.write(fp + '\n')
 
1362
                    print fp
1460
1363
 
1461
1364
 
1462
1365
class cmd_unknowns(Command):
1463
1366
    """List unknown files."""
1464
1367
    @display_command
1465
1368
    def run(self):
 
1369
        from bzrlib.osutils import quotefn
1466
1370
        for f in WorkingTree.open_containing(u'.')[0].unknowns():
1467
 
            self.outf.write(osutils.quotefn(f) + '\n')
 
1371
            print quotefn(f)
1468
1372
 
1469
1373
 
1470
1374
class cmd_ignore(Command):
1486
1390
        bzr ignore '*.class'
1487
1391
    """
1488
1392
    # TODO: Complain if the filename is absolute
1489
 
    takes_args = ['name_pattern?']
1490
 
    takes_options = [
1491
 
                     Option('old-default-rules',
1492
 
                            help='Out the ignore rules bzr < 0.9 always used.')
1493
 
                     ]
 
1393
    takes_args = ['name_pattern']
1494
1394
    
1495
 
    def run(self, name_pattern=None, old_default_rules=None):
 
1395
    def run(self, name_pattern):
1496
1396
        from bzrlib.atomicfile import AtomicFile
1497
 
        if old_default_rules is not None:
1498
 
            # dump the rules and exit
1499
 
            for pattern in ignores.OLD_DEFAULTS:
1500
 
                print pattern
1501
 
            return
1502
 
        if name_pattern is None:
1503
 
            raise BzrCommandError("ignore requires a NAME_PATTERN")
 
1397
        import os.path
 
1398
 
1504
1399
        tree, relpath = WorkingTree.open_containing(u'.')
1505
1400
        ifn = tree.abspath('.bzrignore')
 
1401
 
1506
1402
        if os.path.exists(ifn):
1507
1403
            f = open(ifn, 'rt')
1508
1404
            try:
1593
1489
    takes_args = ['dest']
1594
1490
    takes_options = ['revision', 'format', 'root']
1595
1491
    def run(self, dest, revision=None, format=None, root=None):
 
1492
        import os.path
1596
1493
        from bzrlib.export import export
1597
1494
        tree = WorkingTree.open_containing(u'.')[0]
1598
1495
        b = tree.branch
1641
1538
    hidden = True    
1642
1539
    @display_command
1643
1540
    def run(self):
1644
 
        print osutils.local_time_offset()
 
1541
        print bzrlib.osutils.local_time_offset()
1645
1542
 
1646
1543
 
1647
1544
 
1694
1591
        from bzrlib.msgeditor import edit_commit_message, \
1695
1592
                make_commit_message_template
1696
1593
        from tempfile import TemporaryFile
 
1594
        import codecs
1697
1595
 
1698
1596
        # TODO: Need a blackbox test for invoking the external editor; may be
1699
1597
        # slightly problematic to run this cross-platform.
1722
1620
            raise BzrCommandError("please specify either --message or --file")
1723
1621
        
1724
1622
        if file:
 
1623
            import codecs
1725
1624
            message = codecs.open(file, 'rt', bzrlib.user_encoding).read()
1726
1625
 
1727
1626
        if message == "":
1728
 
            raise BzrCommandError("empty commit message specified")
 
1627
                raise BzrCommandError("empty commit message specified")
1729
1628
        
1730
1629
        if verbose:
1731
1630
            reporter = ReportCommitToLog()
1739
1638
        except PointlessCommit:
1740
1639
            # FIXME: This should really happen before the file is read in;
1741
1640
            # perhaps prepare the commit; get the message; then actually commit
1742
 
            raise BzrCommandError("no changes to commit."
1743
 
                                  " use --unchanged to commit anyhow")
 
1641
            raise BzrCommandError("no changes to commit",
 
1642
                                  ["use --unchanged to commit anyhow"])
1744
1643
        except ConflictsInTree:
1745
1644
            raise BzrCommandError("Conflicts detected in working tree.  "
1746
1645
                'Use "bzr conflicts" to list, "bzr resolve FILE" to resolve.')
1748
1647
            raise BzrCommandError("Commit refused because there are unknown "
1749
1648
                                  "files in the working tree.")
1750
1649
        except errors.BoundBranchOutOfDate, e:
1751
 
            raise BzrCommandError(str(e) + "\n"
1752
 
                'To commit to master branch, run update and then commit.\n'
1753
 
                'You can also pass --local to commit to continue working '
1754
 
                'disconnected.')
 
1650
            raise BzrCommandError(str(e)
 
1651
                                  + ' Either unbind, update, or'
 
1652
                                    ' pass --local to commit.')
 
1653
 
1755
1654
 
1756
1655
class cmd_check(Command):
1757
1656
    """Validate consistency of branch history.
1817
1716
 
1818
1717
 
1819
1718
class cmd_whoami(Command):
1820
 
    """Show or set bzr user id.
1821
 
    
1822
 
    examples:
1823
 
        bzr whoami --email
1824
 
        bzr whoami 'Frank Chu <fchu@example.com>'
1825
 
    """
1826
 
    takes_options = [ Option('email',
1827
 
                             help='display email address only'),
1828
 
                      Option('branch',
1829
 
                             help='set identity for the current branch instead of '
1830
 
                                  'globally'),
1831
 
                    ]
1832
 
    takes_args = ['name?']
1833
 
    encoding_type = 'replace'
 
1719
    """Show bzr user id."""
 
1720
    takes_options = ['email']
1834
1721
    
1835
1722
    @display_command
1836
 
    def run(self, email=False, branch=False, name=None):
1837
 
        if name is None:
1838
 
            # use branch if we're inside one; otherwise global config
1839
 
            try:
1840
 
                c = Branch.open_containing('.')[0].get_config()
1841
 
            except NotBranchError:
1842
 
                c = config.GlobalConfig()
1843
 
            if email:
1844
 
                self.outf.write(c.user_email() + '\n')
1845
 
            else:
1846
 
                self.outf.write(c.username() + '\n')
1847
 
            return
1848
 
 
1849
 
        # display a warning if an email address isn't included in the given name.
 
1723
    def run(self, email=False):
1850
1724
        try:
1851
 
            config.extract_email_address(name)
1852
 
        except BzrError, e:
1853
 
            warning('"%s" does not seem to contain an email address.  '
1854
 
                    'This is allowed, but not recommended.', name)
 
1725
            b = WorkingTree.open_containing(u'.')[0].branch
 
1726
            config = bzrlib.config.BranchConfig(b)
 
1727
        except NotBranchError:
 
1728
            config = bzrlib.config.GlobalConfig()
1855
1729
        
1856
 
        # use global config unless --branch given
1857
 
        if branch:
1858
 
            c = Branch.open_containing('.')[0].get_config()
 
1730
        if email:
 
1731
            print config.user_email()
1859
1732
        else:
1860
 
            c = config.GlobalConfig()
1861
 
        c.set_user_option('email', name)
 
1733
            print config.username()
1862
1734
 
1863
1735
 
1864
1736
class cmd_nick(Command):
1944
1816
        # we don't want progress meters from the tests to go to the
1945
1817
        # real output; and we don't want log messages cluttering up
1946
1818
        # the real logs.
1947
 
        save_ui = ui.ui_factory
1948
 
        print '%10s: %s' % ('bzr', osutils.realpath(sys.argv[0]))
 
1819
        save_ui = bzrlib.ui.ui_factory
 
1820
        print '%10s: %s' % ('bzr', bzrlib.osutils.realpath(sys.argv[0]))
1949
1821
        print '%10s: %s' % ('bzrlib', bzrlib.__path__[0])
1950
1822
        print
1951
 
        info('running tests...')
 
1823
        bzrlib.trace.info('running tests...')
1952
1824
        try:
1953
 
            ui.ui_factory = ui.SilentUIFactory()
 
1825
            bzrlib.ui.ui_factory = bzrlib.ui.SilentUIFactory()
1954
1826
            if testspecs_list is not None:
1955
1827
                pattern = '|'.join(testspecs_list)
1956
1828
            else:
1971
1843
                              test_suite_factory=test_suite_factory,
1972
1844
                              lsprof_timed=lsprof_timed)
1973
1845
            if result:
1974
 
                info('tests passed')
 
1846
                bzrlib.trace.info('tests passed')
1975
1847
            else:
1976
 
                info('tests failed')
 
1848
                bzrlib.trace.info('tests failed')
1977
1849
            return int(not result)
1978
1850
        finally:
1979
 
            ui.ui_factory = save_ui
 
1851
            bzrlib.ui.ui_factory = save_ui
1980
1852
 
1981
1853
 
1982
1854
def _get_bzr_branch():
1983
1855
    """If bzr is run from a branch, return Branch or None"""
 
1856
    import bzrlib.errors
 
1857
    from bzrlib.branch import Branch
 
1858
    from bzrlib.osutils import abspath
1984
1859
    from os.path import dirname
1985
1860
    
1986
1861
    try:
1987
 
        branch = Branch.open(dirname(osutils.abspath(dirname(__file__))))
 
1862
        branch = Branch.open(dirname(abspath(dirname(__file__))))
1988
1863
        return branch
1989
 
    except errors.BzrError:
 
1864
    except bzrlib.errors.BzrError:
1990
1865
        return None
1991
1866
    
1992
1867
 
1993
1868
def show_version():
1994
 
    import bzrlib
1995
 
    print "Bazaar (bzr) %s" % bzrlib.__version__
 
1869
    print "bzr (bazaar-ng) %s" % bzrlib.__version__
1996
1870
    # is bzrlib itself in a branch?
1997
1871
    branch = _get_bzr_branch()
1998
1872
    if branch:
2024
1898
 
2025
1899
class cmd_version(Command):
2026
1900
    """Show version of bzr."""
2027
 
 
2028
1901
    @display_command
2029
1902
    def run(self):
2030
1903
        show_version()
2031
1904
 
2032
 
 
2033
1905
class cmd_rocks(Command):
2034
1906
    """Statement of optimism."""
2035
 
 
2036
1907
    hidden = True
2037
 
 
2038
1908
    @display_command
2039
1909
    def run(self):
2040
1910
        print "it sure does!"
2041
1911
 
2042
1912
 
2043
1913
class cmd_find_merge_base(Command):
2044
 
    """Find and print a base revision for merging two branches."""
 
1914
    """Find and print a base revision for merging two branches.
 
1915
    """
2045
1916
    # TODO: Options to specify revisions on either side, as if
2046
1917
    #       merging only part of the history.
2047
1918
    takes_args = ['branch', 'other']
2066
1937
        base_rev_id = common_ancestor(last1, last2, source)
2067
1938
 
2068
1939
        print 'merge base is revision %s' % base_rev_id
 
1940
        
 
1941
        return
 
1942
 
 
1943
        if base_revno is None:
 
1944
            raise bzrlib.errors.UnrelatedBranches()
 
1945
 
 
1946
        print ' r%-6d in %s' % (base_revno, branch)
 
1947
 
 
1948
        other_revno = branch2.revision_id_to_revno(base_revid)
 
1949
        
 
1950
        print ' r%-6d in %s' % (other_revno, other)
 
1951
 
2069
1952
 
2070
1953
 
2071
1954
class cmd_merge(Command):
2072
1955
    """Perform a three-way merge.
2073
1956
    
2074
 
    The branch is the branch you will merge from.  By default, it will merge
2075
 
    the latest revision.  If you specify a revision, that revision will be
2076
 
    merged.  If you specify two revisions, the first will be used as a BASE,
2077
 
    and the second one as OTHER.  Revision numbers are always relative to the
2078
 
    specified branch.
 
1957
    The branch is the branch you will merge from.  By default, it will
 
1958
    merge the latest revision.  If you specify a revision, that
 
1959
    revision will be merged.  If you specify two revisions, the first
 
1960
    will be used as a BASE, and the second one as OTHER.  Revision
 
1961
    numbers are always relative to the specified branch.
2079
1962
 
2080
1963
    By default, bzr will try to merge in all new work from the other
2081
1964
    branch, automatically determining an appropriate base.  If this
2090
1973
 
2091
1974
    If there is no default branch set, the first merge will set it. After
2092
1975
    that, you can omit the branch to use the default.  To change the
2093
 
    default, use --remember. The value will only be saved if the remote
2094
 
    location can be accessed.
 
1976
    default, use --remember.
2095
1977
 
2096
1978
    Examples:
2097
1979
 
2112
1994
    takes_args = ['branch?']
2113
1995
    takes_options = ['revision', 'force', 'merge-type', 'reprocess', 'remember',
2114
1996
                     Option('show-base', help="Show base revision text in "
2115
 
                            "conflicts"), 
2116
 
                     Option('uncommitted', help='Apply uncommitted changes'
2117
 
                            ' from a working copy, instead of branch changes')]
 
1997
                            "conflicts")]
2118
1998
 
2119
1999
    def help(self):
2120
2000
        from merge import merge_type_help
2122
2002
        return getdoc(self) + '\n' + merge_type_help() 
2123
2003
 
2124
2004
    def run(self, branch=None, revision=None, force=False, merge_type=None,
2125
 
            show_base=False, reprocess=False, remember=False, 
2126
 
            uncommitted=False):
 
2005
            show_base=False, reprocess=False, remember=False):
2127
2006
        if merge_type is None:
2128
2007
            merge_type = Merge3Merger
2129
2008
 
 
2009
 
2130
2010
        tree = WorkingTree.open_containing(u'.')[0]
2131
 
 
2132
 
        if branch is not None:
2133
 
            try:
2134
 
                reader = bundle.read_bundle_from_url(branch)
2135
 
            except NotABundle:
2136
 
                pass # Continue on considering this url a Branch
2137
 
            else:
2138
 
                conflicts = merge_bundle(reader, tree, not force, merge_type,
2139
 
                                            reprocess, show_base)
2140
 
                if conflicts == 0:
2141
 
                    return 0
2142
 
                else:
2143
 
                    return 1
2144
 
 
2145
 
        branch = self._get_remembered_parent(tree, branch, 'Merging from')
 
2011
        try:
 
2012
            if branch is not None:
 
2013
                reader = BundleReader(file(branch, 'rb'))
 
2014
            else:
 
2015
                reader = None
 
2016
        except IOError, e:
 
2017
            if e.errno not in (errno.ENOENT, errno.EISDIR):
 
2018
                raise
 
2019
            reader = None
 
2020
        except BadBundle:
 
2021
            reader = None
 
2022
        if reader is not None:
 
2023
            conflicts = merge_bundle(reader, tree, not force, merge_type,
 
2024
                                        reprocess, show_base)
 
2025
            if conflicts == 0:
 
2026
                return 0
 
2027
            else:
 
2028
                return 1
 
2029
 
 
2030
        stored_loc = tree.branch.get_parent()
 
2031
        if branch is None:
 
2032
            if stored_loc is None:
 
2033
                raise BzrCommandError("No merge branch known or specified.")
 
2034
            else:
 
2035
                print "Using saved branch: %s" % stored_loc
 
2036
                branch = stored_loc
 
2037
 
 
2038
        if tree.branch.get_parent() is None or remember:
 
2039
            tree.branch.set_parent(branch)
2146
2040
 
2147
2041
        if revision is None or len(revision) < 1:
2148
 
            if uncommitted:
2149
 
                base = [branch, -1]
2150
 
                other = [branch, None]
2151
 
            else:
2152
 
                base = [None, None]
2153
 
                other = [branch, -1]
 
2042
            base = [None, None]
 
2043
            other = [branch, -1]
2154
2044
            other_branch, path = Branch.open_containing(branch)
2155
2045
        else:
2156
 
            if uncommitted:
2157
 
                raise BzrCommandError('Cannot use --uncommitted and --revision'
2158
 
                                      ' at the same time.')
2159
2046
            if len(revision) == 1:
2160
2047
                base = [None, None]
2161
2048
                other_branch, path = Branch.open_containing(branch)
2166
2053
                if None in revision:
2167
2054
                    raise BzrCommandError(
2168
2055
                        "Merge doesn't permit that revision specifier.")
2169
 
                other_branch, path = Branch.open_containing(branch)
2170
 
 
2171
 
                base = [branch, revision[0].in_history(other_branch).revno]
2172
 
                other = [branch, revision[1].in_history(other_branch).revno]
2173
 
 
2174
 
        if tree.branch.get_parent() is None or remember:
2175
 
            tree.branch.set_parent(other_branch.base)
2176
 
 
 
2056
                b, path = Branch.open_containing(branch)
 
2057
 
 
2058
                base = [branch, revision[0].in_history(b).revno]
 
2059
                other = [branch, revision[1].in_history(b).revno]
2177
2060
        if path != "":
2178
2061
            interesting_files = [path]
2179
2062
        else:
2180
2063
            interesting_files = None
2181
 
        pb = ui.ui_factory.nested_progress_bar()
 
2064
        pb = bzrlib.ui.ui_factory.nested_progress_bar()
2182
2065
        try:
2183
2066
            try:
2184
2067
                conflict_count = merge(other, base, check_clean=(not force),
2185
 
                                       merge_type=merge_type,
 
2068
                                       merge_type=merge_type, 
2186
2069
                                       reprocess=reprocess,
2187
 
                                       show_base=show_base,
 
2070
                                       show_base=show_base, 
2188
2071
                                       pb=pb, file_list=interesting_files)
2189
2072
            finally:
2190
2073
                pb.finished()
2192
2075
                return 1
2193
2076
            else:
2194
2077
                return 0
2195
 
        except errors.AmbiguousBase, e:
 
2078
        except bzrlib.errors.AmbiguousBase, e:
2196
2079
            m = ("sorry, bzr can't determine the right merge base yet\n"
2197
2080
                 "candidates are:\n  "
2198
2081
                 + "\n  ".join(e.bases)
2201
2084
                 "and (if you want) report this to the bzr developers\n")
2202
2085
            log_error(m)
2203
2086
 
2204
 
    # TODO: move up to common parent; this isn't merge-specific anymore. 
2205
 
    def _get_remembered_parent(self, tree, supplied_location, verb_string):
2206
 
        """Use tree.branch's parent if none was supplied.
2207
 
 
2208
 
        Report if the remembered location was used.
2209
 
        """
2210
 
        if supplied_location is not None:
2211
 
            return supplied_location
2212
 
        stored_location = tree.branch.get_parent()
2213
 
        mutter("%s", stored_location)
2214
 
        if stored_location is None:
2215
 
            raise BzrCommandError("No location specified or remembered")
2216
 
        display_url = urlutils.unescape_for_display(stored_location, self.outf.encoding)
2217
 
        self.outf.write("%s remembered location %s\n" % (verb_string, display_url))
2218
 
        return stored_location
2219
 
 
2220
2087
 
2221
2088
class cmd_remerge(Command):
2222
2089
    """Redo a merge.
2260
2127
            pending_merges = tree.pending_merges() 
2261
2128
            if len(pending_merges) != 1:
2262
2129
                raise BzrCommandError("Sorry, remerge only works after normal"
2263
 
                                      " merges.  Not cherrypicking or"
2264
 
                                      " multi-merges.")
 
2130
                                      + " merges.  Not cherrypicking or"
 
2131
                                      + "multi-merges.")
2265
2132
            repository = tree.branch.repository
2266
2133
            base_revision = common_ancestor(tree.branch.last_revision(), 
2267
2134
                                            pending_merges[0], repository)
2268
2135
            base_tree = repository.revision_tree(base_revision)
2269
2136
            other_tree = repository.revision_tree(pending_merges[0])
2270
2137
            interesting_ids = None
2271
 
            new_conflicts = []
2272
 
            conflicts = tree.conflicts()
2273
2138
            if file_list is not None:
2274
2139
                interesting_ids = set()
2275
2140
                for filename in file_list:
2282
2147
                    
2283
2148
                    for name, ie in tree.inventory.iter_entries(file_id):
2284
2149
                        interesting_ids.add(ie.file_id)
2285
 
                new_conflicts = conflicts.select_conflicts(tree, file_list)[0]
2286
2150
            transform_tree(tree, tree.basis_tree(), interesting_ids)
2287
 
            tree.set_conflicts(ConflictList(new_conflicts))
2288
2151
            if file_list is None:
2289
2152
                restore_files = list(tree.iter_conflicts())
2290
2153
            else:
2294
2157
                    restore(tree.abspath(filename))
2295
2158
                except NotConflicted:
2296
2159
                    pass
2297
 
            conflicts = merge_inner(tree.branch, other_tree, base_tree,
2298
 
                                    this_tree=tree,
2299
 
                                    interesting_ids=interesting_ids, 
2300
 
                                    other_rev_id=pending_merges[0], 
2301
 
                                    merge_type=merge_type, 
2302
 
                                    show_base=show_base,
2303
 
                                    reprocess=reprocess)
 
2160
            conflicts =  merge_inner(tree.branch, other_tree, base_tree,
 
2161
                                     this_tree=tree,
 
2162
                                     interesting_ids = interesting_ids, 
 
2163
                                     other_rev_id=pending_merges[0], 
 
2164
                                     merge_type=merge_type, 
 
2165
                                     show_base=show_base,
 
2166
                                     reprocess=reprocess)
2304
2167
        finally:
2305
2168
            tree.unlock()
2306
2169
        if conflicts > 0:
2335
2198
            raise BzrCommandError('bzr revert --revision takes exactly 1 argument')
2336
2199
        else:
2337
2200
            rev_id = revision[0].in_history(tree.branch).rev_id
2338
 
        pb = ui.ui_factory.nested_progress_bar()
 
2201
        pb = bzrlib.ui.ui_factory.nested_progress_bar()
2339
2202
        try:
2340
2203
            tree.revert(file_list, 
2341
2204
                        tree.branch.repository.revision_tree(rev_id),
2389
2252
    takes_args = ['from_branch', 'to_branch']
2390
2253
    def run(self, from_branch, to_branch):
2391
2254
        from bzrlib.fetch import Fetcher
 
2255
        from bzrlib.branch import Branch
2392
2256
        from_b = Branch.open(from_branch)
2393
2257
        to_b = Branch.open(to_branch)
2394
2258
        Fetcher(to_b, from_b)
2411
2275
                     'show-ids',
2412
2276
                     'verbose'
2413
2277
                     ]
2414
 
    encoding_type = 'replace'
2415
2278
 
2416
 
    @display_command
2417
2279
    def run(self, other_branch=None, reverse=False, mine_only=False,
2418
2280
            theirs_only=False, log_format=None, long=False, short=False, line=False, 
2419
2281
            show_ids=False, verbose=False):
2420
2282
        from bzrlib.missing import find_unmerged, iter_log_data
2421
2283
        from bzrlib.log import log_formatter
2422
 
        local_branch = Branch.open_containing(u".")[0]
 
2284
        local_branch = bzrlib.branch.Branch.open_containing(u".")[0]
2423
2285
        parent = local_branch.get_parent()
2424
2286
        if other_branch is None:
2425
2287
            other_branch = parent
2426
2288
            if other_branch is None:
2427
 
                raise BzrCommandError("No peer location known or specified.")
 
2289
                raise BzrCommandError("No missing location known or specified.")
2428
2290
            print "Using last location: " + local_branch.get_parent()
2429
 
        remote_branch = Branch.open(other_branch)
 
2291
        remote_branch = bzrlib.branch.Branch.open(other_branch)
2430
2292
        if remote_branch.base == local_branch.base:
2431
2293
            remote_branch = local_branch
2432
2294
        local_branch.lock_read()
2435
2297
            try:
2436
2298
                local_extra, remote_extra = find_unmerged(local_branch, remote_branch)
2437
2299
                if (log_format == None):
2438
 
                    default = local_branch.get_config().log_format()
2439
 
                    log_format = get_log_format(long=long, short=short, 
2440
 
                                                line=line, default=default)
2441
 
                lf = log_formatter(log_format,
2442
 
                                   to_file=self.outf,
 
2300
                    default = bzrlib.config.BranchConfig(local_branch).log_format()
 
2301
                    log_format = get_log_format(long=long, short=short, line=line, default=default)
 
2302
                lf = log_formatter(log_format, sys.stdout,
2443
2303
                                   show_ids=show_ids,
2444
2304
                                   show_timezone='original')
2445
2305
                if reverse is False:
2474
2334
            try:
2475
2335
                # handle race conditions - a parent might be set while we run.
2476
2336
                if local_branch.get_parent() is None:
2477
 
                    local_branch.set_parent(remote_branch.base)
 
2337
                    local_branch.set_parent(other_branch)
2478
2338
            finally:
2479
2339
                local_branch.unlock()
2480
2340
        return status_code
2502
2362
 
2503
2363
class cmd_testament(Command):
2504
2364
    """Show testament (signing-form) of a revision."""
2505
 
    takes_options = ['revision', 'long', 
2506
 
                     Option('strict', help='Produce a strict-format'
2507
 
                            ' testament')]
 
2365
    takes_options = ['revision', 'long']
2508
2366
    takes_args = ['branch?']
2509
2367
    @display_command
2510
 
    def run(self, branch=u'.', revision=None, long=False, strict=False):
2511
 
        from bzrlib.testament import Testament, StrictTestament
2512
 
        if strict is True:
2513
 
            testament_class = StrictTestament
2514
 
        else:
2515
 
            testament_class = Testament
 
2368
    def run(self, branch=u'.', revision=None, long=False):
 
2369
        from bzrlib.testament import Testament
2516
2370
        b = WorkingTree.open_containing(branch)[0].branch
2517
2371
        b.lock_read()
2518
2372
        try:
2520
2374
                rev_id = b.last_revision()
2521
2375
            else:
2522
2376
                rev_id = revision[0].in_history(b).rev_id
2523
 
            t = testament_class.from_revision(b.repository, rev_id)
 
2377
            t = Testament.from_revision(b.repository, rev_id)
2524
2378
            if long:
2525
2379
                sys.stdout.writelines(t.as_text_lines())
2526
2380
            else:
2541
2395
    # TODO: annotate directories; showing when each file was last changed
2542
2396
    # TODO: if the working copy is modified, show annotations on that 
2543
2397
    #       with new uncommitted lines marked
2544
 
    aliases = ['ann', 'blame', 'praise']
 
2398
    aliases = ['blame', 'praise']
2545
2399
    takes_args = ['filename']
2546
2400
    takes_options = [Option('all', help='show annotations on all lines'),
2547
2401
                     Option('long', help='show date in annotations'),
2578
2432
    takes_options = ['revision']
2579
2433
    
2580
2434
    def run(self, revision_id_list=None, revision=None):
 
2435
        import bzrlib.config as config
2581
2436
        import bzrlib.gpg as gpg
2582
2437
        if revision_id_list is not None and revision is not None:
2583
2438
            raise BzrCommandError('You can only supply one of revision_id or --revision')
2584
2439
        if revision_id_list is None and revision is None:
2585
2440
            raise BzrCommandError('You must supply either --revision or a revision_id')
2586
2441
        b = WorkingTree.open_containing(u'.')[0].branch
2587
 
        gpg_strategy = gpg.GPGStrategy(b.get_config())
 
2442
        gpg_strategy = gpg.GPGStrategy(config.BranchConfig(b))
2588
2443
        if revision_id_list is not None:
2589
2444
            for revision_id in revision_id_list:
2590
2445
                b.repository.sign_revision(revision_id, gpg_strategy)
2645
2500
            raise BzrCommandError('Local branch is not bound')
2646
2501
 
2647
2502
 
2648
 
class cmd_uncommit(Command):
 
2503
class cmd_uncommit(bzrlib.commands.Command):
2649
2504
    """Remove the last committed revision.
2650
2505
 
2651
2506
    --verbose will print out what is being removed.
2657
2512
    """
2658
2513
 
2659
2514
    # TODO: jam 20060108 Add an option to allow uncommit to remove
2660
 
    # unreferenced information in 'branch-as-repository' branches.
 
2515
    # unreferenced information in 'branch-as-repostory' branches.
2661
2516
    # TODO: jam 20060108 Add the ability for uncommit to remove unreferenced
2662
2517
    # information in shared branches as well.
2663
2518
    takes_options = ['verbose', 'revision',
2666
2521
    takes_args = ['location?']
2667
2522
    aliases = []
2668
2523
 
2669
 
    def run(self, location=None,
 
2524
    def run(self, location=None, 
2670
2525
            dry_run=False, verbose=False,
2671
2526
            revision=None, force=False):
2672
 
        from bzrlib.log import log_formatter, show_log
 
2527
        from bzrlib.branch import Branch
 
2528
        from bzrlib.log import log_formatter
2673
2529
        import sys
2674
2530
        from bzrlib.uncommit import uncommit
2675
2531
 
2683
2539
            tree = None
2684
2540
            b = control.open_branch()
2685
2541
 
2686
 
        rev_id = None
2687
2542
        if revision is None:
2688
2543
            revno = b.revno()
 
2544
            rev_id = b.last_revision()
2689
2545
        else:
2690
 
            # 'bzr uncommit -r 10' actually means uncommit
2691
 
            # so that the final tree is at revno 10.
2692
 
            # but bzrlib.uncommit.uncommit() actually uncommits
2693
 
            # the revisions that are supplied.
2694
 
            # So we need to offset it by one
2695
 
            revno = revision[0].in_history(b).revno+1
2696
 
 
2697
 
        if revno <= b.revno():
2698
 
            rev_id = b.get_rev_id(revno)
 
2546
            revno, rev_id = revision[0].in_history(b)
2699
2547
        if rev_id is None:
2700
 
            self.outf.write('No revisions to uncommit.\n')
2701
 
            return 1
2702
 
 
2703
 
        lf = log_formatter('short',
2704
 
                           to_file=self.outf,
2705
 
                           show_timezone='original')
2706
 
 
2707
 
        show_log(b,
2708
 
                 lf,
2709
 
                 verbose=False,
2710
 
                 direction='forward',
2711
 
                 start_revision=revno,
2712
 
                 end_revision=b.revno())
 
2548
            print 'No revisions to uncommit.'
 
2549
 
 
2550
        for r in range(revno, b.revno()+1):
 
2551
            rev_id = b.get_rev_id(r)
 
2552
            lf = log_formatter('short', to_file=sys.stdout,show_timezone='original')
 
2553
            lf.show(r, b.repository.get_revision(rev_id), None)
2713
2554
 
2714
2555
        if dry_run:
2715
2556
            print 'Dry-run, pretending to remove the above revisions.'