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 | ||
| 18 | ||
| 338
by Martin Pool - cleanup of some imports | 19 | import sys, os, time, os.path | 
| 1
by mbp at sourcefrog import from baz patch-364 | 20 | from sets import Set | 
| 21 | ||
| 22 | import bzrlib | |
| 23 | from bzrlib.trace import mutter, note, log_error | |
| 329
by Martin Pool - refactor command functions into command classes | 24 | from bzrlib.errors import bailout, BzrError, BzrCheckError, BzrCommandError | 
| 1
by mbp at sourcefrog import from baz patch-364 | 25 | from bzrlib.osutils import quotefn, pumpfile, isdir, isfile | 
| 453
by Martin Pool - Split WorkingTree into its own file | 26 | from bzrlib.tree import RevisionTree, EmptyTree, Tree | 
| 1
by mbp at sourcefrog import from baz patch-364 | 27 | from bzrlib.revision import Revision | 
| 28 | from bzrlib import Branch, Inventory, InventoryEntry, ScratchBranch, BZRDIR, \ | |
| 29 |      format_date
 | |
| 493
by Martin Pool - Merge aaron's merge command | 30 | from bzrlib import merge | 
| 1
by mbp at sourcefrog import from baz patch-364 | 31 | |
| 32 | ||
| 350
by Martin Pool - refactor command aliases into command classes | 33 | def _squish_command_name(cmd): | 
| 34 | return 'cmd_' + cmd.replace('-', '_') | |
| 35 | ||
| 36 | ||
| 37 | def _unsquish_command_name(cmd): | |
| 38 | assert cmd.startswith("cmd_") | |
| 39 | return cmd[4:].replace('_','-') | |
| 40 | ||
| 351
by Martin Pool - Split out help functions into bzrlib.help | 41 | def get_all_cmds(): | 
| 350
by Martin Pool - refactor command aliases into command classes | 42 | """Return canonical name and class for all registered commands.""" | 
| 43 | for k, v in globals().iteritems(): | |
| 44 | if k.startswith("cmd_"): | |
| 45 | yield _unsquish_command_name(k), v | |
| 46 | ||
| 351
by Martin Pool - Split out help functions into bzrlib.help | 47 | def get_cmd_class(cmd): | 
| 350
by Martin Pool - refactor command aliases into command classes | 48 | """Return the canonical name and command class for a command. | 
| 49 |     """
 | |
| 50 | cmd = str(cmd) # not unicode | |
| 51 | ||
| 52 |     # first look up this command under the specified name
 | |
| 272
by Martin Pool - Add command aliases | 53 | try: | 
| 350
by Martin Pool - refactor command aliases into command classes | 54 | return cmd, globals()[_squish_command_name(cmd)] | 
| 272
by Martin Pool - Add command aliases | 55 | except KeyError: | 
| 350
by Martin Pool - refactor command aliases into command classes | 56 |         pass
 | 
| 57 | ||
| 58 |     # look for any command which claims this as an alias
 | |
| 351
by Martin Pool - Split out help functions into bzrlib.help | 59 | for cmdname, cmdclass in get_all_cmds(): | 
| 350
by Martin Pool - refactor command aliases into command classes | 60 | if cmd in cmdclass.aliases: | 
| 61 | return cmdname, cmdclass | |
| 422
by Martin Pool - External-command patch from mpe | 62 | |
| 63 | cmdclass = ExternalCommand.find_command(cmd) | |
| 64 | if cmdclass: | |
| 65 | return cmd, cmdclass | |
| 66 | ||
| 67 | raise BzrCommandError("unknown command %r" % cmd) | |
| 272
by Martin Pool - Add command aliases | 68 | |
| 329
by Martin Pool - refactor command functions into command classes | 69 | |
| 70 | class Command: | |
| 71 | """Base class for commands. | |
| 72 | ||
| 73 |     The docstring for an actual command should give a single-line
 | |
| 74 |     summary, then a complete description of the command.  A grammar
 | |
| 75 |     description will be inserted.
 | |
| 76 | ||
| 77 |     takes_args
 | |
| 78 |         List of argument forms, marked with whether they are optional,
 | |
| 79 |         repeated, etc.
 | |
| 80 | ||
| 81 |     takes_options
 | |
| 82 |         List of options that may be given for this command.
 | |
| 83 | ||
| 84 |     hidden
 | |
| 85 |         If true, this command isn't advertised.
 | |
| 86 |     """
 | |
| 87 | aliases = [] | |
| 88 | ||
| 89 | takes_args = [] | |
| 90 | takes_options = [] | |
| 91 | ||
| 92 | hidden = False | |
| 93 | ||
| 94 | def __init__(self, options, arguments): | |
| 95 | """Construct and run the command. | |
| 96 | ||
| 97 |         Sets self.status to the return value of run()."""
 | |
| 98 | assert isinstance(options, dict) | |
| 99 | assert isinstance(arguments, dict) | |
| 100 | cmdargs = options.copy() | |
| 101 | cmdargs.update(arguments) | |
| 102 | assert self.__doc__ != Command.__doc__, \ | |
| 103 | ("No help message set for %r" % self) | |
| 104 | self.status = self.run(**cmdargs) | |
| 105 | ||
| 106 | ||
| 107 | def run(self): | |
| 108 | """Override this in sub-classes. | |
| 109 | ||
| 110 |         This is invoked with the options and arguments bound to
 | |
| 111 |         keyword parameters.
 | |
| 112 | ||
| 337
by Martin Pool - Clarify return codes from command objects | 113 |         Return 0 or None if the command was successful, or a shell
 | 
| 114 |         error code if not.
 | |
| 329
by Martin Pool - refactor command functions into command classes | 115 |         """
 | 
| 337
by Martin Pool - Clarify return codes from command objects | 116 | return 0 | 
| 329
by Martin Pool - refactor command functions into command classes | 117 | |
| 118 | ||
| 422
by Martin Pool - External-command patch from mpe | 119 | class ExternalCommand(Command): | 
| 120 | """Class to wrap external commands. | |
| 121 | ||
| 122 |     We cheat a little here, when get_cmd_class() calls us we actually give it back
 | |
| 123 |     an object we construct that has the appropriate path, help, options etc for the
 | |
| 124 |     specified command.
 | |
| 125 | ||
| 126 |     When run_bzr() tries to instantiate that 'class' it gets caught by the __call__
 | |
| 127 |     method, which we override to call the Command.__init__ method. That then calls
 | |
| 128 |     our run method which is pretty straight forward.
 | |
| 129 | ||
| 130 |     The only wrinkle is that we have to map bzr's dictionary of options and arguments
 | |
| 131 |     back into command line options and arguments for the script.
 | |
| 132 |     """
 | |
| 133 | ||
| 134 | def find_command(cls, cmd): | |
| 135 | bzrpath = os.environ.get('BZRPATH', '') | |
| 136 | ||
| 137 | for dir in bzrpath.split(':'): | |
| 138 | path = os.path.join(dir, cmd) | |
| 139 | if os.path.isfile(path): | |
| 140 | return ExternalCommand(path) | |
| 141 | ||
| 142 | return None | |
| 143 | ||
| 144 | find_command = classmethod(find_command) | |
| 145 | ||
| 146 | def __init__(self, path): | |
| 147 | self.path = path | |
| 148 | ||
| 424
by Martin Pool todo | 149 |         # TODO: If either of these fail, we should detect that and
 | 
| 150 |         # assume that path is not really a bzr plugin after all.
 | |
| 151 | ||
| 422
by Martin Pool - External-command patch from mpe | 152 | pipe = os.popen('%s --bzr-usage' % path, 'r') | 
| 153 | self.takes_options = pipe.readline().split() | |
| 154 | self.takes_args = pipe.readline().split() | |
| 155 | pipe.close() | |
| 156 | ||
| 157 | pipe = os.popen('%s --bzr-help' % path, 'r') | |
| 158 | self.__doc__ = pipe.read() | |
| 159 | pipe.close() | |
| 160 | ||
| 161 | def __call__(self, options, arguments): | |
| 162 | Command.__init__(self, options, arguments) | |
| 163 | return self | |
| 164 | ||
| 165 | def run(self, **kargs): | |
| 166 | opts = [] | |
| 167 | args = [] | |
| 168 | ||
| 169 | keys = kargs.keys() | |
| 170 | keys.sort() | |
| 171 | for name in keys: | |
| 172 | value = kargs[name] | |
| 173 | if OPTIONS.has_key(name): | |
| 174 |                 # it's an option
 | |
| 175 | opts.append('--%s' % name) | |
| 176 | if value is not None and value is not True: | |
| 177 | opts.append(str(value)) | |
| 178 | else: | |
| 179 |                 # it's an arg, or arg list
 | |
