/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
329 by Martin Pool
- refactor command functions into command classes
1
# Copyright (C) 2004, 2005 by Canonical Ltd
1 by mbp at sourcefrog
import from baz patch-364
2
3
# This program is free software; you can redistribute it and/or modify
4
# it under the terms of the GNU General Public License as published by
5
# the Free Software Foundation; either version 2 of the License, or
6
# (at your option) any later version.
7
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
# GNU General Public License for more details.
12
13
# You should have received a copy of the GNU General Public License
14
# along with this program; if not, write to the Free Software
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16
17
"""Bazaar-NG -- a free distributed version-control tool
273 by Martin Pool
- New 'bzr help commands'
18
http://bazaar-ng.org/
1 by mbp at sourcefrog
import from baz patch-364
19
20
**WARNING: THIS IS AN UNSTABLE DEVELOPMENT VERSION**
21
22
* Metadata format is not stable yet -- you may need to
23
  discard history in the future.
24
25
* Many commands unimplemented or partially implemented.
26
27
* Space-inefficient storage.
28
29
* No merge operators yet.
30
273 by Martin Pool
- New 'bzr help commands'
31
Interesting commands:
1 by mbp at sourcefrog
import from baz patch-364
32
85 by mbp at sourcefrog
improved help string
33
  bzr help [COMMAND]
273 by Martin Pool
- New 'bzr help commands'
34
      Show help screen
1 by mbp at sourcefrog
import from baz patch-364
35
  bzr version
273 by Martin Pool
- New 'bzr help commands'
36
      Show software version/licence/non-warranty.
1 by mbp at sourcefrog
import from baz patch-364
37
  bzr init
273 by Martin Pool
- New 'bzr help commands'
38
      Start versioning the current directory
1 by mbp at sourcefrog
import from baz patch-364
39
  bzr add FILE...
273 by Martin Pool
- New 'bzr help commands'
40
      Make files versioned.
1 by mbp at sourcefrog
import from baz patch-364
41
  bzr log
273 by Martin Pool
- New 'bzr help commands'
42
      Show revision history.
281 by Martin Pool
- List rename and move in help
43
  bzr rename FROM TO
44
      Rename one file.
45
  bzr move FROM... DESTDIR
46
      Move one or more files to a different directory.
196 by mbp at sourcefrog
selected-file diff
47
  bzr diff [FILE...]
273 by Martin Pool
- New 'bzr help commands'
48
      Show changes from last revision to working copy.
1 by mbp at sourcefrog
import from baz patch-364
49
  bzr commit -m 'MESSAGE'
273 by Martin Pool
- New 'bzr help commands'
50
      Store current state as new revision.
329 by Martin Pool
- refactor command functions into command classes
51
  bzr export [-r REVNO] DESTINATION
273 by Martin Pool
- New 'bzr help commands'
52
      Export the branch state at a previous version.
1 by mbp at sourcefrog
import from baz patch-364
53
  bzr status
273 by Martin Pool
- New 'bzr help commands'
54
      Show summary of pending changes.
1 by mbp at sourcefrog
import from baz patch-364
55
  bzr remove FILE...
273 by Martin Pool
- New 'bzr help commands'
56
      Make a file not versioned.
76 by mbp at sourcefrog
mention "info" in top-level help
57
  bzr info
273 by Martin Pool
- New 'bzr help commands'
58
      Show statistics about this branch.
59
  bzr check
60
      Verify history is stored safely. 
61
  (for more type 'bzr help commands')
1 by mbp at sourcefrog
import from baz patch-364
62
"""
63
64
65
66
338 by Martin Pool
- cleanup of some imports
67
import sys, os, time, os.path
1 by mbp at sourcefrog
import from baz patch-364
68
from sets import Set
69
70
import bzrlib
71
from bzrlib.trace import mutter, note, log_error
329 by Martin Pool
- refactor command functions into command classes
72
from bzrlib.errors import bailout, BzrError, BzrCheckError, BzrCommandError
1 by mbp at sourcefrog
import from baz patch-364
73
from bzrlib.osutils import quotefn, pumpfile, isdir, isfile
74
from bzrlib.tree import RevisionTree, EmptyTree, WorkingTree, Tree
75
from bzrlib.revision import Revision
76
from bzrlib import Branch, Inventory, InventoryEntry, ScratchBranch, BZRDIR, \
77
     format_date
78
79
350 by Martin Pool
- refactor command aliases into command classes
80
def _squish_command_name(cmd):
81
    return 'cmd_' + cmd.replace('-', '_')
82
83
84
def _unsquish_command_name(cmd):
85
    assert cmd.startswith("cmd_")
86
    return cmd[4:].replace('_','-')
87
88
def _get_all_cmds():
89
    """Return canonical name and class for all registered commands."""
90
    for k, v in globals().iteritems():
91
        if k.startswith("cmd_"):
92
            yield _unsquish_command_name(k), v
93
94
def _get_cmd_class(cmd):
95
    """Return the canonical name and command class for a command.
96
    """
97
    cmd = str(cmd)                      # not unicode
98
99
    # first look up this command under the specified name
272 by Martin Pool
- Add command aliases
100
    try:
350 by Martin Pool
- refactor command aliases into command classes
101
        return cmd, globals()[_squish_command_name(cmd)]
272 by Martin Pool
- Add command aliases
102
    except KeyError:
350 by Martin Pool
- refactor command aliases into command classes
103
        pass
104
105
    # look for any command which claims this as an alias
106
    for cmdname, cmdclass in _get_all_cmds():
107
        if cmd in cmdclass.aliases:
108
            return cmdname, cmdclass
109
    else:
349 by Martin Pool
Better error for incorrect commands
110
        raise BzrCommandError("unknown command %r" % cmd)