| 180 | if type(value) is not list: | |
| 181 | value = [value] | |
| 182 | for v in value: | |
| 183 | if v is not None: | |
| 184 | args.append(str(v)) | |
| 185 | ||
| 186 | self.status = os.spawnv(os.P_WAIT, self.path, [self.path] + opts + args) | |
| 187 | return self.status | |
| 188 | ||
| 329
by Martin Pool - refactor command functions into command classes | 189 | |
| 190 | class cmd_status(Command): | |
| 1
by mbp at sourcefrog import from baz patch-364 | 191 | """Display status summary. | 
| 192 | ||
| 466
by Martin Pool - doc for status command | 193 |     This reports on versioned and unknown files, reporting them
 | 
| 194 |     grouped by state.  Possible states are:
 | |
| 195 | ||
| 196 |     added
 | |
| 197 |         Versioned in the working copy but not in the previous revision.
 | |
| 198 | ||
| 199 |     removed
 | |
| 467
by Martin Pool - doc for status command | 200 |         Versioned in the previous revision but removed or deleted
 | 
| 466
by Martin Pool - doc for status command | 201 |         in the working copy.
 | 
| 202 | ||
| 203 |     renamed
 | |
| 204 |         Path of this file changed from the previous revision;
 | |
| 205 |         the text may also have changed.  This includes files whose
 | |
| 467
by Martin Pool - doc for status command | 206 |         parent directory was renamed.
 | 
| 466
by Martin Pool - doc for status command | 207 | |
| 208 |     modified
 | |
| 209 |         Text has changed since the previous revision.
 | |
| 210 | ||
| 211 |     unchanged
 | |
| 467
by Martin Pool - doc for status command | 212 |         Nothing about this file has changed since the previous revision.
 | 
| 213 |         Only shown with --all.
 | |
| 466
by Martin Pool - doc for status command | 214 | |
| 215 |     unknown
 | |
| 216 |         Not versioned and not matching an ignore pattern.
 | |
| 217 | ||
| 218 |     To see ignored files use 'bzr ignored'.  For details in the
 | |
| 219 |     changes to file texts, use 'bzr diff'.
 | |
| 468
by Martin Pool - Interpret arguments to bzr status | 220 | |
| 221 |     If no arguments are specified, the status of the entire working
 | |
| 222 |     directory is shown.  Otherwise, only the status of the specified
 | |
| 223 |     files or directories is reported.  If a directory is given, status
 | |
| 224 |     is reported for everything inside that directory.
 | |
| 1
by mbp at sourcefrog import from baz patch-364 | 225 |     """
 | 
| 404
by Martin Pool - bzr status now optionally takes filenames to check | 226 | takes_args = ['file*'] | 
| 465
by Martin Pool - Move show_status() out of Branch into a new function in | 227 | takes_options = ['all', 'show-ids'] | 
| 350
by Martin Pool - refactor command aliases into command classes | 228 | aliases = ['st', 'stat'] | 
| 329
by Martin Pool - refactor command functions into command classes | 229 | |
| 465
by Martin Pool - Move show_status() out of Branch into a new function in | 230 | def run(self, all=False, show_ids=False, file_list=None): | 
| 468
by Martin Pool - Interpret arguments to bzr status | 231 | if file_list: | 
| 232 | b = Branch(file_list[0], lock_mode='r') | |
| 233 | file_list = [b.relpath(x) for x in file_list] | |
| 234 |             # special case: only one path was given and it's the root
 | |
| 235 |             # of the branch
 | |
| 236 | if file_list == ['']: | |
| 237 | file_list = None | |
| 238 | else: | |
| 239 | b = Branch('.', lock_mode='r') | |
| 465
by Martin Pool - Move show_status() out of Branch into a new function in | 240 | import status | 
| 241 | status.show_status(b, show_unchanged=all, show_ids=show_ids, | |
| 483
by Martin Pool - change 'file_list' to more explanatory 'specific_files' | 242 | specific_files=file_list) | 
| 329
by Martin Pool - refactor command functions into command classes | 243 | |
| 244 | ||
| 245 | class cmd_cat_revision(Command): | |
| 246 | """Write out metadata for a revision.""" | |
| 247 | ||
| 248 | hidden = True | |
| 249 | takes_args = ['revision_id'] | |
| 250 | ||
| 251 | def run(self, revision_id): | |
| 252 | Branch('.').get_revision(revision_id).write_xml(sys.stdout) | |
| 253 | ||
| 254 | ||
| 255 | class cmd_revno(Command): | |
| 256 | """Show current revision number. | |
| 257 | ||
| 258 |     This is equal to the number of revisions on this branch."""
 | |
| 259 | def run(self): | |
| 260 | print Branch('.').revno() | |
| 261 | ||
| 262 | ||
| 263 | class cmd_add(Command): | |
| 70
by mbp at sourcefrog Prepare for smart recursive add. | 264 | """Add specified files or directories. | 
| 265 | ||
| 266 |     In non-recursive mode, all the named items are added, regardless
 | |
| 267 |     of whether they were previously ignored.  A warning is given if
 | |
| 268 |     any of the named files are already versioned.
 | |
| 269 | ||
| 270 |     In recursive mode (the default), files are treated the same way
 | |
| 271 |     but the behaviour for directories is different.  Directories that
 | |
| 272 |     are already versioned do not give a warning.  All directories,
 | |
| 273 |     whether already versioned or not, are searched for files or
 | |
| 274 |     subdirectories that are neither versioned or ignored, and these
 | |
| 275 |     are added.  This search proceeds recursively into versioned
 | |
| 276 |     directories.
 | |
| 277 | ||
| 278 |     Therefore simply saying 'bzr add .' will version all files that
 | |
| 279 |     are currently unknown.
 | |
| 279
by Martin Pool todo | 280 | |
| 281 |     TODO: Perhaps adding a file whose directly is not versioned should
 | |
| 282 |     recursively add that parent, rather than giving an error?
 | |
| 70
by mbp at sourcefrog Prepare for smart recursive add. | 283 |     """
 | 
| 329
by Martin Pool - refactor command functions into command classes | 284 | takes_args = ['file+'] | 
| 285 | takes_options = ['verbose'] | |
| 286 | ||
| 287 | def run(self, file_list, verbose=False): | |
| 288 | bzrlib.add.smart_add(file_list, verbose) | |
| 289 | ||
| 290 | ||
| 386
by Martin Pool - Typo (reported by uws) | 291 | class cmd_relpath(Command): | 
| 329
by Martin Pool - refactor command functions into command classes | 292 | """Show path of a file relative to root""" | 
| 392
by Martin Pool - fix relpath and add tests | 293 | takes_args = ['filename'] | 
| 329
by Martin Pool - refactor command functions into command classes | 294 | |
| 392
by Martin Pool - fix relpath and add tests | 295 | def run(self, filename): | 
| 296 | print Branch(filename).relpath(filename) | |
| 329
by Martin Pool - refactor command functions into command classes | 297 | |
| 298 | ||
| 299 | ||
| 300 | class cmd_inventory(Command): | |
| 301 | """Show inventory of the current working copy or a revision.""" | |
| 302 | takes_options = ['revision'] | |
| 303 | ||
| 304 | def run(self, revision=None): | |
| 305 | b = Branch('.') | |
| 306 | if revision == None: | |
| 307 | inv = b.read_working_inventory() | |
| 308 | else: | |
| 309 | inv = b.get_revision_inventory(b.lookup_revision(revision)) | |
| 310 | ||
| 311 | for path, entry in inv.iter_entries(): | |
| 312 | print '%-50s %s' % (entry.file_id, path) | |
| 313 | ||
| 314 | ||
| 315 | class cmd_move(Command): | |
| 316 | """Move files to a different directory. | |
| 317 | ||
| 318 |     examples:
 | |
| 319 |         bzr move *.txt doc
 | |
| 320 | ||
| 321 |     The destination must be a versioned directory in the same branch.
 | |
| 322 |     """
 | |
| 323 | takes_args = ['source$', 'dest'] | |
| 324 | def run(self, source_list, dest): | |
| 325 | b = Branch('.') | |
| 326 | ||
| 327 | b.move([b.relpath(s) for s in source_list], b.relpath(dest)) | |
| 328 | ||
| 329 | ||
| 330 | class cmd_rename(Command): | |
| 168
by mbp at sourcefrog new "rename" command | 331 | """Change the name of an entry. | 
| 332 | ||
| 232
by mbp at sourcefrog Allow docstrings for help to be in PEP0257 format. | 333 |     examples:
 | 
| 334 |       bzr rename frob.c frobber.c
 | |
| 335 |       bzr rename src/frob.c lib/frob.c
 | |
| 336 | ||
| 337 |     It is an error if the destination name exists.
 | |
| 338 | ||
| 339 |     See also the 'move' command, which moves files into a different
 | |
| 340 |     directory without changing their name.
 | |
| 341 | ||
| 342 |     TODO: Some way to rename multiple files without invoking bzr for each
 | |
| 343 |     one?"""
 | |