272 by Martin Pool
- Add command aliases
111
329 by Martin Pool
- refactor command functions into command classes
112
113
class Command:
114
    """Base class for commands.
115
116
    The docstring for an actual command should give a single-line
117
    summary, then a complete description of the command.  A grammar
118
    description will be inserted.
119
120
    takes_args
121
        List of argument forms, marked with whether they are optional,
122
        repeated, etc.
123
124
    takes_options
125
        List of options that may be given for this command.
126
127
    hidden
128
        If true, this command isn't advertised.
129
    """
130
    aliases = []
131
    
132
    takes_args = []
133
    takes_options = []
134
135
    hidden = False
136
    
137
    def __init__(self, options, arguments):
138
        """Construct and run the command.
139
140
        Sets self.status to the return value of run()."""
141
        assert isinstance(options, dict)
142
        assert isinstance(arguments, dict)
143
        cmdargs = options.copy()
144
        cmdargs.update(arguments)
145
        assert self.__doc__ != Command.__doc__, \
146
               ("No help message set for %r" % self)
147
        self.status = self.run(**cmdargs)
148
149
    
150
    def run(self):
151
        """Override this in sub-classes.
152
153
        This is invoked with the options and arguments bound to
154
        keyword parameters.
155
337 by Martin Pool
- Clarify return codes from command objects
156
        Return 0 or None if the command was successful, or a shell
157
        error code if not.
329 by Martin Pool
- refactor command functions into command classes
158
        """
337 by Martin Pool
- Clarify return codes from command objects
159
        return 0
329 by Martin Pool
- refactor command functions into command classes
160
161
162
163
class cmd_status(Command):
1 by mbp at sourcefrog
import from baz patch-364
164
    """Display status summary.
165
166
    For each file there is a single line giving its file state and name.
167
    The name is that in the current revision unless it is deleted or
168
    missing, in which case the old name is shown.
169
    """
329 by Martin Pool
- refactor command functions into command classes
170
    takes_options = ['all']
350 by Martin Pool
- refactor command aliases into command classes
171
    aliases = ['st', 'stat']
329 by Martin Pool
- refactor command functions into command classes
172
    
173
    def run(self, all=False):
174
        #import bzrlib.status
175
        #bzrlib.status.tree_status(Branch('.'))
176
        Branch('.').show_status(show_all=all)
177
178
179
class cmd_cat_revision(Command):
180
    """Write out metadata for a revision."""
181
182
    hidden = True
183
    takes_args = ['revision_id']
184
    
185
    def run(self, revision_id):
186
        Branch('.').get_revision(revision_id).write_xml(sys.stdout)
187
188
189
class cmd_revno(Command):
190
    """Show current revision number.
191
192
    This is equal to the number of revisions on this branch."""
193
    def run(self):
194
        print Branch('.').revno()
195
196
    
197
class cmd_add(Command):
70 by mbp at sourcefrog
Prepare for smart recursive add.
198
    """Add specified files or directories.
199
200
    In non-recursive mode, all the named items are added, regardless
201
    of whether they were previously ignored.  A warning is given if
202
    any of the named files are already versioned.
203
204
    In recursive mode (the default), files are treated the same way
205
    but the behaviour for directories is different.  Directories that
206
    are already versioned do not give a warning.  All directories,
207
    whether already versioned or not, are searched for files or
208
    subdirectories that are neither versioned or ignored, and these
209
    are added.  This search proceeds recursively into versioned
210
    directories.
211
212
    Therefore simply saying 'bzr add .' will version all files that
213
    are currently unknown.
279 by Martin Pool
todo
214
215
    TODO: Perhaps adding a file whose directly is not versioned should
216
    recursively add that parent, rather than giving an error?
70 by mbp at sourcefrog
Prepare for smart recursive add.
217
    """
329 by Martin Pool
- refactor command functions into command classes
218
    takes_args = ['file+']
219
    takes_options = ['verbose']
220
    
221
    def run(self, file_list, verbose=False):
222
        bzrlib.add.smart_add(file_list, verbose)
223
224
225
def Relpath(Command):
226
    """Show path of a file relative to root"""
227
    takes_args = ('filename')
228
    
229
    def run(self):
230
        print Branch(self.args['filename']).relpath(filename)
231
232
233
234
class cmd_inventory(Command):
235
    """Show inventory of the current working copy or a revision."""
236
    takes_options = ['revision']
237
    
238
    def run(self, revision=None):
239
        b = Branch('.')
240
        if revision == None:
241
            inv = b.read_working_inventory()
242
        else:
243
            inv = b.get_revision_inventory(b.lookup_revision(revision))
244
245
        for path, entry in inv.iter_entries():
246
            print '%-50s %s' % (entry.file_id, path)
247
248
249
class cmd_move(Command):
250
    """Move files to a different directory.
251
252
    examples:
253
        bzr move *.txt doc
254
255
    The destination must be a versioned directory in the same branch.
256
    """
257
    takes_args = ['source$', 'dest']
258
    def run(self, source_list, dest):
259
        b = Branch('.')
260
261
        b.move([b.relpath(s) for s in source_list], b.relpath(dest))
262
263
264
class cmd_rename(Command):
168 by mbp at sourcefrog
new "rename" command
265
    """Change the name of an entry.
266
232 by mbp at sourcefrog
Allow docstrings for help to be in PEP0257 format.
267
    examples:
268
      bzr rename frob.c frobber.c
269
      bzr rename src/frob.c lib/frob.c
270
271
    It is an error if the destination name exists.
272
273
    See also the 'move' command, which moves files into a different
274
    directory without changing their name.
275
276
    TODO: Some way to rename multiple files without invoking bzr for each
277
    one?"""
329 by Martin Pool
- refactor command functions into command classes
278
    takes_args = ['from_name', 'to_name']
168 by mbp at sourcefrog
new "rename" command
279
    
329 by Martin Pool
- refactor command functions into command classes
280
    def run(self, from_name, to_name):
281
        b = Branch('.')
282
        b.rename_one(b.relpath(from_name), b.relpath(to_name))
283
284
285
286
class cmd_renames(Command):
164 by mbp at sourcefrog
new 'renames' command
287
    """Show list of renamed files.
288
232 by mbp at sourcefrog
Allow docstrings for help to be in PEP0257 format.
289
    TODO: Option to show renames between two historical versions.
290
291
    TODO: Only show renames under dir, rather than in the whole branch.
292
    """
329 by Martin Pool
- refactor command functions into command classes
293
    takes_args = ['dir?']
294
295
    def run(self, dir='.'):
296
        b = Branch(dir)
297
        old_inv = b.basis_tree().inventory
298
        new_inv = b.read_working_inventory()
299
300
        renames = list(bzrlib.tree.find_renames(old_inv, new_inv))
301
        renames.sort()
302
        for old_name, new_name in renames:
303
            print "%s => %s" % (old_name, new_name)        
304
305
306
class cmd_info(Command):
307
    """Show statistical information for this branch"""
308
    def run(self):
309
        import info
310
        info.show_info(Branch('.'))        
311
312
313
class cmd_remove(Command):
314
    """Make a file unversioned.
315
316
    This makes bzr stop tracking changes to a versioned file.  It does
317
    not delete the working copy.
318
    """
319
    takes_args = ['file+']
320
    takes_options = ['verbose']
321
    
322
    def run(self, file_list, verbose=False):
323
        b = Branch(file_list[0])
324
        b.remove([b.relpath(f) for f in file_list], verbose=verbose)
325
326
327
class cmd_file_id(Command):
178 by mbp at sourcefrog
- Use a non-null file_id for the branch root directory. At the moment
328
    """Print file_id of a particular file or directory.
329
232 by mbp at sourcefrog
Allow docstrings for help to be in PEP0257 format.
330
    The file_id is assigned when the file is first added and remains the
331
    same through all revisions where the file exists, even when it is
332
    moved or renamed.
333
    """
329 by Martin Pool
- refactor command functions into command classes
334
    hidden = True
335
    takes_args = ['filename']
336
    def run(self, filename):
337
        b = Branch(filename)
338
        i = b.inventory.path2id(b.relpath(filename))
339
        if i == None:
340
            bailout("%r is not a versioned file" % filename)
341
        else:
342
            print i
343
344
345
class cmd_file_path(Command):
178 by mbp at sourcefrog
- Use a non-null file_id for the branch root directory. At the moment
346
    """Print path of file_ids to a file or directory.
347
232 by mbp at sourcefrog
Allow docstrings for help to be in PEP0257 format.
348
    This prints one line for each directory down to the target,
349
    starting at the branch root."""
329 by Martin Pool
- refactor command functions into command classes
350
    hidden = True
351
    takes_args = ['filename']
352
    def run(self, filename):
353
        b = Branch(filename)
354
        inv = b.inventory
355
        fid = inv.path2id(b.relpath(filename))
356
        if fid == None:
357
            bailout("%r is not a versioned file" % filename)
358
        for fip in inv.get_idpath(fid):
359
            print fip
360
361
362
class cmd_revision_history(Command):
363
    """Display list of revision ids on this branch."""
364
    def run(self):
365
        for patchid in Branch('.').revision_history():
366
            print patchid
367
368
369
class cmd_directories(Command):
370
    """Display list of versioned directories in this branch."""
371
    def run(self):
372
        for name, ie in Branch('.').read_working_inventory().directories():
373
            if name == '':
374
                print '.'
375
            else:
376
                print name
377
378
379
class cmd_init(Command):
380
    """Make a directory into a versioned branch.
381
382
    Use this to create an empty branch, or before importing an
383
    existing project.
384
385
    Recipe for importing a tree of files:
386
        cd ~/project
387
        bzr init
388
        bzr add -v .
389
        bzr status
390
        bzr commit -m 'imported project'
391
    """
392
    def run(self):
393
        Branch('.', init=True)
394
395
396
class cmd_diff(Command):
397
    """Show differences in working tree.
398
    
232 by mbp at sourcefrog
Allow docstrings for help to be in PEP0257 format.
399
    If files are listed, only the changes in those files are listed.
400
    Otherwise, all changes for the tree are listed.
401
402
    TODO: Given two revision arguments, show the difference between them.
403
404
    TODO: Allow diff across branches.
405
406
    TODO: Option to use external diff command; could be GNU diff, wdiff,
407
          or a graphical diff.
408
276 by Martin Pool
Doc
409
    TODO: Python difflib is not exactly the same as unidiff; should
410
          either fix it up or prefer to use an external diff.
411
232 by mbp at sourcefrog
Allow docstrings for help to be in PEP0257 format.
412
    TODO: If a directory is given, diff everything under that.
413
276 by Martin Pool
Doc
414
    TODO: Selected-file diff is inefficient and doesn't show you
415
          deleted files.
278 by Martin Pool
- Better workaround for trailing newlines in diffs
416
417
    TODO: This probably handles non-Unix newlines poorly.
329 by Martin Pool
- refactor command functions into command classes
418
    """
419
    
420
    takes_args = ['file*']
421
    takes_options = ['revision']
350 by Martin Pool
- refactor command aliases into command classes
422
    aliases = ['di']
329 by Martin Pool
- refactor command functions into command classes
423
424
    def run(self, revision=None, file_list=None):
425
        from bzrlib.diff import show_diff
426
    
427
        show_diff(Branch('.'), revision, file_list)
428
429
430
class cmd_deleted(Command):
135 by mbp at sourcefrog
Simple new 'deleted' command
431
    """List files deleted in the working tree.
432
232 by mbp at sourcefrog
Allow docstrings for help to be in PEP0257 format.
433
    TODO: Show files deleted since a previous revision, or between two revisions.
135 by mbp at sourcefrog
Simple new 'deleted' command
434
    """