| 329
by Martin Pool - refactor command functions into command classes | 344 | takes_args = ['from_name', 'to_name'] | 
| 168
by mbp at sourcefrog new "rename" command | 345 | |
| 329
by Martin Pool - refactor command functions into command classes | 346 | def run(self, from_name, to_name): | 
| 347 | b = Branch('.') | |
| 348 | b.rename_one(b.relpath(from_name), b.relpath(to_name)) | |
| 349 | ||
| 350 | ||
| 351 | ||
| 352 | class cmd_renames(Command): | |
| 164
by mbp at sourcefrog new 'renames' command | 353 | """Show list of renamed files. | 
| 354 | ||
| 232
by mbp at sourcefrog Allow docstrings for help to be in PEP0257 format. | 355 |     TODO: Option to show renames between two historical versions.
 | 
| 356 | ||
| 357 |     TODO: Only show renames under dir, rather than in the whole branch.
 | |
| 358 |     """
 | |
| 329
by Martin Pool - refactor command functions into command classes | 359 | takes_args = ['dir?'] | 
| 360 | ||
| 361 | def run(self, dir='.'): | |
| 362 | b = Branch(dir) | |
| 363 | old_inv = b.basis_tree().inventory | |
| 364 | new_inv = b.read_working_inventory() | |
| 365 | ||
| 366 | renames = list(bzrlib.tree.find_renames(old_inv, new_inv)) | |
| 367 | renames.sort() | |
| 368 | for old_name, new_name in renames: | |
| 369 | print "%s => %s" % (old_name, new_name) | |
| 370 | ||
| 371 | ||
| 372 | class cmd_info(Command): | |
| 472
by Martin Pool - Optional branch parameter to info command | 373 | """Show statistical information about a branch.""" | 
| 374 | takes_args = ['branch?'] | |
| 375 | ||
| 376 | def run(self, branch=None): | |
| 329
by Martin Pool - refactor command functions into command classes | 377 | import info | 
| 472
by Martin Pool - Optional branch parameter to info command | 378 | |
| 379 | from branch import find_branch | |
| 380 | b = find_branch(branch) | |
| 381 | info.show_info(b) | |
| 329
by Martin Pool - refactor command functions into command classes | 382 | |
| 383 | ||
| 384 | class cmd_remove(Command): | |
| 385 | """Make a file unversioned. | |
| 386 | ||
| 387 |     This makes bzr stop tracking changes to a versioned file.  It does
 | |
| 388 |     not delete the working copy.
 | |
| 389 |     """
 | |
| 390 | takes_args = ['file+'] | |
| 391 | takes_options = ['verbose'] | |
| 392 | ||
| 393 | def run(self, file_list, verbose=False): | |
| 394 | b = Branch(file_list[0]) | |
| 395 | b.remove([b.relpath(f) for f in file_list], verbose=verbose) | |
| 396 | ||
| 397 | ||
| 398 | class cmd_file_id(Command): | |
| 178
by mbp at sourcefrog - Use a non-null file_id for the branch root directory. At the moment | 399 | """Print file_id of a particular file or directory. | 
| 400 | ||
| 232
by mbp at sourcefrog Allow docstrings for help to be in PEP0257 format. | 401 |     The file_id is assigned when the file is first added and remains the
 | 
| 402 |     same through all revisions where the file exists, even when it is
 | |
| 403 |     moved or renamed.
 | |
| 404 |     """
 | |
| 329
by Martin Pool - refactor command functions into command classes | 405 | hidden = True | 
| 406 | takes_args = ['filename'] | |
| 407 | def run(self, filename): | |
| 408 | b = Branch(filename) | |
| 409 | i = b.inventory.path2id(b.relpath(filename)) | |
| 410 | if i == None: | |
| 411 | bailout("%r is not a versioned file" % filename) | |
| 412 | else: | |
| 413 | print i | |
| 414 | ||
| 415 | ||
| 416 | class cmd_file_path(Command): | |
| 178
by mbp at sourcefrog - Use a non-null file_id for the branch root directory. At the moment | 417 | """Print path of file_ids to a file or directory. | 
| 418 | ||
| 232
by mbp at sourcefrog Allow docstrings for help to be in PEP0257 format. | 419 |     This prints one line for each directory down to the target,
 | 
| 420 |     starting at the branch root."""
 | |
| 329
by Martin Pool - refactor command functions into command classes | 421 | hidden = True | 
| 422 | takes_args = ['filename'] | |
| 423 | def run(self, filename): | |
| 424 | b = Branch(filename) | |
| 425 | inv = b.inventory | |
| 426 | fid = inv.path2id(b.relpath(filename)) | |
| 427 | if fid == None: | |
| 428 | bailout("%r is not a versioned file" % filename) | |
| 429 | for fip in inv.get_idpath(fid): | |
| 430 | print fip | |
| 431 | ||
| 432 | ||
| 433 | class cmd_revision_history(Command): | |
| 434 | """Display list of revision ids on this branch.""" | |
| 435 | def run(self): | |
| 436 | for patchid in Branch('.').revision_history(): | |
| 437 | print patchid | |
| 438 | ||
| 439 | ||
| 440 | class cmd_directories(Command): | |
| 441 | """Display list of versioned directories in this branch.""" | |
| 442 | def run(self): | |
| 443 | for name, ie in Branch('.').read_working_inventory().directories(): | |
| 444 | if name == '': | |
| 445 | print '.' | |
| 446 | else: | |
| 447 | print name | |
| 448 | ||
| 449 | ||
| 450 | class cmd_init(Command): | |
| 451 | """Make a directory into a versioned branch. | |
| 452 | ||
| 453 |     Use this to create an empty branch, or before importing an
 | |
| 454 |     existing project.
 | |
| 455 | ||
| 456 |     Recipe for importing a tree of files:
 | |
| 457 |         cd ~/project
 | |
| 458 |         bzr init
 | |
| 459 |         bzr add -v .
 | |
| 460 |         bzr status
 | |
| 461 |         bzr commit -m 'imported project'
 | |
| 462 |     """
 | |
| 463 | def run(self): | |
| 464 | Branch('.', init=True) | |
| 465 | ||
| 466 | ||
| 467 | class cmd_diff(Command): | |
| 468 | """Show differences in working tree. | |
| 469 |     
 | |
| 232
by mbp at sourcefrog Allow docstrings for help to be in PEP0257 format. | 470 |     If files are listed, only the changes in those files are listed.
 | 
| 471 |     Otherwise, all changes for the tree are listed.
 | |
| 472 | ||
| 473 |     TODO: Given two revision arguments, show the difference between them.
 | |
| 474 | ||
| 475 |     TODO: Allow diff across branches.
 | |
| 476 | ||
| 477 |     TODO: Option to use external diff command; could be GNU diff, wdiff,
 | |
| 478 |           or a graphical diff.
 | |
| 479 | ||
| 276
by Martin Pool Doc | 480 |     TODO: Python difflib is not exactly the same as unidiff; should
 | 
| 481 |           either fix it up or prefer to use an external diff.
 | |
| 482 | ||
| 232
by mbp at sourcefrog Allow docstrings for help to be in PEP0257 format. | 483 |     TODO: If a directory is given, diff everything under that.
 | 
| 484 | ||
| 276
by Martin Pool Doc | 485 |     TODO: Selected-file diff is inefficient and doesn't show you
 | 
| 486 |           deleted files.
 | |
| 278
by Martin Pool - Better workaround for trailing newlines in diffs | 487 | |
| 488 |     TODO: This probably handles non-Unix newlines poorly.
 | |
| 329
by Martin Pool - refactor command functions into command classes | 489 |     """
 | 
| 490 | ||
| 491 | takes_args = ['file*'] | |
| 492 | takes_options = ['revision'] | |
| 350
by Martin Pool - refactor command aliases into command classes | 493 | aliases = ['di'] | 
| 329
by Martin Pool - refactor command functions into command classes | 494 | |
| 495 | def run(self, revision=None, file_list=None): | |
| 496 | from bzrlib.diff import show_diff | |
| 497 | ||
| 483
by Martin Pool - change 'file_list' to more explanatory 'specific_files' | 498 | show_diff(Branch('.'), revision, specific_files=file_list) | 
| 329
by Martin Pool - refactor command functions into command classes | 499 | |
| 500 | ||
| 437
by Martin Pool - new command 'bzr modified' to exercise the statcache | 501 | |
| 502 | ||
| 503 | ||
| 329
by Martin Pool - refactor command functions into command classes | 504 | class cmd_deleted(Command): | 
| 135
by mbp at sourcefrog Simple new 'deleted' command | 505 | """List files deleted in the working tree. | 
| 506 | ||
| 232
by mbp at sourcefrog Allow docstrings for help to be in PEP0257 format. | 507 |     TODO: Show files deleted since a previous revision, or between two revisions.
 | 
| 135
by mbp at sourcefrog Simple new 'deleted' command | 508 |     """
 | 