329 by Martin Pool
- refactor command functions into command classes
435
    def run(self, show_ids=False):
436
        b = Branch('.')
437
        old = b.basis_tree()
438
        new = b.working_tree()
439
440
        ## TODO: Much more efficient way to do this: read in new
441
        ## directories with readdir, rather than stating each one.  Same
442
        ## level of effort but possibly much less IO.  (Or possibly not,
443
        ## if the directories are very large...)
444
445
        for path, ie in old.inventory.iter_entries():
446
            if not new.has_id(ie.file_id):
447
                if show_ids:
448
                    print '%-50s %s' % (path, ie.file_id)
449
                else:
450
                    print path
451
452
class cmd_root(Command):
453
    """Show the tree root directory.
454
455
    The root is the nearest enclosing directory with a .bzr control
456
    directory."""
457
    takes_args = ['filename?']
458
    def run(self, filename=None):
459
        """Print the branch root."""
460
        print bzrlib.branch.find_branch_root(filename)
461
462
463
464
class cmd_log(Command):
1 by mbp at sourcefrog
import from baz patch-364
465
    """Show log of this branch.
466
329 by Martin Pool
- refactor command functions into command classes
467
    TODO: Options to show ids; to limit range; etc.
1 by mbp at sourcefrog
import from baz patch-364
468
    """
329 by Martin Pool
- refactor command functions into command classes
469
    takes_options = ['timezone', 'verbose']
470
    def run(self, timezone='original', verbose=False):
471
        Branch('.').write_log(show_timezone=timezone, verbose=verbose)
472
473
474
class cmd_ls(Command):
1 by mbp at sourcefrog
import from baz patch-364
475
    """List files in a tree.
476
254 by Martin Pool
- Doc cleanups from Magnus Therning
477
    TODO: Take a revision or remote path and list that tree instead.
1 by mbp at sourcefrog
import from baz patch-364
478
    """
329 by Martin Pool
- refactor command functions into command classes
479
    hidden = True
480
    def run(self, revision=None, verbose=False):
481
        b = Branch('.')
482
        if revision == None:
483
            tree = b.working_tree()
484
        else:
485
            tree = b.revision_tree(b.lookup_revision(revision))
486
487
        for fp, fc, kind, fid in tree.list_files():
488
            if verbose:
489
                if kind == 'directory':
490
                    kindch = '/'
491
                elif kind == 'file':
492
                    kindch = ''
493
                else:
494
                    kindch = '???'
495
496
                print '%-8s %s%s' % (fc, fp, kindch)
1 by mbp at sourcefrog
import from baz patch-364
497
            else:
329 by Martin Pool
- refactor command functions into command classes
498
                print fp
499
500
501
502
class cmd_unknowns(Command):
1 by mbp at sourcefrog
import from baz patch-364
503
    """List unknown files"""
329 by Martin Pool
- refactor command functions into command classes
504
    def run(self):
505
        for f in Branch('.').unknowns():
506
            print quotefn(f)
507
508
509
510
class cmd_ignore(Command):
310 by Martin Pool
- new 'bzr ignored' command!
511
    """Ignore a command or pattern"""
329 by Martin Pool
- refactor command functions into command classes
512
    takes_args = ['name_pattern']
310 by Martin Pool
- new 'bzr ignored' command!
513
    
329 by Martin Pool
- refactor command functions into command classes
514
    def run(self, name_pattern):
515
        b = Branch('.')
516
517
        # XXX: This will fail if it's a hardlink; should use an AtomicFile class.
518
        f = open(b.abspath('.bzrignore'), 'at')
519
        f.write(name_pattern + '\n')
520
        f.close()
521
522
        inv = b.working_tree().inventory
523
        if inv.path2id('.bzrignore'):
524
            mutter('.bzrignore is already versioned')
525
        else:
526
            mutter('need to make new .bzrignore file versioned')
527
            b.add(['.bzrignore'])
528
529
530
531
class cmd_ignored(Command):
532
    """List ignored files and the patterns that matched them."""
533
    def run(self):
534
        tree = Branch('.').working_tree()
535
        for path, file_class, kind, file_id in tree.list_files():
536
            if file_class != 'I':
537
                continue
538
            ## XXX: Slightly inefficient since this was already calculated
539
            pat = tree.is_ignored(path)
540
            print '%-50s %s' % (path, pat)
541
542
543
class cmd_lookup_revision(Command):
544
    """Lookup the revision-id from a revision-number
545
546
    example:
547
        bzr lookup-revision 33
548
        """
549
    hidden = True
338 by Martin Pool
- cleanup of some imports
550
    takes_args = ['revno']
551
    
329 by Martin Pool
- refactor command functions into command classes
552
    def run(self, revno):
553
        try:
554
            revno = int(revno)
555
        except ValueError:
338 by Martin Pool
- cleanup of some imports
556
            raise BzrCommandError("not a valid revision-number: %r" % revno)
557
558
        print Branch('.').lookup_revision(revno)
329 by Martin Pool
- refactor command functions into command classes
559
560
561
class cmd_export(Command):
562
    """Export past revision to destination directory.
563
564
    If no revision is specified this exports the last committed revision."""
565
    takes_args = ['dest']
566
    takes_options = ['revision']
567
    def run(self, dest, revno=None):
568
        b = Branch('.')
569
        if revno == None:
570
            rh = b.revision_history[-1]
571
        else:
572
            rh = b.lookup_revision(int(revno))
573
        t = b.revision_tree(rh)
574
        t.export(dest)
575
576
577
class cmd_cat(Command):
578
    """Write a file's text from a previous revision."""
579
580
    takes_options = ['revision']
581
    takes_args = ['filename']
582
583
    def run(self, filename, revision=None):
584
        if revision == None:
585
            raise BzrCommandError("bzr cat requires a revision number")
586
        b = Branch('.')
587
        b.print_file(b.relpath(filename), int(revision))
588
589
590
class cmd_local_time_offset(Command):
591
    """Show the offset in seconds from GMT to local time."""
592
    hidden = True    
593
    def run(self):
594
        print bzrlib.osutils.local_time_offset()
595
596
597
598
class cmd_commit(Command):
599
    """Commit changes into a new revision.
232 by mbp at sourcefrog
Allow docstrings for help to be in PEP0257 format.
600
601
    TODO: Commit only selected files.
602
603
    TODO: Run hooks on tree to-be-committed, and after commit.
604
605
    TODO: Strict commit that fails if there are unknown or deleted files.
606
    """
329 by Martin Pool
- refactor command functions into command classes
607
    takes_options = ['message', 'verbose']
350 by Martin Pool
- refactor command aliases into command classes
608
    aliases = ['ci', 'checkin']
609
329 by Martin Pool
- refactor command functions into command classes
610
    def run(self, message=None, verbose=False):
611
        if not message:
612
            raise BzrCommandError("please specify a commit message")
613
        Branch('.').commit(message, verbose=verbose)
614
615
616
class cmd_check(Command):
617
    """Validate consistency of branch history.
232 by mbp at sourcefrog
Allow docstrings for help to be in PEP0257 format.
618
619
    This command checks various invariants about the branch storage to
620
    detect data corruption or bzr bugs.
621
    """
329 by Martin Pool
- refactor command functions into command classes
622
    takes_args = ['dir?']
623
    def run(self, dir='.'):
624
        import bzrlib.check
625
        bzrlib.check.check(Branch(dir, find_root=False))
626
627
628
629
class cmd_whoami(Command):
630
    """Show bzr user id."""
631
    takes_options = ['email']
286 by Martin Pool
- New bzr whoami --email option
632
    
329 by Martin Pool
- refactor command functions into command classes
633
    def run(self, email=False):
634
        if email:
635
            print bzrlib.osutils.user_email()
636
        else:
637
            print bzrlib.osutils.username()
638
639
640
class cmd_selftest(Command):
55 by mbp at sourcefrog
bzr selftest shows some counts of tests
641
    """Run internal test suite"""
329 by Martin Pool
- refactor command functions into command classes
642
    hidden = True
643
    def run(self):
644
        failures, tests = 0, 0
645
646
        import doctest, bzrlib.store, bzrlib.tests
647
        bzrlib.trace.verbose = False
648
649
        for m in bzrlib.store, bzrlib.inventory, bzrlib.branch, bzrlib.osutils, \
650
            bzrlib.tree, bzrlib.tests, bzrlib.commands, bzrlib.add:
651
            mf, mt = doctest.testmod(m)
652
            failures += mf
653
            tests += mt
654
            print '%-40s %3d tests' % (m.__name__, mt),
655
            if mf:
656
                print '%3d FAILED!' % mf
657
            else:
658
                print
659
660
        print '%-40s %3d tests' % ('total', tests),
661
        if failures:
662
            print '%3d FAILED!' % failures
55 by mbp at sourcefrog
bzr selftest shows some counts of tests
663
        else:
664
            print
665
329 by Martin Pool
- refactor command functions into command classes
666
667
668
class cmd_version(Command):
669
    """Show version of bzr"""
670
    def run(self):
671
        show_version()
672
673
def show_version():
674
    print "bzr (bazaar-ng) %s" % bzrlib.__version__
675
    print bzrlib.__copyright__
676
    print "http://bazaar-ng.org/"
677
    print
678
    print "bzr comes with ABSOLUTELY NO WARRANTY.  bzr is free software, and"
679
    print "you may use, modify and redistribute it under the terms of the GNU"
680
    print "General Public License version 2 or later."
681
682
683
class cmd_rocks(Command):
684
    """Statement of optimism."""
685
    hidden = True
686
    def run(self):
687
        print "it sure does!"
688
689
690
class cmd_assert_fail(Command):
691
    """Test reporting of assertion failures"""
692
    hidden = True
693
    def run(self):
694
        assert False, "always fails"
695
696
697
class cmd_help(Command):
698
    """Show help on a command or other topic.
699
700
    For a list of all available commands, say 'bzr help commands'."""
701
    takes_args = ['topic?']
350 by Martin Pool
- refactor command aliases into command classes
702
    aliases = ['?']
329 by Martin Pool
- refactor command functions into command classes
703
    
704
    def run(self, topic=None):
705
        help(topic)
706
707
708
def help(topic=None):
83 by mbp at sourcefrog
Can now say "bzr help COMMAND" for more detailed help
709
    if topic == None:
710
        print __doc__
273 by Martin Pool
- New 'bzr help commands'
711
    elif topic == 'commands':
712
        help_commands()
713
    else:
329 by Martin Pool
- refactor command functions into command classes
714
        help_on_command(topic)
715
716
717
def help_on_command(cmdname):
718
    cmdname = str(cmdname)
719
720
    from inspect import getdoc
350 by Martin Pool
- refactor command aliases into command classes
721
    topic, cmdclass = _get_cmd_class(cmdname)
329 by Martin Pool
- refactor command functions into command classes
722
723
    doc = getdoc(cmdclass)
724
    if doc == None:
725
        raise NotImplementedError("sorry, no detailed help yet for %r" % cmdname)
726
727
    if '\n' in doc:
728
        short, rest = doc.split('\n', 1)
729
    else:
730
        short = doc
731
        rest = ''
732
733
    print 'usage: bzr ' + topic,
734
    for aname in cmdclass.takes_args:
735
        aname = aname.upper()