| 329
by Martin Pool - refactor command functions into command classes | 509 | def run(self, show_ids=False): | 
| 510 | b = Branch('.') | |
| 511 | old = b.basis_tree() | |
| 512 | new = b.working_tree() | |
| 513 | ||
| 514 |         ## TODO: Much more efficient way to do this: read in new
 | |
| 515 |         ## directories with readdir, rather than stating each one.  Same
 | |
| 516 |         ## level of effort but possibly much less IO.  (Or possibly not,
 | |
| 517 |         ## if the directories are very large...)
 | |
| 518 | ||
| 519 | for path, ie in old.inventory.iter_entries(): | |
| 520 | if not new.has_id(ie.file_id): | |
| 521 | if show_ids: | |
| 522 | print '%-50s %s' % (path, ie.file_id) | |
| 523 | else: | |
| 524 | print path | |
| 525 | ||
| 437
by Martin Pool - new command 'bzr modified' to exercise the statcache | 526 | |
| 527 | class cmd_modified(Command): | |
| 528 | """List files modified in working tree.""" | |
| 529 | hidden = True | |
| 530 | def run(self): | |
| 531 | import statcache | |
| 532 | b = Branch('.') | |
| 438
by Martin Pool - Avoid calling Inventory.iter_entries() when finding modified | 533 | inv = b.read_working_inventory() | 
| 534 | sc = statcache.update_cache(b, inv) | |
| 437
by Martin Pool - new command 'bzr modified' to exercise the statcache | 535 | basis = b.basis_tree() | 
| 536 | basis_inv = basis.inventory | |
| 438
by Martin Pool - Avoid calling Inventory.iter_entries() when finding modified | 537 | |
| 538 |         # We used to do this through iter_entries(), but that's slow
 | |
| 539 |         # when most of the files are unmodified, as is usually the
 | |
| 540 |         # case.  So instead we iterate by inventory entry, and only
 | |
| 541 |         # calculate paths as necessary.
 | |
| 542 | ||
| 543 | for file_id in basis_inv: | |
| 544 | cacheentry = sc.get(file_id) | |
| 545 | if not cacheentry: # deleted | |
| 546 |                 continue
 | |
| 547 | ie = basis_inv[file_id] | |
| 437
by Martin Pool - new command 'bzr modified' to exercise the statcache | 548 | if cacheentry[statcache.SC_SHA1] != ie.text_sha1: | 
| 438
by Martin Pool - Avoid calling Inventory.iter_entries() when finding modified | 549 | path = inv.id2path(file_id) | 
| 437
by Martin Pool - new command 'bzr modified' to exercise the statcache | 550 | print path | 
| 439
by Martin Pool - new command 'bzr added' | 551 | |
| 552 | ||
| 553 | ||
| 554 | class cmd_added(Command): | |
| 555 | """List files added in working tree.""" | |
| 556 | hidden = True | |
| 557 | def run(self): | |
| 558 | b = Branch('.') | |
| 559 | wt = b.working_tree() | |
| 560 | basis_inv = b.basis_tree().inventory | |
| 561 | inv = wt.inventory | |
| 562 | for file_id in inv: | |
| 563 | if file_id in basis_inv: | |
| 564 |                 continue
 | |
| 565 | path = inv.id2path(file_id) | |
| 566 | if not os.access(b.abspath(path), os.F_OK): | |
| 567 |                 continue
 | |
| 568 | print path | |
| 437
by Martin Pool - new command 'bzr modified' to exercise the statcache | 569 | |
| 570 | ||
| 571 | ||
| 329
by Martin Pool - refactor command functions into command classes | 572 | class cmd_root(Command): | 
| 573 | """Show the tree root directory. | |
| 574 | ||
| 575 |     The root is the nearest enclosing directory with a .bzr control
 | |
| 576 |     directory."""
 | |
| 577 | takes_args = ['filename?'] | |
| 578 | def run(self, filename=None): | |
| 579 | """Print the branch root.""" | |
| 416
by Martin Pool - bzr log and bzr root now accept an http URL | 580 | from branch import find_branch | 
| 581 | b = find_branch(filename) | |
| 582 | print getattr(b, 'base', None) or getattr(b, 'baseurl') | |
| 329
by Martin Pool - refactor command functions into command classes | 583 | |
| 584 | ||
| 585 | class cmd_log(Command): | |
| 1
by mbp at sourcefrog import from baz patch-364 | 586 | """Show log of this branch. | 
| 587 | ||
| 367
by Martin Pool - New --show-ids option for bzr log | 588 |     TODO: Option to limit range.
 | 
| 589 | ||
| 590 |     TODO: Perhaps show most-recent first with an option for last.
 | |
| 1
by mbp at sourcefrog import from baz patch-364 | 591 |     """
 | 
| 378
by Martin Pool - New usage bzr log FILENAME | 592 | takes_args = ['filename?'] | 
| 367
by Martin Pool - New --show-ids option for bzr log | 593 | takes_options = ['timezone', 'verbose', 'show-ids'] | 
| 378
by Martin Pool - New usage bzr log FILENAME | 594 | def run(self, filename=None, timezone='original', verbose=False, show_ids=False): | 
| 416
by Martin Pool - bzr log and bzr root now accept an http URL | 595 | from branch import find_branch | 
| 596 | b = find_branch((filename or '.'), lock_mode='r') | |
| 378
by Martin Pool - New usage bzr log FILENAME | 597 | if filename: | 
| 598 | filename = b.relpath(filename) | |
| 599 | bzrlib.show_log(b, filename, | |
| 371
by Martin Pool - Fix up bzr log command | 600 | show_timezone=timezone, | 
| 601 | verbose=verbose, | |
| 602 | show_ids=show_ids) | |
| 329
by Martin Pool - refactor command functions into command classes | 603 | |
| 604 | ||
| 375
by Martin Pool - New command touching-revisions and function to trace | 605 | |
| 606 | class cmd_touching_revisions(Command): | |
| 607 | """Return revision-ids which affected a particular file.""" | |
| 608 | hidden = True | |
| 609 | takes_args = ["filename"] | |
| 610 | def run(self, filename): | |
| 611 | b = Branch(filename, lock_mode='r') | |
| 612 | inv = b.read_working_inventory() | |
| 613 | file_id = inv.path2id(b.relpath(filename)) | |
| 614 | for revno, revision_id, what in bzrlib.log.find_touching_revisions(b, file_id): | |
| 615 | print "%6d %s" % (revno, what) | |
| 616 | ||
| 617 | ||
| 329
by Martin Pool - refactor command functions into command classes | 618 | class cmd_ls(Command): | 
| 1
by mbp at sourcefrog import from baz patch-364 | 619 | """List files in a tree. | 
| 620 | ||
| 254
by Martin Pool - Doc cleanups from Magnus Therning | 621 |     TODO: Take a revision or remote path and list that tree instead.
 | 
| 1
by mbp at sourcefrog import from baz patch-364 | 622 |     """
 | 
| 329
by Martin Pool - refactor command functions into command classes | 623 | hidden = True | 
| 624 | def run(self, revision=None, verbose=False): | |
| 625 | b = Branch('.') | |
| 626 | if revision == None: | |
| 627 | tree = b.working_tree() | |
| 628 | else: | |
| 629 | tree = b.revision_tree(b.lookup_revision(revision)) | |
| 630 | ||
| 631 | for fp, fc, kind, fid in tree.list_files(): | |
| 632 | if verbose: | |
| 633 | if kind == 'directory': | |
| 634 | kindch = '/' | |
| 635 | elif kind == 'file': | |
| 636 | kindch = '' | |
| 637 | else: | |
| 638 | kindch = '???' | |
| 639 | ||
| 640 | print '%-8s %s%s' % (fc, fp, kindch) | |
| 1
by mbp at sourcefrog import from baz patch-364 | 641 | else: | 
| 329
by Martin Pool - refactor command functions into command classes | 642 | print fp | 
| 643 | ||
| 644 | ||
| 645 | ||
| 646 | class cmd_unknowns(Command): | |
| 1
by mbp at sourcefrog import from baz patch-364 | 647 | """List unknown files""" | 
| 329
by Martin Pool - refactor command functions into command classes | 648 | def run(self): | 
| 649 | for f in Branch('.').unknowns(): | |
| 650 | print quotefn(f) | |
| 651 | ||
| 652 | ||
| 653 | ||
| 654 | class cmd_ignore(Command): | |
| 420
by Martin Pool Doc | 655 | """Ignore a command or pattern | 
| 656 | ||
| 657 |     To remove patterns from the ignore list, edit the .bzrignore file.
 | |
| 658 | ||
| 659 |     If the pattern contains a slash, it is compared to the whole path
 | |
| 660 |     from the branch root.  Otherwise, it is comapred to only the last
 | |
| 661 |     component of the path.
 | |
| 662 | ||
| 663 |     Ignore patterns are case-insensitive on case-insensitive systems.
 | |
| 664 | ||
| 665 |     Note: wildcards must be quoted from the shell on Unix.
 | |
| 666 | ||
| 667 |     examples:
 | |
| 668 |         bzr ignore ./Makefile
 | |
| 669 |         bzr ignore '*.class'
 | |
| 670 |     """
 | |
| 329
by Martin Pool - refactor command functions into command classes | 671 | takes_args = ['name_pattern'] | 
| 310
by Martin Pool - new 'bzr ignored' command! | 672 | |
| 329
by Martin Pool - refactor command functions into command classes | 673 | def run(self, name_pattern): | 
| 409
by Martin Pool - New AtomicFile class | 674 | from bzrlib.atomicfile import AtomicFile | 
| 675 | import codecs | |
| 676 | ||
| 329
by Martin Pool - refactor command functions into command classes | 677 | b = Branch('.') | 
| 410
by Martin Pool - Fix ignore command and add tests | 678 | ifn = b.abspath('.bzrignore') | 
| 329
by Martin Pool - refactor command functions into command classes | 679 | |
| 410
by Martin Pool - Fix ignore command and add tests | 680 | if os.path.exists(ifn): | 
| 498
by Martin Pool bugfix for bzr ignore reported by ddaa: | 681 | f = open(ifn, 'rt') | 
| 682 | try: | |
| 683 | igns = f.read().decode('utf-8') | |
| 684 | finally: | |
| 685 | f.close() | |
| 409
by Martin Pool - New AtomicFile class | 686 | else: | 
| 687 | igns = '' | |
| 688 | ||
| 689 | if igns and igns[-1] != '\n': | |
| 690 | igns += '\n' | |
| 691 | igns += name_pattern + '\n' | |
| 692 | ||
| 498
by Martin Pool bugfix for bzr ignore reported by ddaa: | 693 | try: | 
| 694 | f = AtomicFile(ifn, 'wt') | |
| 695 | f.write(igns.encode('utf-8')) | |
| 696 | f.commit() | |
| 697 | finally: | |
| 698 | f.close() | |
| 329
by Martin Pool - refactor command functions into command classes | 699 | |
| 700 | inv = b.working_tree().inventory | |
| 701 | if inv.path2id('.bzrignore'): | |
| 702 | mutter('.bzrignore is already versioned') | |
| 703 | else: | |
| 704 | mutter('need to make new .bzrignore file versioned') | |
| 705 | b.add(['.bzrignore']) | |
| 706 | ||
| 707 | ||
| 708 | ||
| 709 | class cmd_ignored(Command): | |
| 421
by Martin Pool doc | 710 | """List ignored files and the patterns that matched them. | 
| 711 | ||
| 712 |     See also: bzr ignore"""
 | |
| 329
by Martin Pool - refactor command functions into command classes | 713 | def run(self): | 
| 714 | tree = Branch('.').working_tree() | |
| 715 | for path, file_class, kind, file_id in tree.list_files(): | |
| 716 | if file_class != 'I': | |
| 717 |                 continue
 | |
| 718 |             ## XXX: Slightly inefficient since this was already calculated
 | |
| 719 | pat = tree.is_ignored(path) | |
| 720 | print '%-50s %s' % (path, pat) | |
| 721 | ||
| 722 | ||
| 723 | class cmd_lookup_revision(Command): | |
| 724 | """Lookup the revision-id from a revision-number | |
| 725 | ||
| 726 |     example:
 | |
| 727 |         bzr lookup-revision 33
 | |
| 421
by Martin Pool doc | 728 |     """
 | 
| 329
by Martin Pool - refactor command functions into command classes | 729 | hidden = True | 
| 338
by Martin Pool - cleanup of some imports | 730 | takes_args = ['revno'] | 
| 731 | ||
| 329
by Martin Pool - refactor command functions into command classes | 732 | def run(self, revno): | 
| 733 | try: | |
| 734 | revno = int(revno) | |
| 735 | except ValueError: | |
| 338
by Martin Pool - cleanup of some imports | 736 | raise BzrCommandError("not a valid revision-number: %r" % revno) | 
| 737 | ||
| 738 | print Branch('.').lookup_revision(revno) | |
| 329
by Martin Pool - refactor command functions into command classes | 739 | |
| 740 | ||
| 741 | class cmd_export(Command): | |
| 742 | """Export past revision to destination directory. | |
| 743 | ||
| 744 |     If no revision is specified this exports the last committed revision."""
 | |
| 745 | takes_args = ['dest'] | |
| 746 | takes_options = ['revision'] | |
| 394
by Martin Pool - Fix argument handling in export command | 747 | def run(self, dest, revision=None): | 
| 329
by Martin Pool - refactor command functions into command classes | 748 | b = Branch('.') | 
| 394
by Martin Pool - Fix argument handling in export command | 749 | if revision == None: | 
| 750 | rh = b.revision_history()[-1] | |
| 329
by Martin Pool - refactor command functions into command classes | 751 | else: | 
| 394
by Martin Pool - Fix argument handling in export command | 752 | rh = b.lookup_revision(int(revision)) | 
| 329
by Martin Pool - refactor command functions into command classes | 753 | t = b.revision_tree(rh) | 
| 754 | t.export(dest) | |
| 755 | ||
| 756 | ||
| 757 | class cmd_cat(Command): | |
| 758 | """Write a file's text from a previous revision.""" | |
| 759 | ||
| 760 | takes_options = ['revision'] | |
| 761 | takes_args = ['filename'] | |
| 762 | ||
| 763 | def run(self, filename, revision=None): | |
| 764 | if revision == None: | |
| 765 | raise BzrCommandError("bzr cat requires a revision number") | |
| 766 | b = Branch('.') | |
| 767 | b.print_file(b.relpath(filename), int(revision)) | |
| 768 | ||
| 769 | ||
| 770 | class cmd_local_time_offset(Command): | |
| 771 | """Show the offset in seconds from GMT to local time.""" | |
| 772 | hidden = True | |
| 773 | def run(self): | |
| 774 | print bzrlib.osutils.local_time_offset() | |
| 775 | ||
| 776 | ||
| 777 | ||
| 778 | class cmd_commit(Command): | |
| 779 | """Commit changes into a new revision. | |
| 232
by mbp at sourcefrog Allow docstrings for help to be in PEP0257 format. | 780 | |
| 491
by Martin Pool - Selective commit! | 781 |     If selected files are specified, only changes to those files are
 | 
| 782 |     committed.  If a directory is specified then its contents are also
 | |
| 783 |     committed.
 | |
| 784 | ||
| 785 |     A selected-file commit may fail in some cases where the committed
 | |
| 786 |     tree would be invalid, such as trying to commit a file in a
 | |
| 787 |     newly-added directory that is not itself committed.
 | |
| 232
by mbp at sourcefrog Allow docstrings for help to be in PEP0257 format. | 788 | |
| 789 |     TODO: Run hooks on tree to-be-committed, and after commit.
 | |
| 790 | ||
| 791 |     TODO: Strict commit that fails if there are unknown or deleted files.
 | |
| 792 |     """
 | |
| 491
by Martin Pool - Selective commit! | 793 | takes_args = ['selected*'] | 
| 389
by Martin Pool - new commit --file option! | 794 | takes_options = ['message', 'file', 'verbose'] | 
| 350
by Martin Pool - refactor command aliases into command classes | 795 | aliases = ['ci', 'checkin'] | 
| 796 | ||
| 505
by Martin Pool - commit is verbose by default | 797 | def run(self, message=None, file=None, verbose=True, selected_list=None): | 
| 485
by Martin Pool - move commit code into its own module | 798 | from bzrlib.commit import commit | 
| 799 | ||
| 389
by Martin Pool - new commit --file option! | 800 |         ## Warning: shadows builtin file()
 | 