736
        if aname[-1] in ['$', '+']:
737
            aname = aname[:-1] + '...'
738
        elif aname[-1] == '?':
739
            aname = '[' + aname[:-1] + ']'
740
        elif aname[-1] == '*':
741
            aname = '[' + aname[:-1] + '...]'
742
        print aname,
743
    print 
744
    print short
745
    if rest:
746
        print rest
747
332 by Martin Pool
- nicer formatting of help for options
748
    help_on_option(cmdclass.takes_options)
749
750
751
def help_on_option(options):
752
    if not options:
753
        return
754
    
755
    print
756
    print 'options:'
757
    for on in options:
758
        l = '    --' + on
759
        for shortname, longname in SHORT_OPTIONS.items():
760
            if longname == on:
761
                l += ', -' + shortname
762
                break
763
        print l
273 by Martin Pool
- New 'bzr help commands'
764
765
766
def help_commands():
767
    """List all commands"""
329 by Martin Pool
- refactor command functions into command classes
768
    import inspect
769
    
273 by Martin Pool
- New 'bzr help commands'
770
    accu = []
350 by Martin Pool
- refactor command aliases into command classes
771
    for cmdname, cmdclass in _get_all_cmds():
772
        accu.append((cmdname, cmdclass))
273 by Martin Pool
- New 'bzr help commands'
773
    accu.sort()
329 by Martin Pool
- refactor command functions into command classes
774
    for cmdname, cmdclass in accu:
775
        if cmdclass.hidden:
776
            continue
777
        print cmdname
778
        help = inspect.getdoc(cmdclass)
779
        if help:
780
            print "    " + help.split('\n', 1)[0]
332 by Martin Pool
- nicer formatting of help for options
781
            
1 by mbp at sourcefrog
import from baz patch-364
782
783
######################################################################
784
# main routine
785
786
787
# list of all available options; the rhs can be either None for an
788
# option that takes no argument, or a constructor function that checks
789
# the type.
790
OPTIONS = {
791
    'all':                    None,
792
    'help':                   None,
793
    'message':                unicode,
137 by mbp at sourcefrog
new --profile option
794
    'profile':                None,
1 by mbp at sourcefrog
import from baz patch-364
795
    'revision':               int,
796
    'show-ids':               None,
12 by mbp at sourcefrog
new --timezone option for bzr log
797
    'timezone':               str,
1 by mbp at sourcefrog
import from baz patch-364
798
    'verbose':                None,
799
    'version':                None,
286 by Martin Pool
- New bzr whoami --email option
800
    'email':                  None,
1 by mbp at sourcefrog
import from baz patch-364
801
    }
802
803
SHORT_OPTIONS = {
804
    'm':                      'message',
805
    'r':                      'revision',
806
    'v':                      'verbose',
807
}
808
809
810
def parse_args(argv):
811
    """Parse command line.
812
    
813
    Arguments and options are parsed at this level before being passed
814
    down to specific command handlers.  This routine knows, from a
815
    lookup table, something about the available options, what optargs
816
    they take, and which commands will accept them.
817
31 by Martin Pool
fix up parse_args doctest
818
    >>> parse_args('--help'.split())
1 by mbp at sourcefrog
import from baz patch-364
819
    ([], {'help': True})
31 by Martin Pool
fix up parse_args doctest
820
    >>> parse_args('--version'.split())
1 by mbp at sourcefrog
import from baz patch-364
821
    ([], {'version': True})
31 by Martin Pool
fix up parse_args doctest
822
    >>> parse_args('status --all'.split())
1 by mbp at sourcefrog
import from baz patch-364
823
    (['status'], {'all': True})
31 by Martin Pool
fix up parse_args doctest
824
    >>> parse_args('commit --message=biter'.split())
17 by mbp at sourcefrog
allow --option=ARG syntax
825
    (['commit'], {'message': u'biter'})
1 by mbp at sourcefrog
import from baz patch-364
826
    """
827
    args = []
828
    opts = {}
829
830
    # TODO: Maybe handle '--' to end options?
831
26 by mbp at sourcefrog
fix StopIteration error on python2.3(?)
832
    while argv:
833
        a = argv.pop(0)
1 by mbp at sourcefrog
import from baz patch-364
834
        if a[0] == '-':
264 by Martin Pool
parse_args: option names must be ascii
835
            # option names must not be unicode
836
            a = str(a)
17 by mbp at sourcefrog
allow --option=ARG syntax
837
            optarg = None
1 by mbp at sourcefrog
import from baz patch-364
838
            if a[1] == '-':
839
                mutter("  got option %r" % a)
17 by mbp at sourcefrog
allow --option=ARG syntax
840
                if '=' in a:
841
                    optname, optarg = a[2:].split('=', 1)
842
                else:
843
                    optname = a[2:]
1 by mbp at sourcefrog
import from baz patch-364
844
                if optname not in OPTIONS:
845
                    bailout('unknown long option %r' % a)
846
            else:
847
                shortopt = a[1:]
848
                if shortopt not in SHORT_OPTIONS:
849
                    bailout('unknown short option %r' % a)
850
                optname = SHORT_OPTIONS[shortopt]
851
            
852
            if optname in opts:
853
                # XXX: Do we ever want to support this, e.g. for -r?
854
                bailout('repeated option %r' % a)
17 by mbp at sourcefrog
allow --option=ARG syntax
855
                
1 by mbp at sourcefrog
import from baz patch-364
856
            optargfn = OPTIONS[optname]
857
            if optargfn:
17 by mbp at sourcefrog
allow --option=ARG syntax
858
                if optarg == None:
26 by mbp at sourcefrog
fix StopIteration error on python2.3(?)
859
                    if not argv:
17 by mbp at sourcefrog
allow --option=ARG syntax
860
                        bailout('option %r needs an argument' % a)