| 801 | if not message and not file: | |
| 802 | raise BzrCommandError("please specify a commit message", | |
| 803 | ["use either --message or --file"]) | |
| 804 | elif message and file: | |
| 805 | raise BzrCommandError("please specify either --message or --file") | |
| 806 | ||
| 807 | if file: | |
| 808 | import codecs | |
| 809 | message = codecs.open(file, 'rt', bzrlib.user_encoding).read() | |
| 810 | ||
| 485
by Martin Pool - move commit code into its own module | 811 | b = Branch('.') | 
| 491
by Martin Pool - Selective commit! | 812 | commit(b, message, verbose=verbose, specific_files=selected_list) | 
| 329
by Martin Pool - refactor command functions into command classes | 813 | |
| 814 | ||
| 815 | class cmd_check(Command): | |
| 816 | """Validate consistency of branch history. | |
| 232
by mbp at sourcefrog Allow docstrings for help to be in PEP0257 format. | 817 | |
| 818 |     This command checks various invariants about the branch storage to
 | |
| 819 |     detect data corruption or bzr bugs.
 | |
| 820 |     """
 | |
| 329
by Martin Pool - refactor command functions into command classes | 821 | takes_args = ['dir?'] | 
| 822 | def run(self, dir='.'): | |
| 823 | import bzrlib.check | |
| 512
by Martin Pool - bzr check can be run from a branch subdirectory | 824 | bzrlib.check.check(Branch(dir)) | 
| 329
by Martin Pool - refactor command functions into command classes | 825 | |
| 826 | ||
| 827 | ||
| 828 | class cmd_whoami(Command): | |
| 829 | """Show bzr user id.""" | |
| 830 | takes_options = ['email'] | |
| 286
by Martin Pool - New bzr whoami --email option | 831 | |
| 329
by Martin Pool - refactor command functions into command classes | 832 | def run(self, email=False): | 
| 833 | if email: | |
| 834 | print bzrlib.osutils.user_email() | |
| 835 | else: | |
| 836 | print bzrlib.osutils.username() | |
| 837 | ||
| 838 | ||
| 839 | class cmd_selftest(Command): | |
| 55
by mbp at sourcefrog bzr selftest shows some counts of tests | 840 | """Run internal test suite""" | 
| 329
by Martin Pool - refactor command functions into command classes | 841 | hidden = True | 
| 842 | def run(self): | |
| 843 | failures, tests = 0, 0 | |
| 844 | ||
| 845 | import doctest, bzrlib.store, bzrlib.tests | |
| 846 | bzrlib.trace.verbose = False | |
| 847 | ||
| 848 | for m in bzrlib.store, bzrlib.inventory, bzrlib.branch, bzrlib.osutils, \ | |
| 849 | bzrlib.tree, bzrlib.tests, bzrlib.commands, bzrlib.add: | |
| 850 | mf, mt = doctest.testmod(m) | |
| 851 | failures += mf | |
| 852 | tests += mt | |
| 853 | print '%-40s %3d tests' % (m.__name__, mt), | |
| 854 | if mf: | |
| 855 | print '%3d FAILED!' % mf | |
| 856 | else: | |
| 857 |                 print
 | |
| 858 | ||
| 859 | print '%-40s %3d tests' % ('total', tests), | |
| 860 | if failures: | |
| 861 | print '%3d FAILED!' % failures | |
| 55
by mbp at sourcefrog bzr selftest shows some counts of tests | 862 | else: | 
| 863 |             print
 | |
| 864 | ||
| 329
by Martin Pool - refactor command functions into command classes | 865 | |
| 866 | ||
| 867 | class cmd_version(Command): | |
| 868 | """Show version of bzr""" | |
| 869 | def run(self): | |
| 870 | show_version() | |
| 871 | ||
| 872 | def show_version(): | |
| 873 | print "bzr (bazaar-ng) %s" % bzrlib.__version__ | |
| 874 | print bzrlib.__copyright__ | |
| 875 | print "http://bazaar-ng.org/" | |
| 876 |     print
 | |
| 877 | print "bzr comes with ABSOLUTELY NO WARRANTY. bzr is free software, and" | |
| 878 | print "you may use, modify and redistribute it under the terms of the GNU" | |
| 879 | print "General Public License version 2 or later." | |
| 880 | ||
| 881 | ||
| 882 | class cmd_rocks(Command): | |
| 883 | """Statement of optimism.""" | |
| 884 | hidden = True | |
| 885 | def run(self): | |
| 886 | print "it sure does!" | |
| 887 | ||
| 493
by Martin Pool - Merge aaron's merge command | 888 | def parse_spec(spec): | 
| 889 | if '/@' in spec: | |
| 890 | parsed = spec.split('/@') | |
| 891 | assert len(parsed) == 2 | |
| 892 | if parsed[1] == "": | |
| 893 | parsed[1] = -1 | |
| 894 | else: | |
| 895 | parsed[1] = int(parsed[1]) | |
| 896 | assert parsed[1] >=0 | |
| 897 | else: | |
| 898 | parsed = [spec, None] | |
| 899 | return parsed | |
| 900 | ||
| 901 | class cmd_merge(Command): | |
| 902 | """Perform a three-way merge of trees.""" | |
| 903 | takes_args = ['other_spec', 'base_spec'] | |
| 904 | ||
| 905 | def run(self, other_spec, base_spec): | |
| 906 | merge.merge(parse_spec(other_spec), parse_spec(base_spec)) | |
| 329
by Martin Pool - refactor command functions into command classes | 907 | |
| 908 | class cmd_assert_fail(Command): | |
| 909 | """Test reporting of assertion failures""" | |
| 910 | hidden = True | |
| 911 | def run(self): | |
| 912 | assert False, "always fails" | |
| 913 | ||
| 914 | ||
| 915 | class cmd_help(Command): | |
| 916 | """Show help on a command or other topic. | |
| 917 | ||
| 918 |     For a list of all available commands, say 'bzr help commands'."""
 | |
| 919 | takes_args = ['topic?'] | |
| 350
by Martin Pool - refactor command aliases into command classes | 920 | aliases = ['?'] | 
| 329
by Martin Pool - refactor command functions into command classes | 921 | |
| 922 | def run(self, topic=None): | |
| 351
by Martin Pool - Split out help functions into bzrlib.help | 923 | import help | 
| 924 | help.help(topic) | |
| 925 | ||
| 1
by mbp at sourcefrog import from baz patch-364 | 926 | |
| 429
by Martin Pool - New command update-stat-cache for testing | 927 | class cmd_update_stat_cache(Command): | 
| 928 | """Update stat-cache mapping inodes to SHA-1 hashes. | |
| 929 | ||
| 930 |     For testing only."""
 | |
| 931 | hidden = True | |
| 932 | def run(self): | |
| 933 | import statcache | |
| 934 | b = Branch('.') | |
| 454
by Martin Pool - fix update-stat-cache command | 935 | statcache.update_cache(b.base, b.read_working_inventory()) | 
| 429
by Martin Pool - New command update-stat-cache for testing | 936 | |
| 937 | ||
| 1
by mbp at sourcefrog import from baz patch-364 | 938 | ######################################################################
 | 
| 939 | # main routine
 | |
| 940 | ||
| 941 | ||
| 942 | # list of all available options; the rhs can be either None for an
 | |
| 943 | # option that takes no argument, or a constructor function that checks
 | |
| 944 | # the type.
 | |
| 945 | OPTIONS = { | |
| 946 | 'all': None, | |
| 947 | 'help': None, | |
| 389
by Martin Pool - new commit --file option! | 948 | 'file': unicode, | 
| 1
by mbp at sourcefrog import from baz patch-364 | 949 | 'message': unicode, | 
| 137
by mbp at sourcefrog new --profile option | 950 | 'profile': None, | 
| 1
by mbp at sourcefrog import from baz patch-364 | 951 | 'revision': int, | 
| 952 | 'show-ids': None, | |
| 12
by mbp at sourcefrog new --timezone option for bzr log | 953 | 'timezone': str, | 
| 1
by mbp at sourcefrog import from baz patch-364 | 954 | 'verbose': None, | 
| 955 | 'version': None, | |
| 286
by Martin Pool - New bzr whoami --email option | 956 | 'email': None, | 
| 1
by mbp at sourcefrog import from baz patch-364 | 957 |     }
 | 
| 958 | ||
| 959 | SHORT_OPTIONS = { | |
| 960 | 'm': 'message', | |
| 389
by Martin Pool - new commit --file option! | 961 | 'F': 'file', | 
| 1
by mbp at sourcefrog import from baz patch-364 | 962 | 'r': 'revision', | 
| 963 | 'v': 'verbose', | |
| 964 | }
 | |
| 965 | ||
| 966 | ||
| 967 | def parse_args(argv): | |
| 968 | """Parse command line. | |
| 969 |     
 | |
| 970 |     Arguments and options are parsed at this level before being passed
 | |
| 971 |     down to specific command handlers.  This routine knows, from a
 | |
| 972 |     lookup table, something about the available options, what optargs
 | |
| 973 |     they take, and which commands will accept them.
 | |
| 974 | ||
| 31
by Martin Pool fix up parse_args doctest | 975 |     >>> parse_args('--help'.split())
 | 
| 1
by mbp at sourcefrog import from baz patch-364 | 976 |     ([], {'help': True})
 | 
| 31
by Martin Pool fix up parse_args doctest | 977 |     >>> parse_args('--version'.split())
 | 
| 1
by mbp at sourcefrog import from baz patch-364 | 978 |     ([], {'version': True})
 | 
| 31
by Martin Pool fix up parse_args doctest | 979 |     >>> parse_args('status --all'.split())
 | 
| 1
by mbp at sourcefrog import from baz patch-364 | 980 |     (['status'], {'all': True})
 | 
| 31
by Martin Pool fix up parse_args doctest | 981 |     >>> parse_args('commit --message=biter'.split())
 | 
| 17
by mbp at sourcefrog allow --option=ARG syntax | 982 |     (['commit'], {'message': u'biter'})
 | 
| 1
by mbp at sourcefrog import from baz patch-364 | 983 |     """
 | 
| 984 | args = [] | |
| 985 | opts = {} | |
| 986 | ||
| 987 |     # TODO: Maybe handle '--' to end options?
 | |
| 988 | ||
| 26
by mbp at sourcefrog fix StopIteration error on python2.3(?) | 989 | while argv: | 
| 990 | a = argv.pop(0) | |
| 1
by mbp at sourcefrog import from baz patch-364 | 991 | if a[0] == '-': | 
| 264
by Martin Pool parse_args: option names must be ascii | 992 |             # option names must not be unicode
 | 
| 993 | a = str(a) | |
| 17
by mbp at sourcefrog allow --option=ARG syntax | 994 | optarg = None | 
| 1
by mbp at sourcefrog import from baz patch-364 | 995 | if a[1] == '-': | 
| 996 | mutter(" got option %r" % a) | |
| 17
by mbp at sourcefrog allow --option=ARG syntax | 997 | if '=' in a: | 
| 998 | optname, optarg = a[2:].split('=', 1) | |
| 999 | else: | |
| 1000 | optname = a[2:] | |
| 1
by mbp at sourcefrog import from baz patch-364 | 1001 | if optname not in OPTIONS: | 
| 1002 | bailout('unknown long option %r' % a) | |
| 1003 | else: | |
| 1004 | shortopt = a[1:] | |
| 1005 | if shortopt not in SHORT_OPTIONS: | |
| 1006 | bailout('unknown short option %r' % a) | |
| 1007 | optname = SHORT_OPTIONS[shortopt] | |
| 1008 | ||
| 1009 | if optname in opts: | |
| 1010 |                 # XXX: Do we ever want to support this, e.g. for -r?
 | |
| 1011 | bailout('repeated option %r' % a) | |
| 17
by mbp at sourcefrog allow --option=ARG syntax | 1012 | |
| 1
by mbp at sourcefrog import from baz patch-364 | 1013 | optargfn = OPTIONS[optname] | 
| 1014 | if optargfn: | |
| 17
by mbp at sourcefrog allow --option=ARG syntax | 1015 | if optarg == None: | 
| 26
by mbp at sourcefrog fix StopIteration error on python2.3(?) | 1016 | if not argv: | 
| 17
by mbp at sourcefrog allow --option=ARG syntax | 1017 | bailout('option %r needs an argument' % a) | 
| 1018 | else: | |
| 26
by mbp at sourcefrog fix StopIteration error on python2.3(?) | 1019 | optarg = argv.pop(0) | 
| 17
by mbp at sourcefrog allow --option=ARG syntax | 1020 | opts[optname] = optargfn(optarg) | 
| 1
by mbp at sourcefrog import from baz patch-364 | 1021 | else: | 
| 17
by mbp at sourcefrog allow --option=ARG syntax | 1022 | if optarg != None: | 
| 1023 | bailout('option %r takes no argument' % optname) | |
| 1
by mbp at sourcefrog import from baz patch-364 | 1024 | opts[optname] = True | 
| 1025 | else: | |
| 1026 | args.append(a) | |
| 1027 | ||
| 1028 | return args, opts | |
| 1029 | ||
| 1030 | ||
| 1031 | ||
| 1032 | ||
| 329
by Martin Pool - refactor command functions into command classes | 1033 | def _match_argform(cmd, takes_args, args): | 
| 1
by mbp at sourcefrog import from baz patch-364 | 1034 | argdict = {} | 
| 26
by mbp at sourcefrog fix StopIteration error on python2.3(?) | 1035 | |
| 329
by Martin Pool - refactor command functions into command classes | 1036 |     # step through args and takes_args, allowing appropriate 0-many matches
 | 
| 1037 | for ap in takes_args: | |
| 1
by mbp at sourcefrog import from baz patch-364 | 1038 | argname = ap[:-1] | 
| 1039 | if ap[-1] == '?': | |
| 62
by mbp at sourcefrog - new find_branch_root function; based on suggestion from aaron | 1040 | if args: | 
| 1041 | argdict[argname] = args.pop(0) | |
| 196
by mbp at sourcefrog selected-file diff | 1042 | elif ap[-1] == '*': # all remaining arguments | 
| 1043 | if args: | |
| 1044 | argdict[argname + '_list'] = args[:] | |
| 1045 | args = [] | |
| 1046 | else: | |
| 1047 | argdict[argname + '_list'] = None | |
| 1
by mbp at sourcefrog import from baz patch-364 | 1048 | elif ap[-1] == '+': | 
| 1049 | if not args: | |
| 329
by Martin Pool - refactor command functions into command classes | 1050 | raise BzrCommandError("command %r needs one or more %s" | 
| 1
by mbp at sourcefrog import from baz patch-364 | 1051 | % (cmd, argname.upper())) | 
| 1052 | else: | |
| 1053 | argdict[argname + '_list'] = args[:] | |
| 1054 | 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 | 1055 | elif ap[-1] == '$': # all but one | 
| 1056 | if len(args) < 2: | |
| 329
by Martin Pool - refactor command functions into command classes | 1057 | 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 | 1058 | % (cmd, argname.upper())) | 
| 1059 | argdict[argname + '_list'] = args[:-1] | |
| 1060 | args[:-1] = [] | |
| 1
by mbp at sourcefrog import from baz patch-364 | 1061 | else: | 
| 1062 |             # just a plain arg
 | |
| 1063 | argname = ap | |
| 1064 | if not args: | |
| 329
by Martin Pool - refactor command functions into command classes | 1065 | raise BzrCommandError("command %r requires argument %s" | 
| 1
by mbp at sourcefrog import from baz patch-364 | 1066 | % (cmd, argname.upper())) | 
| 1067 | else: | |
| 1068 | argdict[argname] = args.pop(0) | |
| 1069 | ||
| 1070 | if args: | |
| 329
by Martin Pool - refactor command functions into command classes | 1071 | raise BzrCommandError("extra argument to command %s: %s" | 
| 1072 | % (cmd, args[0])) | |
| 1
by mbp at sourcefrog import from baz patch-364 | 1073 | |
| 1074 | return argdict | |
| 1075 | ||
| 1076 | ||
| 1077 | ||
| 1078 | def run_bzr(argv): | |
| 1079 | """Execute a command. | |
| 1080 | ||
| 1081 |     This is similar to main(), but without all the trappings for
 | |
| 245
by mbp at sourcefrog - control files always in utf-8-unix format | 1082 |     logging and error handling.  
 | 
| 1
by mbp at sourcefrog import from baz patch-364 | 1083 |     """
 | 
| 251
by mbp at sourcefrog - factor out locale.getpreferredencoding() | 1084 | argv = [a.decode(bzrlib.user_encoding) for a in argv] | 
| 245
by mbp at sourcefrog - control files always in utf-8-unix format | 1085 | |
| 1
by mbp at sourcefrog import from baz patch-364 | 1086 | try: | 
| 26
by mbp at sourcefrog fix StopIteration error on python2.3(?) | 1087 | args, opts = parse_args(argv[1:]) | 
| 1
by mbp at sourcefrog import from baz patch-364 | 1088 | if 'help' in opts: | 
| 351
by Martin Pool - Split out help functions into bzrlib.help | 1089 | import help | 
| 159
by mbp at sourcefrog bzr commit --help now works | 1090 | if args: | 
| 351
by Martin Pool - Split out help functions into bzrlib.help | 1091 | help.help(args[0]) | 
| 159
by mbp at sourcefrog bzr commit --help now works | 1092 | else: | 
| 351
by Martin Pool - Split out help functions into bzrlib.help | 1093 | help.help() | 
| 1
by mbp at sourcefrog import from baz patch-364 | 1094 | return 0 | 
| 1095 | elif 'version' in opts: | |
| 336
by Martin Pool - fix up 'bzr --version' | 1096 | show_version() | 
| 1
by mbp at sourcefrog import from baz patch-364 | 1097 | return 0 | 
| 265
by Martin Pool parse_args: command names must also be ascii | 1098 | cmd = str(args.pop(0)) | 
| 1
by mbp at sourcefrog import from baz patch-364 | 1099 | except IndexError: | 
| 448
by Martin Pool - bzr with no command now shows help, not just an error | 1100 | import help | 
| 1101 | help.help() | |
| 1
by mbp at sourcefrog import from baz patch-364 | 1102 | return 1 | 
| 448
by Martin Pool - bzr with no command now shows help, not just an error | 1103 | |
| 115
by mbp at sourcefrog todo | 1104 | |
| 351
by Martin Pool - Split out help functions into bzrlib.help | 1105 | canonical_cmd, cmd_class = get_cmd_class(cmd) | 
| 1
by mbp at sourcefrog import from baz patch-364 | 1106 | |
| 137
by mbp at sourcefrog new --profile option | 1107 |     # global option
 | 