861
                    else:
26 by mbp at sourcefrog
fix StopIteration error on python2.3(?)
862
                        optarg = argv.pop(0)
17 by mbp at sourcefrog
allow --option=ARG syntax
863
                opts[optname] = optargfn(optarg)
1 by mbp at sourcefrog
import from baz patch-364
864
            else:
17 by mbp at sourcefrog
allow --option=ARG syntax
865
                if optarg != None:
866
                    bailout('option %r takes no argument' % optname)
1 by mbp at sourcefrog
import from baz patch-364
867
                opts[optname] = True
868
        else:
869
            args.append(a)
870
871
    return args, opts
872
873
874
875
329 by Martin Pool
- refactor command functions into command classes
876
def _match_argform(cmd, takes_args, args):
1 by mbp at sourcefrog
import from baz patch-364
877
    argdict = {}
26 by mbp at sourcefrog
fix StopIteration error on python2.3(?)
878
329 by Martin Pool
- refactor command functions into command classes
879
    # step through args and takes_args, allowing appropriate 0-many matches
880
    for ap in takes_args:
1 by mbp at sourcefrog
import from baz patch-364
881
        argname = ap[:-1]
882
        if ap[-1] == '?':
62 by mbp at sourcefrog
- new find_branch_root function; based on suggestion from aaron
883
            if args:
884
                argdict[argname] = args.pop(0)
196 by mbp at sourcefrog
selected-file diff
885
        elif ap[-1] == '*': # all remaining arguments
886
            if args:
887
                argdict[argname + '_list'] = args[:]
888
                args = []
889
            else:
890
                argdict[argname + '_list'] = None
1 by mbp at sourcefrog
import from baz patch-364
891
        elif ap[-1] == '+':
892
            if not args:
329 by Martin Pool
- refactor command functions into command classes
893
                raise BzrCommandError("command %r needs one or more %s"
1 by mbp at sourcefrog
import from baz patch-364
894
                        % (cmd, argname.upper()))
895
            else:
896
                argdict[argname + '_list'] = args[:]
897
                args = []
160 by mbp at sourcefrog
- basic support for moving files to different directories - have not done support for renaming them yet, but should be straightforward - some tests, but many cases are not handled yet i think
898
        elif ap[-1] == '$': # all but one
899
            if len(args) < 2:
329 by Martin Pool
- refactor command functions into command classes
900
                raise BzrCommandError("command %r needs one or more %s"
160 by mbp at sourcefrog
- basic support for moving files to different directories - have not done support for renaming them yet, but should be straightforward - some tests, but many cases are not handled yet i think
901
                        % (cmd, argname.upper()))
902
            argdict[argname + '_list'] = args[:-1]
903
            args[:-1] = []                
1 by mbp at sourcefrog
import from baz patch-364
904
        else:
905
            # just a plain arg
906
            argname = ap
907
            if not args:
329 by Martin Pool
- refactor command functions into command classes
908
                raise BzrCommandError("command %r requires argument %s"
1 by mbp at sourcefrog
import from baz patch-364
909
                        % (cmd, argname.upper()))
910
            else:
911
                argdict[argname] = args.pop(0)
912
            
913
    if args:
329 by Martin Pool
- refactor command functions into command classes
914
        raise BzrCommandError("extra argument to command %s: %s"
915
                              % (cmd, args[0]))
1 by mbp at sourcefrog
import from baz patch-364
916
917
    return argdict
918
919
920
921
def run_bzr(argv):
922
    """Execute a command.
923
924
    This is similar to main(), but without all the trappings for
245 by mbp at sourcefrog
- control files always in utf-8-unix format
925
    logging and error handling.  
1 by mbp at sourcefrog
import from baz patch-364
926
    """
245 by mbp at sourcefrog
- control files always in utf-8-unix format
927
251 by mbp at sourcefrog
- factor out locale.getpreferredencoding()
928
    argv = [a.decode(bzrlib.user_encoding) for a in argv]
245 by mbp at sourcefrog
- control files always in utf-8-unix format
929
    
1 by mbp at sourcefrog
import from baz patch-364
930
    try:
26 by mbp at sourcefrog
fix StopIteration error on python2.3(?)
931
        args, opts = parse_args(argv[1:])
1 by mbp at sourcefrog
import from baz patch-364
932
        if 'help' in opts:
159 by mbp at sourcefrog
bzr commit --help now works
933
            if args:
329 by Martin Pool
- refactor command functions into command classes
934
                help(args[0])
159 by mbp at sourcefrog
bzr commit --help now works
935
            else:
329 by Martin Pool
- refactor command functions into command classes
936
                help()
1 by mbp at sourcefrog
import from baz patch-364
937
            return 0
938
        elif 'version' in opts:
336 by Martin Pool
- fix up 'bzr --version'
939
            show_version()
1 by mbp at sourcefrog
import from baz patch-364
940
            return 0
265 by Martin Pool
parse_args: command names must also be ascii
941
        cmd = str(args.pop(0))
1 by mbp at sourcefrog
import from baz patch-364
942
    except IndexError:
257 by Martin Pool
- Write less startup junk to .bzr.log
943
        log_error('usage: bzr COMMAND')
944
        log_error('  try "bzr help"')
1 by mbp at sourcefrog
import from baz patch-364
945
        return 1
115 by mbp at sourcefrog
todo
946
350 by Martin Pool
- refactor command aliases into command classes
947
    canonical_cmd, cmd_class = _get_cmd_class(cmd)
1 by mbp at sourcefrog
import from baz patch-364
948
137 by mbp at sourcefrog
new --profile option
949
    # global option
950
    if 'profile' in opts:
951
        profile = True
952
        del opts['profile']
953
    else:
954
        profile = False
1 by mbp at sourcefrog
import from baz patch-364
955
956
    # check options are reasonable