| 1108 | if 'profile' in opts: | |
| 1109 | profile = True | |
| 1110 | del opts['profile'] | |
| 1111 | else: | |
| 1112 | profile = False | |
| 1
by mbp at sourcefrog import from baz patch-364 | 1113 | |
| 1114 |     # check options are reasonable
 | |
| 329
by Martin Pool - refactor command functions into command classes | 1115 | allowed = cmd_class.takes_options | 
| 1
by mbp at sourcefrog import from baz patch-364 | 1116 | for oname in opts: | 
| 1117 | if oname not in allowed: | |
| 381
by Martin Pool - Better message when a wrong argument is given | 1118 | raise BzrCommandError("option '--%s' is not allowed for command %r" | 
| 329
by Martin Pool - refactor command functions into command classes | 1119 | % (oname, cmd)) | 
| 176
by mbp at sourcefrog New cat command contributed by janmar. | 1120 | |
| 137
by mbp at sourcefrog new --profile option | 1121 |     # mix arguments and options into one dictionary
 | 
| 329
by Martin Pool - refactor command functions into command classes | 1122 | cmdargs = _match_argform(cmd, cmd_class.takes_args, args) | 
| 1123 | cmdopts = {} | |
| 136
by mbp at sourcefrog new --show-ids option for 'deleted' command | 1124 | for k, v in opts.items(): | 
| 329
by Martin Pool - refactor command functions into command classes | 1125 | cmdopts[k.replace('-', '_')] = v | 
| 1
by mbp at sourcefrog import from baz patch-364 | 1126 | |
| 137
by mbp at sourcefrog new --profile option | 1127 | if profile: | 
| 338
by Martin Pool - cleanup of some imports | 1128 | import hotshot, tempfile | 
| 239
by mbp at sourcefrog - remove profiler temporary file when done | 1129 | pffileno, pfname = tempfile.mkstemp() | 
| 1130 | try: | |
| 1131 | prof = hotshot.Profile(pfname) | |
| 329
by Martin Pool - refactor command functions into command classes | 1132 | ret = prof.runcall(cmd_class, cmdopts, cmdargs) or 0 | 
| 239
by mbp at sourcefrog - remove profiler temporary file when done | 1133 | prof.close() | 
| 1134 | ||
| 1135 | import hotshot.stats | |
| 1136 | stats = hotshot.stats.load(pfname) | |
| 1137 |             #stats.strip_dirs()
 | |
| 1138 | stats.sort_stats('time') | |
| 1139 |             ## XXX: Might like to write to stderr or the trace file instead but
 | |
| 1140 |             ## print_stats seems hardcoded to stdout
 | |
| 1141 | stats.print_stats(20) | |
| 1142 | ||
| 337
by Martin Pool - Clarify return codes from command objects | 1143 | return ret.status | 
| 239
by mbp at sourcefrog - remove profiler temporary file when done | 1144 | |
| 1145 | finally: | |
| 1146 | os.close(pffileno) | |
| 1147 | os.remove(pfname) | |
| 137
by mbp at sourcefrog new --profile option | 1148 | else: | 
| 500
by Martin Pool - fix return value from run_bzr | 1149 | return cmd_class(cmdopts, cmdargs).status | 
| 1
by mbp at sourcefrog import from baz patch-364 | 1150 | |
| 1151 | ||
| 359
by Martin Pool - pychecker fixups | 1152 | def _report_exception(summary, quiet=False): | 
| 267
by Martin Pool - better reporting of errors | 1153 | import traceback | 
| 1154 | log_error('bzr: ' + summary) | |
| 359
by Martin Pool - pychecker fixups | 1155 | bzrlib.trace.log_exception() | 
| 317
by Martin Pool - better error message for broken pipe | 1156 | |
| 1157 | if not quiet: | |
| 1158 | tb = sys.exc_info()[2] | |
| 1159 | exinfo = traceback.extract_tb(tb) | |
| 1160 | if exinfo: | |
| 1161 | sys.stderr.write(' at %s:%d in %s()\n' % exinfo[-1][:3]) | |
| 1162 | sys.stderr.write(' see ~/.bzr.log for debug information\n') | |
| 267
by Martin Pool - better reporting of errors | 1163 | |
| 1164 | ||
| 1165 | ||
| 1
by mbp at sourcefrog import from baz patch-364 | 1166 | def main(argv): | 
| 317
by Martin Pool - better error message for broken pipe | 1167 | import errno | 
| 1168 | ||
| 344
by Martin Pool - It's not an error to use the library without | 1169 | bzrlib.open_tracefile(argv) | 
| 260
by Martin Pool - remove atexit() dependency for writing out execution times | 1170 | |
| 1
by mbp at sourcefrog import from baz patch-364 | 1171 | try: | 
| 260
by Martin Pool - remove atexit() dependency for writing out execution times | 1172 | try: | 
| 337
by Martin Pool - Clarify return codes from command objects | 1173 | try: | 
| 1174 | return run_bzr(argv) | |
| 1175 | finally: | |
| 1176 |                 # do this here inside the exception wrappers to catch EPIPE
 | |
| 1177 | sys.stdout.flush() | |
| 260
by Martin Pool - remove atexit() dependency for writing out execution times | 1178 | except BzrError, e: | 
| 329
by Martin Pool - refactor command functions into command classes | 1179 | quiet = isinstance(e, (BzrCommandError)) | 
| 359
by Martin Pool - pychecker fixups | 1180 | _report_exception('error: ' + e.args[0], quiet=quiet) | 
| 260
by Martin Pool - remove atexit() dependency for writing out execution times | 1181 | if len(e.args) > 1: | 
| 1182 | for h in e.args[1]: | |
| 267
by Martin Pool - better reporting of errors | 1183 |                     # some explanation or hints
 | 
| 260
by Martin Pool - remove atexit() dependency for writing out execution times | 1184 | log_error(' ' + h) | 
| 1185 | return 1 | |
| 267
by Martin Pool - better reporting of errors | 1186 | except AssertionError, e: | 
| 1187 | msg = 'assertion failed' | |
| 1188 | if str(e): | |
| 1189 | msg += ': ' + str(e) | |
| 359
by Martin Pool - pychecker fixups | 1190 | _report_exception(msg) | 
| 318
by Martin Pool - better error message for Ctrl-c | 1191 | return 2 | 
| 1192 | except KeyboardInterrupt, e: | |
| 359
by Martin Pool - pychecker fixups | 1193 | _report_exception('interrupted', quiet=True) | 
| 318
by Martin Pool - better error message for Ctrl-c | 1194 | return 2 | 
| 260
by Martin Pool - remove atexit() dependency for writing out execution times | 1195 | except Exception, e: | 
| 317
by Martin Pool - better error message for broken pipe | 1196 | quiet = False | 
| 419
by Martin Pool - RemoteBranch.__str__ and repr | 1197 | if (isinstance(e, IOError) | 
| 1198 | and hasattr(e, 'errno') | |
| 1199 | and e.errno == errno.EPIPE): | |
| 317
by Martin Pool - better error message for broken pipe | 1200 | quiet = True | 
| 1201 | msg = 'broken pipe' | |
| 1202 | else: | |
| 1203 | msg = str(e).rstrip('\n') | |
| 359
by Martin Pool - pychecker fixups | 1204 | _report_exception(msg, quiet) | 
| 318
by Martin Pool - better error message for Ctrl-c | 1205 | return 2 | 
| 260
by Martin Pool - remove atexit() dependency for writing out execution times | 1206 | finally: | 
| 1207 | bzrlib.trace.close_trace() | |
| 1
by mbp at sourcefrog import from baz patch-364 | 1208 | |
| 1209 | ||
| 1210 | if __name__ == '__main__': | |
| 1211 | sys.exit(main(sys.argv)) |