329 by Martin Pool
- refactor command functions into command classes
957
    allowed = cmd_class.takes_options
1 by mbp at sourcefrog
import from baz patch-364
958
    for oname in opts:
959
        if oname not in allowed:
329 by Martin Pool
- refactor command functions into command classes
960
            raise BzrCommandError("option %r is not allowed for command %r"
961
                                  % (oname, cmd))
176 by mbp at sourcefrog
New cat command contributed by janmar.
962
137 by mbp at sourcefrog
new --profile option
963
    # mix arguments and options into one dictionary
329 by Martin Pool
- refactor command functions into command classes
964
    cmdargs = _match_argform(cmd, cmd_class.takes_args, args)
965
    cmdopts = {}
136 by mbp at sourcefrog
new --show-ids option for 'deleted' command
966
    for k, v in opts.items():
329 by Martin Pool
- refactor command functions into command classes
967
        cmdopts[k.replace('-', '_')] = v
1 by mbp at sourcefrog
import from baz patch-364
968
137 by mbp at sourcefrog
new --profile option
969
    if profile:
338 by Martin Pool
- cleanup of some imports
970
        import hotshot, tempfile
239 by mbp at sourcefrog
- remove profiler temporary file when done
971
        pffileno, pfname = tempfile.mkstemp()
972
        try:
973
            prof = hotshot.Profile(pfname)
329 by Martin Pool
- refactor command functions into command classes
974
            ret = prof.runcall(cmd_class, cmdopts, cmdargs) or 0
239 by mbp at sourcefrog
- remove profiler temporary file when done
975
            prof.close()
976
977
            import hotshot.stats
978
            stats = hotshot.stats.load(pfname)
979
            #stats.strip_dirs()
980
            stats.sort_stats('time')
981
            ## XXX: Might like to write to stderr or the trace file instead but
982
            ## print_stats seems hardcoded to stdout
983
            stats.print_stats(20)
984
            
337 by Martin Pool
- Clarify return codes from command objects
985
            return ret.status
239 by mbp at sourcefrog
- remove profiler temporary file when done
986
987
        finally:
988
            os.close(pffileno)
989
            os.remove(pfname)
137 by mbp at sourcefrog
new --profile option
990
    else:
337 by Martin Pool
- Clarify return codes from command objects
991
        cmdobj = cmd_class(cmdopts, cmdargs).status 
1 by mbp at sourcefrog
import from baz patch-364
992
993
317 by Martin Pool
- better error message for broken pipe
994
def _report_exception(e, summary, quiet=False):
267 by Martin Pool
- better reporting of errors
995
    import traceback
996
    log_error('bzr: ' + summary)
997
    bzrlib.trace.log_exception(e)
317 by Martin Pool
- better error message for broken pipe
998
999
    if not quiet:
1000
        tb = sys.exc_info()[2]
1001
        exinfo = traceback.extract_tb(tb)
1002
        if exinfo:
1003
            sys.stderr.write('  at %s:%d in %s()\n' % exinfo[-1][:3])
1004
        sys.stderr.write('  see ~/.bzr.log for debug information\n')
267 by Martin Pool
- better reporting of errors
1005
1006
1007
1 by mbp at sourcefrog
import from baz patch-364
1008
def main(argv):
317 by Martin Pool
- better error message for broken pipe
1009
    import errno
1010
    
344 by Martin Pool
- It's not an error to use the library without
1011
    bzrlib.open_tracefile(argv)
260 by Martin Pool
- remove atexit() dependency for writing out execution times
1012
1 by mbp at sourcefrog
import from baz patch-364
1013
    try:
260 by Martin Pool
- remove atexit() dependency for writing out execution times
1014
        try:
337 by Martin Pool
- Clarify return codes from command objects
1015
            try:
1016
                return run_bzr(argv)
1017
            finally:
1018
                # do this here inside the exception wrappers to catch EPIPE
1019
                sys.stdout.flush()
260 by Martin Pool
- remove atexit() dependency for writing out execution times
1020
        except BzrError, e:
329 by Martin Pool
- refactor command functions into command classes
1021
            quiet = isinstance(e, (BzrCommandError))
1022
            _report_exception(e, 'error: ' + e.args[0], quiet=quiet)
260 by Martin Pool
- remove atexit() dependency for writing out execution times
1023
            if len(e.args) > 1:
1024
                for h in e.args[1]:
267 by Martin Pool
- better reporting of errors
1025
                    # some explanation or hints
260 by Martin Pool
- remove atexit() dependency for writing out execution times
1026
                    log_error('  ' + h)
1027
            return 1
267 by Martin Pool
- better reporting of errors
1028
        except AssertionError, e:
1029
            msg = 'assertion failed'
1030
            if str(e):
1031
                msg += ': ' + str(e)
1032
            _report_exception(e, msg)
318 by Martin Pool
- better error message for Ctrl-c
1033
            return 2
1034
        except KeyboardInterrupt, e:
1035
            _report_exception(e, 'interrupted', quiet=True)
1036
            return 2
260 by Martin Pool
- remove atexit() dependency for writing out execution times
1037
        except Exception, e:
317 by Martin Pool
- better error message for broken pipe
1038
            quiet = False
1039
            if isinstance(e, IOError) and e.errno == errno.EPIPE:
1040
                quiet = True
1041
                msg = 'broken pipe'
1042
            else:
1043
                msg = str(e).rstrip('\n')
1044
            _report_exception(e, msg, quiet)
318 by Martin Pool
- better error message for Ctrl-c
1045
            return 2
260 by Martin Pool
- remove atexit() dependency for writing out execution times
1046
    finally:
1047
        bzrlib.trace.close_trace()
1 by mbp at sourcefrog
import from baz patch-364
1048
1049
1050
if __name__ == '__main__':
1051
    sys.exit(main(sys.argv))