summaryrefslogtreecommitdiff
path: root/bzrlib/tests/test_patches_data/orig
diff options
context:
space:
mode:
Diffstat (limited to 'bzrlib/tests/test_patches_data/orig')
-rw-r--r--bzrlib/tests/test_patches_data/orig2789
1 files changed, 2789 insertions, 0 deletions
diff --git a/bzrlib/tests/test_patches_data/orig b/bzrlib/tests/test_patches_data/orig
new file mode 100644
index 0000000..8e02dac
--- /dev/null
+++ b/bzrlib/tests/test_patches_data/orig
@@ -0,0 +1,2789 @@
+# Copyright (C) 2004 Aaron Bentley
+# <aaron.bentley@utoronto.ca>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+import sys
+import arch
+import arch.util
+import arch.arch
+import abacmds
+import cmdutil
+import shutil
+import os
+import options
+import paths
+import time
+import cmd
+import readline
+import re
+import string
+import arch_core
+from errors import *
+import errors
+import terminal
+import ancillary
+import misc
+import email
+import smtplib
+
+__docformat__ = "restructuredtext"
+__doc__ = "Implementation of user (sub) commands"
+commands = {}
+
+def find_command(cmd):
+ """
+ Return an instance of a command type. Return None if the type isn't
+ registered.
+
+ :param cmd: the name of the command to look for
+ :type cmd: the type of the command
+ """
+ if commands.has_key(cmd):
+ return commands[cmd]()
+ else:
+ return None
+
+class BaseCommand:
+ def __call__(self, cmdline):
+ try:
+ self.do_command(cmdline.split())
+ except cmdutil.GetHelp, e:
+ self.help()
+ except Exception, e:
+ print e
+
+ def get_completer(index):
+ return None
+
+ def complete(self, args, text):
+ """
+ Returns a list of possible completions for the given text.
+
+ :param args: The complete list of arguments
+ :type args: List of str
+ :param text: text to complete (may be shorter than args[-1])
+ :type text: str
+ :rtype: list of str
+ """
+ matches = []
+ candidates = None
+
+ if len(args) > 0:
+ realtext = args[-1]
+ else:
+ realtext = ""
+
+ try:
+ parser=self.get_parser()
+ if realtext.startswith('-'):
+ candidates = parser.iter_options()
+ else:
+ (options, parsed_args) = parser.parse_args(args)
+
+ if len (parsed_args) > 0:
+ candidates = self.get_completer(parsed_args[-1], len(parsed_args) -1)
+ else:
+ candidates = self.get_completer("", 0)
+ except:
+ pass
+ if candidates is None:
+ return
+ for candidate in candidates:
+ candidate = str(candidate)
+ if candidate.startswith(realtext):
+ matches.append(candidate[len(realtext)- len(text):])
+ return matches
+
+
+class Help(BaseCommand):
+ """
+ Lists commands, prints help messages.
+ """
+ def __init__(self):
+ self.description="Prints help mesages"
+ self.parser = None
+
+ def do_command(self, cmdargs):
+ """
+ Prints a help message.
+ """
+ options, args = self.get_parser().parse_args(cmdargs)
+ if len(args) > 1:
+ raise cmdutil.GetHelp
+
+ if options.native or options.suggestions or options.external:
+ native = options.native
+ suggestions = options.suggestions
+ external = options.external
+ else:
+ native = True
+ suggestions = False
+ external = True
+
+ if len(args) == 0:
+ self.list_commands(native, suggestions, external)
+ return
+ elif len(args) == 1:
+ command_help(args[0])
+ return
+
+ def help(self):
+ self.get_parser().print_help()
+ print """
+If no command is specified, commands are listed. If a command is
+specified, help for that command is listed.
+ """
+
+ def get_parser(self):
+ """
+ Returns the options parser to use for the "revision" command.
+
+ :rtype: cmdutil.CmdOptionParser
+ """
+ if self.parser is not None:
+ return self.parser
+ parser=cmdutil.CmdOptionParser("fai help [command]")
+ parser.add_option("-n", "--native", action="store_true",
+ dest="native", help="Show native commands")
+ parser.add_option("-e", "--external", action="store_true",
+ dest="external", help="Show external commands")
+ parser.add_option("-s", "--suggest", action="store_true",
+ dest="suggestions", help="Show suggestions")
+ self.parser = parser
+ return parser
+
+ def list_commands(self, native=True, suggest=False, external=True):
+ """
+ Lists supported commands.
+
+ :param native: list native, python-based commands
+ :type native: bool
+ :param external: list external aba-style commands
+ :type external: bool
+ """
+ if native:
+ print "Native Fai commands"
+ keys=commands.keys()
+ keys.sort()
+ for k in keys:
+ space=""
+ for i in range(28-len(k)):
+ space+=" "
+ print space+k+" : "+commands[k]().description
+ print
+ if suggest:
+ print "Unavailable commands and suggested alternatives"
+ key_list = suggestions.keys()
+ key_list.sort()
+ for key in key_list:
+ print "%28s : %s" % (key, suggestions[key])
+ print
+ if external:
+ fake_aba = abacmds.AbaCmds()
+ if (fake_aba.abadir == ""):
+ return
+ print "External commands"
+ fake_aba.list_commands()
+ print
+ if not suggest:
+ print "Use help --suggest to list alternatives to tla and aba"\
+ " commands."
+ if options.tla_fallthrough and (native or external):
+ print "Fai also supports tla commands."
+
+def command_help(cmd):
+ """
+ Prints help for a command.
+
+ :param cmd: The name of the command to print help for
+ :type cmd: str
+ """
+ fake_aba = abacmds.AbaCmds()
+ cmdobj = find_command(cmd)
+ if cmdobj != None:
+ cmdobj.help()
+ elif suggestions.has_key(cmd):
+ print "Not available\n" + suggestions[cmd]
+ else:
+ abacmd = fake_aba.is_command(cmd)
+ if abacmd:
+ abacmd.help()
+ else:
+ print "No help is available for \""+cmd+"\". Maybe try \"tla "+cmd+" -H\"?"
+
+
+
+class Changes(BaseCommand):
+ """
+ the "changes" command: lists differences between trees/revisions:
+ """
+
+ def __init__(self):
+ self.description="Lists what files have changed in the project tree"
+
+ def get_completer(self, arg, index):
+ if index > 1:
+ return None
+ try:
+ tree = arch.tree_root()
+ except:
+ tree = None
+ return cmdutil.iter_revision_completions(arg, tree)
+
+ def parse_commandline(self, cmdline):
+ """
+ Parse commandline arguments. Raises cmdutil.GetHelp if help is needed.
+
+ :param cmdline: A list of arguments to parse
+ :rtype: (options, Revision, Revision/WorkingTree)
+ """
+ parser=self.get_parser()
+ (options, args) = parser.parse_args(cmdline)
+ if len(args) > 2:
+ raise cmdutil.GetHelp
+
+ tree=arch.tree_root()
+ if len(args) == 0:
+ a_spec = cmdutil.comp_revision(tree)
+ else:
+ a_spec = cmdutil.determine_revision_tree(tree, args[0])
+ cmdutil.ensure_archive_registered(a_spec.archive)
+ if len(args) == 2:
+ b_spec = cmdutil.determine_revision_tree(tree, args[1])
+ cmdutil.ensure_archive_registered(b_spec.archive)
+ else:
+ b_spec=tree
+ return options, a_spec, b_spec
+
+ def do_command(self, cmdargs):
+ """
+ Master function that perfoms the "changes" command.
+ """
+ try:
+ options, a_spec, b_spec = self.parse_commandline(cmdargs);
+ except cmdutil.CantDetermineRevision, e:
+ print e
+ return
+ except arch.errors.TreeRootError, e:
+ print e
+ return
+ if options.changeset:
+ changeset=options.changeset
+ tmpdir = None
+ else:
+ tmpdir=cmdutil.tmpdir()
+ changeset=tmpdir+"/changeset"
+ try:
+ delta=arch.iter_delta(a_spec, b_spec, changeset)
+ try:
+ for line in delta:
+ if cmdutil.chattermatch(line, "changeset:"):
+ pass
+ else:
+ cmdutil.colorize(line, options.suppress_chatter)
+ except arch.util.ExecProblem, e:
+ if e.proc.error and e.proc.error.startswith(
+ "missing explicit id for file"):
+ raise MissingID(e)
+ else:
+ raise
+ status=delta.status
+ if status > 1:
+ return
+ if (options.perform_diff):
+ chan = cmdutil.ChangesetMunger(changeset)
+ chan.read_indices()
+ if isinstance(b_spec, arch.Revision):
+ b_dir = b_spec.library_find()
+ else:
+ b_dir = b_spec
+ a_dir = a_spec.library_find()
+ if options.diffopts is not None:
+ diffopts = options.diffopts.split()
+ cmdutil.show_custom_diffs(chan, diffopts, a_dir, b_dir)
+ else:
+ cmdutil.show_diffs(delta.changeset)
+ finally:
+ if tmpdir and (os.access(tmpdir, os.X_OK)):
+ shutil.rmtree(tmpdir)
+
+ def get_parser(self):
+ """
+ Returns the options parser to use for the "changes" command.
+
+ :rtype: cmdutil.CmdOptionParser
+ """
+ parser=cmdutil.CmdOptionParser("fai changes [options] [revision]"
+ " [revision]")
+ parser.add_option("-d", "--diff", action="store_true",
+ dest="perform_diff", default=False,
+ help="Show diffs in summary")
+ parser.add_option("-c", "--changeset", dest="changeset",
+ help="Store a changeset in the given directory",
+ metavar="DIRECTORY")
+ parser.add_option("-s", "--silent", action="store_true",
+ dest="suppress_chatter", default=False,
+ help="Suppress chatter messages")
+ parser.add_option("--diffopts", dest="diffopts",
+ help="Use the specified diff options",
+ metavar="OPTIONS")
+
+ return parser
+
+ def help(self, parser=None):
+ """
+ Prints a help message.
+
+ :param parser: If supplied, the parser to use for generating help. If \
+ not supplied, it is retrieved.
+ :type parser: cmdutil.CmdOptionParser
+ """
+ if parser is None:
+ parser=self.get_parser()
+ parser.print_help()
+ print """
+Performs source-tree comparisons
+
+If no revision is specified, the current project tree is compared to the
+last-committed revision. If one revision is specified, the current project
+tree is compared to that revision. If two revisions are specified, they are
+compared to each other.
+ """
+ help_tree_spec()
+ return
+
+
+class ApplyChanges(BaseCommand):
+ """
+ Apply differences between two revisions to a tree
+ """
+
+ def __init__(self):
+ self.description="Applies changes to a project tree"
+
+ def get_completer(self, arg, index):
+ if index > 1:
+ return None
+ try:
+ tree = arch.tree_root()
+ except:
+ tree = None
+ return cmdutil.iter_revision_completions(arg, tree)
+
+ def parse_commandline(self, cmdline, tree):
+ """
+ Parse commandline arguments. Raises cmdutil.GetHelp if help is needed.
+
+ :param cmdline: A list of arguments to parse
+ :rtype: (options, Revision, Revision/WorkingTree)
+ """
+ parser=self.get_parser()
+ (options, args) = parser.parse_args(cmdline)
+ if len(args) != 2:
+ raise cmdutil.GetHelp
+
+ a_spec = cmdutil.determine_revision_tree(tree, args[0])
+ cmdutil.ensure_archive_registered(a_spec.archive)
+ b_spec = cmdutil.determine_revision_tree(tree, args[1])
+ cmdutil.ensure_archive_registered(b_spec.archive)
+ return options, a_spec, b_spec
+
+ def do_command(self, cmdargs):
+ """
+ Master function that performs "apply-changes".
+ """
+ try:
+ tree = arch.tree_root()
+ options, a_spec, b_spec = self.parse_commandline(cmdargs, tree);
+ except cmdutil.CantDetermineRevision, e:
+ print e
+ return
+ except arch.errors.TreeRootError, e:
+ print e
+ return
+ delta=cmdutil.apply_delta(a_spec, b_spec, tree)
+ for line in cmdutil.iter_apply_delta_filter(delta):
+ cmdutil.colorize(line, options.suppress_chatter)
+
+ def get_parser(self):
+ """
+ Returns the options parser to use for the "apply-changes" command.
+
+ :rtype: cmdutil.CmdOptionParser
+ """
+ parser=cmdutil.CmdOptionParser("fai apply-changes [options] revision"
+ " revision")
+ parser.add_option("-d", "--diff", action="store_true",
+ dest="perform_diff", default=False,
+ help="Show diffs in summary")
+ parser.add_option("-c", "--changeset", dest="changeset",
+ help="Store a changeset in the given directory",
+ metavar="DIRECTORY")
+ parser.add_option("-s", "--silent", action="store_true",
+ dest="suppress_chatter", default=False,
+ help="Suppress chatter messages")
+ return parser
+
+ def help(self, parser=None):
+ """
+ Prints a help message.
+
+ :param parser: If supplied, the parser to use for generating help. If \
+ not supplied, it is retrieved.
+ :type parser: cmdutil.CmdOptionParser
+ """
+ if parser is None:
+ parser=self.get_parser()
+ parser.print_help()
+ print """
+Applies changes to a project tree
+
+Compares two revisions and applies the difference between them to the current
+tree.
+ """
+ help_tree_spec()
+ return
+
+class Update(BaseCommand):
+ """
+ Updates a project tree to a given revision, preserving un-committed hanges.
+ """
+
+ def __init__(self):
+ self.description="Apply the latest changes to the current directory"
+
+ def get_completer(self, arg, index):
+ if index > 0:
+ return None
+ try:
+ tree = arch.tree_root()
+ except:
+ tree = None
+ return cmdutil.iter_revision_completions(arg, tree)
+
+ def parse_commandline(self, cmdline, tree):
+ """
+ Parse commandline arguments. Raises cmdutil.GetHelp if help is needed.
+
+ :param cmdline: A list of arguments to parse
+ :rtype: (options, Revision, Revision/WorkingTree)
+ """
+ parser=self.get_parser()
+ (options, args) = parser.parse_args(cmdline)
+ if len(args) > 2:
+ raise cmdutil.GetHelp
+
+ spec=None
+ if len(args)>0:
+ spec=args[0]
+ revision=cmdutil.determine_revision_arch(tree, spec)
+ cmdutil.ensure_archive_registered(revision.archive)
+
+ mirror_source = cmdutil.get_mirror_source(revision.archive)
+ if mirror_source != None:
+ if cmdutil.prompt("Mirror update"):
+ cmd=cmdutil.mirror_archive(mirror_source,
+ revision.archive, arch.NameParser(revision).get_package_version())
+ for line in arch.chatter_classifier(cmd):
+ cmdutil.colorize(line, options.suppress_chatter)
+
+ revision=cmdutil.determine_revision_arch(tree, spec)
+
+ return options, revision
+
+ def do_command(self, cmdargs):
+ """
+ Master function that perfoms the "update" command.
+ """
+ tree=arch.tree_root()
+ try:
+ options, to_revision = self.parse_commandline(cmdargs, tree);
+ except cmdutil.CantDetermineRevision, e:
+ print e
+ return
+ except arch.errors.TreeRootError, e:
+ print e
+ return
+ from_revision=cmdutil.tree_latest(tree)
+ if from_revision==to_revision:
+ print "Tree is already up to date with:\n"+str(to_revision)+"."
+ return
+ cmdutil.ensure_archive_registered(from_revision.archive)
+ cmd=cmdutil.apply_delta(from_revision, to_revision, tree,
+ options.patch_forward)
+ for line in cmdutil.iter_apply_delta_filter(cmd):
+ cmdutil.colorize(line)
+ if to_revision.version != tree.tree_version:
+ if cmdutil.prompt("Update version"):
+ tree.tree_version = to_revision.version
+
+ def get_parser(self):
+ """
+ Returns the options parser to use for the "update" command.
+
+ :rtype: cmdutil.CmdOptionParser
+ """
+ parser=cmdutil.CmdOptionParser("fai update [options]"
+ " [revision/version]")
+ parser.add_option("-f", "--forward", action="store_true",
+ dest="patch_forward", default=False,
+ help="pass the --forward option to 'patch'")
+ parser.add_option("-s", "--silent", action="store_true",
+ dest="suppress_chatter", default=False,
+ help="Suppress chatter messages")
+ return parser
+
+ def help(self, parser=None):
+ """
+ Prints a help message.
+
+ :param parser: If supplied, the parser to use for generating help. If \
+ not supplied, it is retrieved.
+ :type parser: cmdutil.CmdOptionParser
+ """
+ if parser is None:
+ parser=self.get_parser()
+ parser.print_help()
+ print """
+Updates a working tree to the current archive revision
+
+If a revision or version is specified, that is used instead
+ """
+ help_tree_spec()
+ return
+
+
+class Commit(BaseCommand):
+ """
+ Create a revision based on the changes in the current tree.
+ """
+
+ def __init__(self):
+ self.description="Write local changes to the archive"
+
+ def get_completer(self, arg, index):
+ if arg is None:
+ arg = ""
+ return iter_modified_file_completions(arch.tree_root(), arg)
+# return iter_source_file_completions(arch.tree_root(), arg)
+
+ def parse_commandline(self, cmdline, tree):
+ """
+ Parse commandline arguments. Raise cmtutil.GetHelp if help is needed.
+
+ :param cmdline: A list of arguments to parse
+ :rtype: (options, Revision, Revision/WorkingTree)
+ """
+ parser=self.get_parser()
+ (options, args) = parser.parse_args(cmdline)
+
+ if len(args) == 0:
+ args = None
+ revision=cmdutil.determine_revision_arch(tree, options.version)
+ return options, revision.get_version(), args
+
+ def do_command(self, cmdargs):
+ """
+ Master function that perfoms the "commit" command.
+ """
+ tree=arch.tree_root()
+ options, version, files = self.parse_commandline(cmdargs, tree)
+ if options.__dict__.has_key("base") and options.base:
+ base = cmdutil.determine_revision_tree(tree, options.base)
+ else:
+ base = cmdutil.submit_revision(tree)
+
+ writeversion=version
+ archive=version.archive
+ source=cmdutil.get_mirror_source(archive)
+ allow_old=False
+ writethrough="implicit"
+
+ if source!=None:
+ if writethrough=="explicit" and \
+ cmdutil.prompt("Writethrough"):
+ writeversion=arch.Version(str(source)+"/"+str(version.get_nonarch()))
+ elif writethrough=="none":
+ raise CommitToMirror(archive)
+
+ elif archive.is_mirror:
+ raise CommitToMirror(archive)
+
+ try:
+ last_revision=tree.iter_logs(version, True).next().revision
+ except StopIteration, e:
+ if cmdutil.prompt("Import from commit"):
+ return do_import(version)
+ else:
+ raise NoVersionLogs(version)
+ if last_revision!=version.iter_revisions(True).next():
+ if not cmdutil.prompt("Out of date"):
+ raise OutOfDate
+ else:
+ allow_old=True
+
+ try:
+ if not cmdutil.has_changed(version):
+ if not cmdutil.prompt("Empty commit"):
+ raise EmptyCommit
+ except arch.util.ExecProblem, e:
+ if e.proc.error and e.proc.error.startswith(
+ "missing explicit id for file"):
+ raise MissingID(e)
+ else:
+ raise
+ log = tree.log_message(create=False)
+ if log is None:
+ try:
+ if cmdutil.prompt("Create log"):
+ edit_log(tree)
+
+ except cmdutil.NoEditorSpecified, e:
+ raise CommandFailed(e)
+ log = tree.log_message(create=False)
+ if log is None:
+ raise NoLogMessage
+ if log["Summary"] is None or len(log["Summary"].strip()) == 0:
+ if not cmdutil.prompt("Omit log summary"):
+ raise errors.NoLogSummary
+ try:
+ for line in tree.iter_commit(version, seal=options.seal_version,
+ base=base, out_of_date_ok=allow_old, file_list=files):
+ cmdutil.colorize(line, options.suppress_chatter)
+
+ except arch.util.ExecProblem, e:
+ if e.proc.error and e.proc.error.startswith(
+ "These files violate naming conventions:"):
+ raise LintFailure(e.proc.error)
+ else:
+ raise
+
+ def get_parser(self):
+ """
+ Returns the options parser to use for the "commit" command.
+
+ :rtype: cmdutil.CmdOptionParser
+ """
+
+ parser=cmdutil.CmdOptionParser("fai commit [options] [file1]"
+ " [file2...]")
+ parser.add_option("--seal", action="store_true",
+ dest="seal_version", default=False,
+ help="seal this version")
+ parser.add_option("-v", "--version", dest="version",
+ help="Use the specified version",
+ metavar="VERSION")
+ parser.add_option("-s", "--silent", action="store_true",
+ dest="suppress_chatter", default=False,
+ help="Suppress chatter messages")
+ if cmdutil.supports_switch("commit", "--base"):
+ parser.add_option("--base", dest="base", help="",
+ metavar="REVISION")
+ return parser
+
+ def help(self, parser=None):
+ """
+ Prints a help message.
+
+ :param parser: If supplied, the parser to use for generating help. If \
+ not supplied, it is retrieved.
+ :type parser: cmdutil.CmdOptionParser
+ """
+ if parser is None:
+ parser=self.get_parser()
+ parser.print_help()
+ print """
+Updates a working tree to the current archive revision
+
+If a version is specified, that is used instead
+ """
+# help_tree_spec()
+ return
+
+
+
+class CatLog(BaseCommand):
+ """
+ Print the log of a given file (from current tree)
+ """
+ def __init__(self):
+ self.description="Prints the patch log for a revision"
+
+ def get_completer(self, arg, index):
+ if index > 0:
+ return None
+ try:
+ tree = arch.tree_root()
+ except:
+ tree = None
+ return cmdutil.iter_revision_completions(arg, tree)
+
+ def do_command(self, cmdargs):
+ """
+ Master function that perfoms the "cat-log" command.
+ """
+ parser=self.get_parser()
+ (options, args) = parser.parse_args(cmdargs)
+ try:
+ tree = arch.tree_root()
+ except arch.errors.TreeRootError, e:
+ tree = None
+ spec=None
+ if len(args) > 0:
+ spec=args[0]
+ if len(args) > 1:
+ raise cmdutil.GetHelp()
+ try:
+ if tree:
+ revision = cmdutil.determine_revision_tree(tree, spec)
+ else:
+ revision = cmdutil.determine_revision_arch(tree, spec)
+ except cmdutil.CantDetermineRevision, e:
+ raise CommandFailedWrapper(e)
+ log = None
+
+ use_tree = (options.source == "tree" or \
+ (options.source == "any" and tree))
+ use_arch = (options.source == "archive" or options.source == "any")
+
+ log = None
+ if use_tree:
+ for log in tree.iter_logs(revision.get_version()):
+ if log.revision == revision:
+ break
+ else:
+ log = None
+ if log is None and use_arch:
+ cmdutil.ensure_revision_exists(revision)
+ log = arch.Patchlog(revision)
+ if log is not None:
+ for item in log.items():
+ print "%s: %s" % item
+ print log.description
+
+ def get_parser(self):
+ """
+ Returns the options parser to use for the "cat-log" command.
+
+ :rtype: cmdutil.CmdOptionParser
+ """
+ parser=cmdutil.CmdOptionParser("fai cat-log [revision]")
+ parser.add_option("--archive", action="store_const", dest="source",
+ const="archive", default="any",
+ help="Always get the log from the archive")
+ parser.add_option("--tree", action="store_const", dest="source",
+ const="tree", help="Always get the log from the tree")
+ return parser
+
+ def help(self, parser=None):
+ """
+ Prints a help message.
+
+ :param parser: If supplied, the parser to use for generating help. If \
+ not supplied, it is retrieved.
+ :type parser: cmdutil.CmdOptionParser
+ """
+ if parser==None:
+ parser=self.get_parser()
+ parser.print_help()
+ print """
+Prints the log for the specified revision
+ """
+ help_tree_spec()
+ return
+
+class Revert(BaseCommand):
+ """ Reverts a tree (or aspects of it) to a revision
+ """
+ def __init__(self):
+ self.description="Reverts a tree (or aspects of it) to a revision "
+
+ def get_completer(self, arg, index):
+ if index > 0:
+ return None
+ try:
+ tree = arch.tree_root()
+ except:
+ tree = None
+ return iter_modified_file_completions(tree, arg)
+
+ def do_command(self, cmdargs):
+ """
+ Master function that perfoms the "revert" command.
+ """
+ parser=self.get_parser()
+ (options, args) = parser.parse_args(cmdargs)
+ try:
+ tree = arch.tree_root()
+ except arch.errors.TreeRootError, e:
+ raise CommandFailed(e)
+ spec=None
+ if options.revision is not None:
+ spec=options.revision
+ try:
+ if spec is not None:
+ revision = cmdutil.determine_revision_tree(tree, spec)
+ else:
+ revision = cmdutil.comp_revision(tree)
+ except cmdutil.CantDetermineRevision, e:
+ raise CommandFailedWrapper(e)
+ munger = None
+
+ if options.file_contents or options.file_perms or options.deletions\
+ or options.additions or options.renames or options.hunk_prompt:
+ munger = cmdutil.MungeOpts()
+ munger.hunk_prompt = options.hunk_prompt
+
+ if len(args) > 0 or options.logs or options.pattern_files or \
+ options.control:
+ if munger is None:
+ munger = cmdutil.MungeOpts(True)
+ munger.all_types(True)
+ if len(args) > 0:
+ t_cwd = cmdutil.tree_cwd(tree)
+ for name in args:
+ if len(t_cwd) > 0:
+ t_cwd += "/"
+ name = "./" + t_cwd + name
+ munger.add_keep_file(name);
+
+ if options.file_perms:
+ munger.file_perms = True
+ if options.file_contents:
+ munger.file_contents = True
+ if options.deletions:
+ munger.deletions = True
+ if options.additions:
+ munger.additions = True
+ if options.renames:
+ munger.renames = True
+ if options.logs:
+ munger.add_keep_pattern('^\./\{arch\}/[^=].*')
+ if options.control:
+ munger.add_keep_pattern("/\.arch-ids|^\./\{arch\}|"\
+ "/\.arch-inventory$")
+ if options.pattern_files:
+ munger.add_keep_pattern(options.pattern_files)
+
+ for line in cmdutil.revert(tree, revision, munger,
+ not options.no_output):
+ cmdutil.colorize(line)
+
+
+ def get_parser(self):
+ """
+ Returns the options parser to use for the "cat-log" command.
+
+ :rtype: cmdutil.CmdOptionParser
+ """
+ parser=cmdutil.CmdOptionParser("fai revert [options] [FILE...]")
+ parser.add_option("", "--contents", action="store_true",
+ dest="file_contents",
+ help="Revert file content changes")
+ parser.add_option("", "--permissions", action="store_true",
+ dest="file_perms",
+ help="Revert file permissions changes")
+ parser.add_option("", "--deletions", action="store_true",
+ dest="deletions",
+ help="Restore deleted files")
+ parser.add_option("", "--additions", action="store_true",
+ dest="additions",
+ help="Remove added files")
+ parser.add_option("", "--renames", action="store_true",
+ dest="renames",
+ help="Revert file names")
+ parser.add_option("--hunks", action="store_true",
+ dest="hunk_prompt", default=False,
+ help="Prompt which hunks to revert")
+ parser.add_option("--pattern-files", dest="pattern_files",
+ help="Revert files that match this pattern",
+ metavar="REGEX")
+ parser.add_option("--logs", action="store_true",
+ dest="logs", default=False,
+ help="Revert only logs")
+ parser.add_option("--control-files", action="store_true",
+ dest="control", default=False,
+ help="Revert logs and other control files")
+ parser.add_option("-n", "--no-output", action="store_true",
+ dest="no_output",
+ help="Don't keep an undo changeset")
+ parser.add_option("--revision", dest="revision",
+ help="Revert to the specified revision",
+ metavar="REVISION")
+ return parser
+
+ def help(self, parser=None):
+ """
+ Prints a help message.
+
+ :param parser: If supplied, the parser to use for generating help. If \
+ not supplied, it is retrieved.
+ :type parser: cmdutil.CmdOptionParser
+ """
+ if parser==None:
+ parser=self.get_parser()
+ parser.print_help()
+ print """
+Reverts changes in the current working tree. If no flags are specified, all
+types of changes are reverted. Otherwise, only selected types of changes are
+reverted.
+
+If a revision is specified on the commandline, differences between the current
+tree and that revision are reverted. If a version is specified, the current
+tree is used to determine the revision.
+
+If files are specified, only those files listed will have any changes applied.
+To specify a renamed file, you can use either the old or new name. (or both!)
+
+Unless "-n" is specified, reversions can be undone with "redo".
+ """
+ return
+
+class Revision(BaseCommand):
+ """
+ Print a revision name based on a revision specifier
+ """
+ def __init__(self):
+ self.description="Prints the name of a revision"
+
+ def get_completer(self, arg, index):
+ if index > 0:
+ return None
+ try:
+ tree = arch.tree_root()
+ except:
+ tree = None
+ return cmdutil.iter_revision_completions(arg, tree)
+
+ def do_command(self, cmdargs):
+ """
+ Master function that perfoms the "revision" command.
+ """
+ parser=self.get_parser()
+ (options, args) = parser.parse_args(cmdargs)
+
+ try:
+ tree = arch.tree_root()
+ except arch.errors.TreeRootError:
+ tree = None
+
+ spec=None
+ if len(args) > 0:
+ spec=args[0]
+ if len(args) > 1:
+ raise cmdutil.GetHelp
+ try:
+ if tree:
+ revision = cmdutil.determine_revision_tree(tree, spec)
+ else:
+ revision = cmdutil.determine_revision_arch(tree, spec)
+ except cmdutil.CantDetermineRevision, e:
+ print str(e)
+ return
+ print options.display(revision)
+
+ def get_parser(self):
+ """
+ Returns the options parser to use for the "revision" command.
+
+ :rtype: cmdutil.CmdOptionParser
+ """
+ parser=cmdutil.CmdOptionParser("fai revision [revision]")
+ parser.add_option("", "--location", action="store_const",
+ const=paths.determine_path, dest="display",
+ help="Show location instead of name", default=str)
+ parser.add_option("--import", action="store_const",
+ const=paths.determine_import_path, dest="display",
+ help="Show location of import file")
+ parser.add_option("--log", action="store_const",
+ const=paths.determine_log_path, dest="display",
+ help="Show location of log file")
+ parser.add_option("--patch", action="store_const",
+ dest="display", const=paths.determine_patch_path,
+ help="Show location of patchfile")
+ parser.add_option("--continuation", action="store_const",
+ const=paths.determine_continuation_path,
+ dest="display",
+ help="Show location of continuation file")
+ parser.add_option("--cacherev", action="store_const",
+ const=paths.determine_cacherev_path, dest="display",
+ help="Show location of cacherev file")
+ return parser
+
+ def help(self, parser=None):
+ """
+ Prints a help message.
+
+ :param parser: If supplied, the parser to use for generating help. If \
+ not supplied, it is retrieved.
+ :type parser: cmdutil.CmdOptionParser
+ """
+ if parser==None:
+ parser=self.get_parser()
+ parser.print_help()
+ print """
+Expands aliases and prints the name of the specified revision. Instead of
+the name, several options can be used to print locations. If more than one is
+specified, the last one is used.
+ """
+ help_tree_spec()
+ return
+
+def require_version_exists(version, spec):
+ if not version.exists():
+ raise cmdutil.CantDetermineVersion(spec,
+ "The version %s does not exist." \
+ % version)
+
+class Revisions(BaseCommand):
+ """
+ Print a revision name based on a revision specifier
+ """
+ def __init__(self):
+ self.description="Lists revisions"
+
+ def do_command(self, cmdargs):
+ """
+ Master function that perfoms the "revision" command.
+ """
+ (options, args) = self.get_parser().parse_args(cmdargs)
+ if len(args) > 1:
+ raise cmdutil.GetHelp
+ try:
+ self.tree = arch.tree_root()
+ except arch.errors.TreeRootError:
+ self.tree = None
+ try:
+ iter = self.get_iterator(options.type, args, options.reverse,
+ options.modified)
+ except cmdutil.CantDetermineRevision, e:
+ raise CommandFailedWrapper(e)
+
+ if options.skip is not None:
+ iter = cmdutil.iter_skip(iter, int(options.skip))
+
+ for revision in iter:
+ log = None
+ if isinstance(revision, arch.Patchlog):
+ log = revision
+ revision=revision.revision
+ print options.display(revision)
+ if log is None and (options.summary or options.creator or
+ options.date or options.merges):
+ log = revision.patchlog
+ if options.creator:
+ print " %s" % log.creator
+ if options.date:
+ print " %s" % time.strftime('%Y-%m-%d %H:%M:%S %Z', log.date)
+ if options.summary:
+ print " %s" % log.summary
+ if options.merges:
+ showed_title = False
+ for revision in log.merged_patches:
+ if not showed_title:
+ print " Merged:"
+ showed_title = True
+ print " %s" % revision
+
+ def get_iterator(self, type, args, reverse, modified):
+ if len(args) > 0:
+ spec = args[0]
+ else:
+ spec = None
+ if modified is not None:
+ iter = cmdutil.modified_iter(modified, self.tree)
+ if reverse:
+ return iter
+ else:
+ return cmdutil.iter_reverse(iter)
+ elif type == "archive":
+ if spec is None:
+ if self.tree is None:
+ raise cmdutil.CantDetermineRevision("",
+ "Not in a project tree")
+ version = cmdutil.determine_version_tree(spec, self.tree)
+ else:
+ version = cmdutil.determine_version_arch(spec, self.tree)
+ cmdutil.ensure_archive_registered(version.archive)
+ require_version_exists(version, spec)
+ return version.iter_revisions(reverse)
+ elif type == "cacherevs":
+ if spec is None:
+ if self.tree is None:
+ raise cmdutil.CantDetermineRevision("",
+ "Not in a project tree")
+ version = cmdutil.determine_version_tree(spec, self.tree)
+ else:
+ version = cmdutil.determine_version_arch(spec, self.tree)
+ cmdutil.ensure_archive_registered(version.archive)
+ require_version_exists(version, spec)
+ return cmdutil.iter_cacherevs(version, reverse)
+ elif type == "library":
+ if spec is None:
+ if self.tree is None:
+ raise cmdutil.CantDetermineRevision("",
+ "Not in a project tree")
+ version = cmdutil.determine_version_tree(spec, self.tree)
+ else:
+ version = cmdutil.determine_version_arch(spec, self.tree)
+ return version.iter_library_revisions(reverse)
+ elif type == "logs":
+ if self.tree is None:
+ raise cmdutil.CantDetermineRevision("", "Not in a project tree")
+ return self.tree.iter_logs(cmdutil.determine_version_tree(spec, \
+ self.tree), reverse)
+ elif type == "missing" or type == "skip-present":
+ if self.tree is None:
+ raise cmdutil.CantDetermineRevision("", "Not in a project tree")
+ skip = (type == "skip-present")
+ version = cmdutil.determine_version_tree(spec, self.tree)
+ cmdutil.ensure_archive_registered(version.archive)
+ require_version_exists(version, spec)
+ return cmdutil.iter_missing(self.tree, version, reverse,
+ skip_present=skip)
+
+ elif type == "present":
+ if self.tree is None:
+ raise cmdutil.CantDetermineRevision("", "Not in a project tree")
+ version = cmdutil.determine_version_tree(spec, self.tree)
+ cmdutil.ensure_archive_registered(version.archive)
+ require_version_exists(version, spec)
+ return cmdutil.iter_present(self.tree, version, reverse)
+
+ elif type == "new-merges" or type == "direct-merges":
+ if self.tree is None:
+ raise cmdutil.CantDetermineRevision("", "Not in a project tree")
+ version = cmdutil.determine_version_tree(spec, self.tree)
+ cmdutil.ensure_archive_registered(version.archive)
+ require_version_exists(version, spec)
+ iter = cmdutil.iter_new_merges(self.tree, version, reverse)
+ if type == "new-merges":
+ return iter
+ elif type == "direct-merges":
+ return cmdutil.direct_merges(iter)
+
+ elif type == "missing-from":
+ if self.tree is None:
+ raise cmdutil.CantDetermineRevision("", "Not in a project tree")
+ revision = cmdutil.determine_revision_tree(self.tree, spec)
+ libtree = cmdutil.find_or_make_local_revision(revision)
+ return cmdutil.iter_missing(libtree, self.tree.tree_version,
+ reverse)
+
+ elif type == "partner-missing":
+ return cmdutil.iter_partner_missing(self.tree, reverse)
+
+ elif type == "ancestry":
+ revision = cmdutil.determine_revision_tree(self.tree, spec)
+ iter = cmdutil._iter_ancestry(self.tree, revision)
+ if reverse:
+ return iter
+ else:
+ return cmdutil.iter_reverse(iter)
+
+ elif type == "dependencies" or type == "non-dependencies":
+ nondeps = (type == "non-dependencies")
+ revision = cmdutil.determine_revision_tree(self.tree, spec)
+ anc_iter = cmdutil._iter_ancestry(self.tree, revision)
+ iter_depends = cmdutil.iter_depends(anc_iter, nondeps)
+ if reverse:
+ return iter_depends
+ else:
+ return cmdutil.iter_reverse(iter_depends)
+ elif type == "micro":
+ return cmdutil.iter_micro(self.tree)
+
+
+ def get_parser(self):
+ """
+ Returns the options parser to use for the "revision" command.
+
+ :rtype: cmdutil.CmdOptionParser
+ """
+ parser=cmdutil.CmdOptionParser("fai revisions [revision]")
+ select = cmdutil.OptionGroup(parser, "Selection options",
+ "Control which revisions are listed. These options"
+ " are mutually exclusive. If more than one is"
+ " specified, the last is used.")
+ select.add_option("", "--archive", action="store_const",
+ const="archive", dest="type", default="archive",
+ help="List all revisions in the archive")
+ select.add_option("", "--cacherevs", action="store_const",
+ const="cacherevs", dest="type",
+ help="List all revisions stored in the archive as "
+ "complete copies")
+ select.add_option("", "--logs", action="store_const",
+ const="logs", dest="type",
+ help="List revisions that have a patchlog in the "
+ "tree")
+ select.add_option("", "--missing", action="store_const",
+ const="missing", dest="type",
+ help="List revisions from the specified version that"
+ " have no patchlog in the tree")
+ select.add_option("", "--skip-present", action="store_const",
+ const="skip-present", dest="type",
+ help="List revisions from the specified version that"
+ " have no patchlogs at all in the tree")
+ select.add_option("", "--present", action="store_const",
+ const="present", dest="type",
+ help="List revisions from the specified version that"
+ " have no patchlog in the tree, but can't be merged")
+ select.add_option("", "--missing-from", action="store_const",
+ const="missing-from", dest="type",
+ help="List revisions from the specified revision "
+ "that have no patchlog for the tree version")
+ select.add_option("", "--partner-missing", action="store_const",
+ const="partner-missing", dest="type",
+ help="List revisions in partner versions that are"
+ " missing")
+ select.add_option("", "--new-merges", action="store_const",
+ const="new-merges", dest="type",
+ help="List revisions that have had patchlogs added"
+ " to the tree since the last commit")
+ select.add_option("", "--direct-merges", action="store_const",
+ const="direct-merges", dest="type",
+ help="List revisions that have been directly added"
+ " to tree since the last commit ")
+ select.add_option("", "--library", action="store_const",
+ const="library", dest="type",
+ help="List revisions in the revision library")
+ select.add_option("", "--ancestry", action="store_const",
+ const="ancestry", dest="type",
+ help="List revisions that are ancestors of the "
+ "current tree version")
+
+ select.add_option("", "--dependencies", action="store_const",
+ const="dependencies", dest="type",
+ help="List revisions that the given revision "
+ "depends on")
+
+ select.add_option("", "--non-dependencies", action="store_const",
+ const="non-dependencies", dest="type",
+ help="List revisions that the given revision "
+ "does not depend on")
+
+ select.add_option("--micro", action="store_const",
+ const="micro", dest="type",
+ help="List partner revisions aimed for this "
+ "micro-branch")
+
+ select.add_option("", "--modified", dest="modified",
+ help="List tree ancestor revisions that modified a "
+ "given file", metavar="FILE[:LINE]")
+
+ parser.add_option("", "--skip", dest="skip",
+ help="Skip revisions. Positive numbers skip from "
+ "beginning, negative skip from end.",
+ metavar="NUMBER")
+
+ parser.add_option_group(select)
+
+ format = cmdutil.OptionGroup(parser, "Revision format options",
+ "These control the appearance of listed revisions")
+ format.add_option("", "--location", action="store_const",
+ const=paths.determine_path, dest="display",
+ help="Show location instead of name", default=str)
+ format.add_option("--import", action="store_const",
+ const=paths.determine_import_path, dest="display",
+ help="Show location of import file")
+ format.add_option("--log", action="store_const",
+ const=paths.determine_log_path, dest="display",
+ help="Show location of log file")
+ format.add_option("--patch", action="store_const",
+ dest="display", const=paths.determine_patch_path,
+ help="Show location of patchfile")
+ format.add_option("--continuation", action="store_const",
+ const=paths.determine_continuation_path,
+ dest="display",
+ help="Show location of continuation file")
+ format.add_option("--cacherev", action="store_const",
+ const=paths.determine_cacherev_path, dest="display",
+ help="Show location of cacherev file")
+ parser.add_option_group(format)
+ display = cmdutil.OptionGroup(parser, "Display format options",
+ "These control the display of data")
+ display.add_option("-r", "--reverse", action="store_true",
+ dest="reverse", help="Sort from newest to oldest")
+ display.add_option("-s", "--summary", action="store_true",
+ dest="summary", help="Show patchlog summary")
+ display.add_option("-D", "--date", action="store_true",
+ dest="date", help="Show patchlog date")
+ display.add_option("-c", "--creator", action="store_true",
+ dest="creator", help="Show the id that committed the"
+ " revision")
+ display.add_option("-m", "--merges", action="store_true",
+ dest="merges", help="Show the revisions that were"
+ " merged")
+ parser.add_option_group(display)
+ return parser
+ def help(self, parser=None):
+ """Attempt to explain the revisions command
+
+ :param parser: If supplied, used to determine options
+ """
+ if parser==None:
+ parser=self.get_parser()
+ parser.print_help()
+ print """List revisions.
+ """
+ help_tree_spec()
+
+
+class Get(BaseCommand):
+ """
+ Retrieve a revision from the archive
+ """
+ def __init__(self):
+ self.description="Retrieve a revision from the archive"
+ self.parser=self.get_parser()
+
+
+ def get_completer(self, arg, index):
+ if index > 0:
+ return None
+ try:
+ tree = arch.tree_root()
+ except:
+ tree = None
+ return cmdutil.iter_revision_completions(arg, tree)
+
+
+ def do_command(self, cmdargs):
+ """
+ Master function that perfoms the "get" command.
+ """
+ (options, args) = self.parser.parse_args(cmdargs)
+ if len(args) < 1:
+ return self.help()
+ try:
+ tree = arch.tree_root()
+ except arch.errors.TreeRootError:
+ tree = None
+
+ arch_loc = None
+ try:
+ revision, arch_loc = paths.full_path_decode(args[0])
+ except Exception, e:
+ revision = cmdutil.determine_revision_arch(tree, args[0],
+ check_existence=False, allow_package=True)
+ if len(args) > 1:
+ directory = args[1]
+ else:
+ directory = str(revision.nonarch)
+ if os.path.exists(directory):
+ raise DirectoryExists(directory)
+ cmdutil.ensure_archive_registered(revision.archive, arch_loc)
+ try:
+ cmdutil.ensure_revision_exists(revision)
+ except cmdutil.NoSuchRevision, e:
+ raise CommandFailedWrapper(e)
+
+ link = cmdutil.prompt ("get link")
+ for line in cmdutil.iter_get(revision, directory, link,
+ options.no_pristine,
+ options.no_greedy_add):
+ cmdutil.colorize(line)
+
+ def get_parser(self):
+ """
+ Returns the options parser to use for the "get" command.
+
+ :rtype: cmdutil.CmdOptionParser
+ """
+ parser=cmdutil.CmdOptionParser("fai get revision [dir]")
+ parser.add_option("--no-pristine", action="store_true",
+ dest="no_pristine",
+ help="Do not make pristine copy for reference")
+ parser.add_option("--no-greedy-add", action="store_true",
+ dest="no_greedy_add",
+ help="Never add to greedy libraries")
+
+ return parser
+
+ def help(self, parser=None):
+ """
+ Prints a help message.
+
+ :param parser: If supplied, the parser to use for generating help. If \
+ not supplied, it is retrieved.
+ :type parser: cmdutil.CmdOptionParser
+ """
+ if parser==None:
+ parser=self.get_parser()
+ parser.print_help()
+ print """
+Expands aliases and constructs a project tree for a revision. If the optional
+"dir" argument is provided, the project tree will be stored in this directory.
+ """
+ help_tree_spec()
+ return
+
+class PromptCmd(cmd.Cmd):
+ def __init__(self):
+ cmd.Cmd.__init__(self)
+ self.prompt = "Fai> "
+ try:
+ self.tree = arch.tree_root()
+ except:
+ self.tree = None
+ self.set_title()
+ self.set_prompt()
+ self.fake_aba = abacmds.AbaCmds()
+ self.identchars += '-'
+ self.history_file = os.path.expanduser("~/.fai-history")
+ readline.set_completer_delims(string.whitespace)
+ if os.access(self.history_file, os.R_OK) and \
+ os.path.isfile(self.history_file):
+ readline.read_history_file(self.history_file)
+
+ def write_history(self):
+ readline.write_history_file(self.history_file)
+
+ def do_quit(self, args):
+ self.write_history()
+ sys.exit(0)
+
+ def do_exit(self, args):
+ self.do_quit(args)
+
+ def do_EOF(self, args):
+ print
+ self.do_quit(args)
+
+ def postcmd(self, line, bar):
+ self.set_title()
+ self.set_prompt()
+
+ def set_prompt(self):
+ if self.tree is not None:
+ try:
+ version = " "+self.tree.tree_version.nonarch
+ except:
+ version = ""
+ else:
+ version = ""
+ self.prompt = "Fai%s> " % version
+
+ def set_title(self, command=None):
+ try:
+ version = self.tree.tree_version.nonarch
+ except:
+ version = "[no version]"
+ if command is None:
+ command = ""
+ sys.stdout.write(terminal.term_title("Fai %s %s" % (command, version)))
+
+ def do_cd(self, line):
+ if line == "":
+ line = "~"
+ try:
+ os.chdir(os.path.expanduser(line))
+ except Exception, e:
+ print e
+ try:
+ self.tree = arch.tree_root()
+ except:
+ self.tree = None
+
+ def do_help(self, line):
+ Help()(line)
+
+ def default(self, line):
+ args = line.split()
+ if find_command(args[0]):
+ try:
+ find_command(args[0]).do_command(args[1:])
+ except cmdutil.BadCommandOption, e:
+ print e
+ except cmdutil.GetHelp, e:
+ find_command(args[0]).help()
+ except CommandFailed, e:
+ print e
+ except arch.errors.ArchiveNotRegistered, e:
+ print e
+ except KeyboardInterrupt, e:
+ print "Interrupted"
+ except arch.util.ExecProblem, e:
+ print e.proc.error.rstrip('\n')
+ except cmdutil.CantDetermineVersion, e:
+ print e
+ except cmdutil.CantDetermineRevision, e:
+ print e
+ except Exception, e:
+ print "Unhandled error:\n%s" % cmdutil.exception_str(e)
+
+ elif suggestions.has_key(args[0]):
+ print suggestions[args[0]]
+
+ elif self.fake_aba.is_command(args[0]):
+ tree = None
+ try:
+ tree = arch.tree_root()
+ except arch.errors.TreeRootError:
+ pass
+ cmd = self.fake_aba.is_command(args[0])
+ try:
+ cmd.run(cmdutil.expand_prefix_alias(args[1:], tree))
+ except KeyboardInterrupt, e:
+ print "Interrupted"
+
+ elif options.tla_fallthrough and args[0] != "rm" and \
+ cmdutil.is_tla_command(args[0]):
+ try:
+ tree = None
+ try:
+ tree = arch.tree_root()
+ except arch.errors.TreeRootError:
+ pass
+ args = cmdutil.expand_prefix_alias(args, tree)
+ arch.util.exec_safe('tla', args, stderr=sys.stderr,
+ expected=(0, 1))
+ except arch.util.ExecProblem, e:
+ pass
+ except KeyboardInterrupt, e:
+ print "Interrupted"
+ else:
+ try:
+ try:
+ tree = arch.tree_root()
+ except arch.errors.TreeRootError:
+ tree = None
+ args=line.split()
+ os.system(" ".join(cmdutil.expand_prefix_alias(args, tree)))
+ except KeyboardInterrupt, e:
+ print "Interrupted"
+
+ def completenames(self, text, line, begidx, endidx):
+ completions = []
+ iter = iter_command_names(self.fake_aba)
+ try:
+ if len(line) > 0:
+ arg = line.split()[-1]
+ else:
+ arg = ""
+ iter = iter_munged_completions(iter, arg, text)
+ except Exception, e:
+ print e
+ return list(iter)
+
+ def completedefault(self, text, line, begidx, endidx):
+ """Perform completion for native commands.
+
+ :param text: The text to complete
+ :type text: str
+ :param line: The entire line to complete
+ :type line: str
+ :param begidx: The start of the text in the line
+ :type begidx: int
+ :param endidx: The end of the text in the line
+ :type endidx: int
+ """
+ try:
+ (cmd, args, foo) = self.parseline(line)
+ command_obj=find_command(cmd)
+ if command_obj is not None:
+ return command_obj.complete(args.split(), text)
+ elif not self.fake_aba.is_command(cmd) and \
+ cmdutil.is_tla_command(cmd):
+ iter = cmdutil.iter_supported_switches(cmd)
+ if len(args) > 0:
+ arg = args.split()[-1]
+ else:
+ arg = ""
+ if arg.startswith("-"):
+ return list(iter_munged_completions(iter, arg, text))
+ else:
+ return list(iter_munged_completions(
+ iter_file_completions(arg), arg, text))
+
+
+ elif cmd == "cd":
+ if len(args) > 0:
+ arg = args.split()[-1]
+ else:
+ arg = ""
+ iter = iter_dir_completions(arg)
+ iter = iter_munged_completions(iter, arg, text)
+ return list(iter)
+ elif len(args)>0:
+ arg = args.split()[-1]
+ return list(iter_munged_completions(iter_file_completions(arg),
+ arg, text))
+ else:
+ return self.completenames(text, line, begidx, endidx)
+ except Exception, e:
+ print e
+
+
+def iter_command_names(fake_aba):
+ for entry in cmdutil.iter_combine([commands.iterkeys(),
+ fake_aba.get_commands(),
+ cmdutil.iter_tla_commands(False)]):
+ if not suggestions.has_key(str(entry)):
+ yield entry
+
+
+def iter_file_completions(arg, only_dirs = False):
+ """Generate an iterator that iterates through filename completions.
+
+ :param arg: The filename fragment to match
+ :type arg: str
+ :param only_dirs: If true, match only directories
+ :type only_dirs: bool
+ """
+ cwd = os.getcwd()
+ if cwd != "/":
+ extras = [".", ".."]
+ else:
+ extras = []
+ (dir, file) = os.path.split(arg)
+ if dir != "":
+ listingdir = os.path.expanduser(dir)
+ else:
+ listingdir = cwd
+ for file in cmdutil.iter_combine([os.listdir(listingdir), extras]):
+ if dir != "":
+ userfile = dir+'/'+file
+ else:
+ userfile = file
+ if userfile.startswith(arg):
+ if os.path.isdir(listingdir+'/'+file):
+ userfile+='/'
+ yield userfile
+ elif not only_dirs:
+ yield userfile
+
+def iter_munged_completions(iter, arg, text):
+ for completion in iter:
+ completion = str(completion)
+ if completion.startswith(arg):
+ yield completion[len(arg)-len(text):]
+
+def iter_source_file_completions(tree, arg):
+ treepath = cmdutil.tree_cwd(tree)
+ if len(treepath) > 0:
+ dirs = [treepath]
+ else:
+ dirs = None
+ for file in tree.iter_inventory(dirs, source=True, both=True):
+ file = file_completion_match(file, treepath, arg)
+ if file is not None:
+ yield file
+
+
+def iter_untagged(tree, dirs):
+ for file in arch_core.iter_inventory_filter(tree, dirs, tagged=False,
+ categories=arch_core.non_root,
+ control_files=True):
+ yield file.name
+
+
+def iter_untagged_completions(tree, arg):
+ """Generate an iterator for all visible untagged files that match arg.
+
+ :param tree: The tree to look for untagged files in
+ :type tree: `arch.WorkingTree`
+ :param arg: The argument to match
+ :type arg: str
+ :return: An iterator of all matching untagged files
+ :rtype: iterator of str
+ """
+ treepath = cmdutil.tree_cwd(tree)
+ if len(treepath) > 0:
+ dirs = [treepath]
+ else:
+ dirs = None
+
+ for file in iter_untagged(tree, dirs):
+ file = file_completion_match(file, treepath, arg)
+ if file is not None:
+ yield file
+
+
+def file_completion_match(file, treepath, arg):
+ """Determines whether a file within an arch tree matches the argument.
+
+ :param file: The rooted filename
+ :type file: str
+ :param treepath: The path to the cwd within the tree
+ :type treepath: str
+ :param arg: The prefix to match
+ :return: The completion name, or None if not a match
+ :rtype: str
+ """
+ if not file.startswith(treepath):
+ return None
+ if treepath != "":
+ file = file[len(treepath)+1:]
+
+ if not file.startswith(arg):
+ return None
+ if os.path.isdir(file):
+ file += '/'
+ return file
+
+def iter_modified_file_completions(tree, arg):
+ """Returns a list of modified files that match the specified prefix.
+
+ :param tree: The current tree
+ :type tree: `arch.WorkingTree`
+ :param arg: The prefix to match
+ :type arg: str
+ """
+ treepath = cmdutil.tree_cwd(tree)
+ tmpdir = cmdutil.tmpdir()
+ changeset = tmpdir+"/changeset"
+ completions = []
+ revision = cmdutil.determine_revision_tree(tree)
+ for line in arch.iter_delta(revision, tree, changeset):
+ if isinstance(line, arch.FileModification):
+ file = file_completion_match(line.name[1:], treepath, arg)
+ if file is not None:
+ completions.append(file)
+ shutil.rmtree(tmpdir)
+ return completions
+
+def iter_dir_completions(arg):
+ """Generate an iterator that iterates through directory name completions.
+
+ :param arg: The directory name fragment to match
+ :type arg: str
+ """
+ return iter_file_completions(arg, True)
+
+class Shell(BaseCommand):
+ def __init__(self):
+ self.description = "Runs Fai as a shell"
+
+ def do_command(self, cmdargs):
+ if len(cmdargs)!=0:
+ raise cmdutil.GetHelp
+ prompt = PromptCmd()
+ try:
+ prompt.cmdloop()
+ finally:
+ prompt.write_history()
+
+class AddID(BaseCommand):
+ """
+ Adds an inventory id for the given file
+ """
+ def __init__(self):
+ self.description="Add an inventory id for a given file"
+
+ def get_completer(self, arg, index):
+ tree = arch.tree_root()
+ return iter_untagged_completions(tree, arg)
+
+ def do_command(self, cmdargs):
+ """
+ Master function that perfoms the "revision" command.
+ """
+ parser=self.get_parser()
+ (options, args) = parser.parse_args(cmdargs)
+
+ tree = arch.tree_root()
+
+ if (len(args) == 0) == (options.untagged == False):
+ raise cmdutil.GetHelp
+
+ #if options.id and len(args) != 1:
+ # print "If --id is specified, only one file can be named."
+ # return
+
+ method = tree.tagging_method
+
+ if options.id_type == "tagline":
+ if method != "tagline":
+ if not cmdutil.prompt("Tagline in other tree"):
+ if method == "explicit":
+ options.id_type == explicit
+ else:
+ print "add-id not supported for \"%s\" tagging method"\
+ % method
+ return
+
+ elif options.id_type == "explicit":
+ if method != "tagline" and method != explicit:
+ if not prompt("Explicit in other tree"):
+ print "add-id not supported for \"%s\" tagging method" % \
+ method
+ return
+
+ if options.id_type == "auto":
+ if method != "tagline" and method != "explicit":
+ print "add-id not supported for \"%s\" tagging method" % method
+ return
+ else:
+ options.id_type = method
+ if options.untagged:
+ args = None
+ self.add_ids(tree, options.id_type, args)
+
+ def add_ids(self, tree, id_type, files=()):
+ """Add inventory ids to files.
+
+ :param tree: the tree the files are in
+ :type tree: `arch.WorkingTree`
+ :param id_type: the type of id to add: "explicit" or "tagline"
+ :type id_type: str
+ :param files: The list of files to add. If None do all untagged.
+ :type files: tuple of str
+ """
+
+ untagged = (files is None)
+ if untagged:
+ files = list(iter_untagged(tree, None))
+ previous_files = []
+ while len(files) > 0:
+ previous_files.extend(files)
+ if id_type == "explicit":
+ cmdutil.add_id(files)
+ elif id_type == "tagline":
+ for file in files:
+ try:
+ cmdutil.add_tagline_or_explicit_id(file)
+ except cmdutil.AlreadyTagged:
+ print "\"%s\" already has a tagline." % file
+ except cmdutil.NoCommentSyntax:
+ pass
+ #do inventory after tagging until no untagged files are encountered
+ if untagged:
+ files = []
+ for file in iter_untagged(tree, None):
+ if not file in previous_files:
+ files.append(file)
+
+ else:
+ break
+
+ def get_parser(self):
+ """
+ Returns the options parser to use for the "revision" command.
+
+ :rtype: cmdutil.CmdOptionParser
+ """
+ parser=cmdutil.CmdOptionParser("fai add-id file1 [file2] [file3]...")
+# ddaa suggests removing this to promote GUIDs. Let's see who squalks.
+# parser.add_option("-i", "--id", dest="id",
+# help="Specify id for a single file", default=None)
+ parser.add_option("--tltl", action="store_true",
+ dest="lord_style", help="Use Tom Lord's style of id.")
+ parser.add_option("--explicit", action="store_const",
+ const="explicit", dest="id_type",
+ help="Use an explicit id", default="auto")
+ parser.add_option("--tagline", action="store_const",
+ const="tagline", dest="id_type",
+ help="Use a tagline id")
+ parser.add_option("--untagged", action="store_true",
+ dest="untagged", default=False,
+ help="tag all untagged files")
+ return parser
+
+ def help(self, parser=None):
+ """
+ Prints a help message.
+
+ :param parser: If supplied, the parser to use for generating help. If \
+ not supplied, it is retrieved.
+ :type parser: cmdutil.CmdOptionParser
+ """
+ if parser==None:
+ parser=self.get_parser()
+ parser.print_help()
+ print """
+Adds an inventory to the specified file(s) and directories. If --untagged is
+specified, adds inventory to all untagged files and directories.
+ """
+ return
+
+
+class Merge(BaseCommand):
+ """
+ Merges changes from other versions into the current tree
+ """
+ def __init__(self):
+ self.description="Merges changes from other versions"
+ try:
+ self.tree = arch.tree_root()
+ except:
+ self.tree = None
+
+
+ def get_completer(self, arg, index):
+ if self.tree is None:
+ raise arch.errors.TreeRootError
+ completions = list(ancillary.iter_partners(self.tree,
+ self.tree.tree_version))
+ if len(completions) == 0:
+ completions = list(self.tree.iter_log_versions())
+
+ aliases = []
+ try:
+ for completion in completions:
+ alias = ancillary.compact_alias(str(completion), self.tree)
+ if alias:
+ aliases.extend(alias)
+
+ for completion in completions:
+ if completion.archive == self.tree.tree_version.archive:
+ aliases.append(completion.nonarch)
+
+ except Exception, e:
+ print e
+
+ completions.extend(aliases)
+ return completions
+
+ def do_command(self, cmdargs):
+ """
+ Master function that perfoms the "merge" command.
+ """
+ parser=self.get_parser()
+ (options, args) = parser.parse_args(cmdargs)
+ if options.diff3:
+ action="star-merge"
+ else:
+ action = options.action
+
+ if self.tree is None:
+ raise arch.errors.TreeRootError(os.getcwd())
+ if cmdutil.has_changed(self.tree.tree_version):
+ raise UncommittedChanges(self.tree)
+
+ if len(args) > 0:
+ revisions = []
+ for arg in args:
+ revisions.append(cmdutil.determine_revision_arch(self.tree,
+ arg))
+ source = "from commandline"
+ else:
+ revisions = ancillary.iter_partner_revisions(self.tree,
+ self.tree.tree_version)
+ source = "from partner version"
+ revisions = misc.rewind_iterator(revisions)
+ try:
+ revisions.next()
+ revisions.rewind()
+ except StopIteration, e:
+ revision = cmdutil.tag_cur(self.tree)
+ if revision is None:
+ raise CantDetermineRevision("", "No version specified, no "
+ "partner-versions, and no tag"
+ " source")
+ revisions = [revision]
+ source = "from tag source"
+ for revision in revisions:
+ cmdutil.ensure_archive_registered(revision.archive)
+ cmdutil.colorize(arch.Chatter("* Merging %s [%s]" %
+ (revision, source)))
+ if action=="native-merge" or action=="update":
+ if self.native_merge(revision, action) == 0:
+ continue
+ elif action=="star-merge":
+ try:
+ self.star_merge(revision, options.diff3)
+ except errors.MergeProblem, e:
+ break
+ if cmdutil.has_changed(self.tree.tree_version):
+ break
+
+ def star_merge(self, revision, diff3):
+ """Perform a star-merge on the current tree.
+
+ :param revision: The revision to use for the merge
+ :type revision: `arch.Revision`
+ :param diff3: If true, do a diff3 merge
+ :type diff3: bool
+ """
+ try:
+ for line in self.tree.iter_star_merge(revision, diff3=diff3):
+ cmdutil.colorize(line)
+ except arch.util.ExecProblem, e:
+ if e.proc.status is not None and e.proc.status == 1:
+ if e.proc.error:
+ print e.proc.error
+ raise MergeProblem
+ else:
+ raise
+
+ def native_merge(self, other_revision, action):
+ """Perform a native-merge on the current tree.
+
+ :param other_revision: The revision to use for the merge
+ :type other_revision: `arch.Revision`
+ :return: 0 if the merge was skipped, 1 if it was applied
+ """
+ other_tree = cmdutil.find_or_make_local_revision(other_revision)
+ try:
+ if action == "native-merge":
+ ancestor = cmdutil.merge_ancestor2(self.tree, other_tree,
+ other_revision)
+ elif action == "update":
+ ancestor = cmdutil.tree_latest(self.tree,
+ other_revision.version)
+ except CantDetermineRevision, e:
+ raise CommandFailedWrapper(e)
+ cmdutil.colorize(arch.Chatter("* Found common ancestor %s" % ancestor))
+ if (ancestor == other_revision):
+ cmdutil.colorize(arch.Chatter("* Skipping redundant merge"
+ % ancestor))
+ return 0
+ delta = cmdutil.apply_delta(ancestor, other_tree, self.tree)
+ for line in cmdutil.iter_apply_delta_filter(delta):
+ cmdutil.colorize(line)
+ return 1
+
+
+
+ def get_parser(self):
+ """
+ Returns the options parser to use for the "merge" command.
+
+ :rtype: cmdutil.CmdOptionParser
+ """
+ parser=cmdutil.CmdOptionParser("fai merge [VERSION]")
+ parser.add_option("-s", "--star-merge", action="store_const",
+ dest="action", help="Use star-merge",
+ const="star-merge", default="native-merge")
+ parser.add_option("--update", action="store_const",
+ dest="action", help="Use update picker",
+ const="update")
+ parser.add_option("--diff3", action="store_true",
+ dest="diff3",
+ help="Use diff3 for merge (implies star-merge)")
+ return parser
+
+ def help(self, parser=None):
+ """
+ Prints a help message.
+
+ :param parser: If supplied, the parser to use for generating help. If \
+ not supplied, it is retrieved.
+ :type parser: cmdutil.CmdOptionParser
+ """
+ if parser==None:
+ parser=self.get_parser()
+ parser.print_help()
+ print """
+Performs a merge operation using the specified version.
+ """
+ return
+
+class ELog(BaseCommand):
+ """
+ Produces a raw patchlog and invokes the user's editor
+ """
+ def __init__(self):
+ self.description="Edit a patchlog to commit"
+ try:
+ self.tree = arch.tree_root()
+ except:
+ self.tree = None
+
+
+ def do_command(self, cmdargs):
+ """
+ Master function that perfoms the "elog" command.
+ """
+ parser=self.get_parser()
+ (options, args) = parser.parse_args(cmdargs)
+ if self.tree is None:
+ raise arch.errors.TreeRootError
+
+ edit_log(self.tree)
+
+ def get_parser(self):
+ """
+ Returns the options parser to use for the "merge" command.
+
+ :rtype: cmdutil.CmdOptionParser
+ """
+ parser=cmdutil.CmdOptionParser("fai elog")
+ return parser
+
+
+ def help(self, parser=None):
+ """
+ Invokes $EDITOR to produce a log for committing.
+
+ :param parser: If supplied, the parser to use for generating help. If \
+ not supplied, it is retrieved.
+ :type parser: cmdutil.CmdOptionParser
+ """
+ if parser==None:
+ parser=self.get_parser()
+ parser.print_help()
+ print """
+Invokes $EDITOR to produce a log for committing.
+ """
+ return
+
+def edit_log(tree):
+ """Makes and edits the log for a tree. Does all kinds of fancy things
+ like log templates and merge summaries and log-for-merge
+
+ :param tree: The tree to edit the log for
+ :type tree: `arch.WorkingTree`
+ """
+ #ensure we have an editor before preparing the log
+ cmdutil.find_editor()
+ log = tree.log_message(create=False)
+ log_is_new = False
+ if log is None or cmdutil.prompt("Overwrite log"):
+ if log is not None:
+ os.remove(log.name)
+ log = tree.log_message(create=True)
+ log_is_new = True
+ tmplog = log.name
+ template = tree+"/{arch}/=log-template"
+ if not os.path.exists(template):
+ template = os.path.expanduser("~/.arch-params/=log-template")
+ if not os.path.exists(template):
+ template = None
+ if template:
+ shutil.copyfile(template, tmplog)
+
+ new_merges = list(cmdutil.iter_new_merges(tree,
+ tree.tree_version))
+ log["Summary"] = merge_summary(new_merges, tree.tree_version)
+ if len(new_merges) > 0:
+ if cmdutil.prompt("Log for merge"):
+ mergestuff = cmdutil.log_for_merge(tree)
+ log.description += mergestuff
+ log.save()
+ try:
+ cmdutil.invoke_editor(log.name)
+ except:
+ if log_is_new:
+ os.remove(log.name)
+ raise
+
+def merge_summary(new_merges, tree_version):
+ if len(new_merges) == 0:
+ return ""
+ if len(new_merges) == 1:
+ summary = new_merges[0].summary
+ else:
+ summary = "Merge"
+
+ credits = []
+ for merge in new_merges:
+ if arch.my_id() != merge.creator:
+ name = re.sub("<.*>", "", merge.creator).rstrip(" ");
+ if not name in credits:
+ credits.append(name)
+ else:
+ version = merge.revision.version
+ if version.archive == tree_version.archive:
+ if not version.nonarch in credits:
+ credits.append(version.nonarch)
+ elif not str(version) in credits:
+ credits.append(str(version))
+
+ return ("%s (%s)") % (summary, ", ".join(credits))
+
+class MirrorArchive(BaseCommand):
+ """
+ Updates a mirror from an archive
+ """
+ def __init__(self):
+ self.description="Update a mirror from an archive"
+
+ def do_command(self, cmdargs):
+ """
+ Master function that perfoms the "revision" command.
+ """
+
+ parser=self.get_parser()
+ (options, args) = parser.parse_args(cmdargs)
+ if len(args) > 1:
+ raise GetHelp
+ try:
+ tree = arch.tree_root()
+ except:
+ tree = None
+
+ if len(args) == 0:
+ if tree is not None:
+ name = tree.tree_version()
+ else:
+ name = cmdutil.expand_alias(args[0], tree)
+ name = arch.NameParser(name)
+
+ to_arch = name.get_archive()
+ from_arch = cmdutil.get_mirror_source(arch.Archive(to_arch))
+ limit = name.get_nonarch()
+
+ iter = arch_core.mirror_archive(from_arch,to_arch, limit)
+ for line in arch.chatter_classifier(iter):
+ cmdutil.colorize(line)
+
+ def get_parser(self):
+ """
+ Returns the options parser to use for the "revision" command.
+
+ :rtype: cmdutil.CmdOptionParser
+ """
+ parser=cmdutil.CmdOptionParser("fai mirror-archive ARCHIVE")
+ return parser
+
+ def help(self, parser=None):
+ """
+ Prints a help message.
+
+ :param parser: If supplied, the parser to use for generating help. If \
+ not supplied, it is retrieved.
+ :type parser: cmdutil.CmdOptionParser
+ """
+ if parser==None:
+ parser=self.get_parser()
+ parser.print_help()
+ print """
+Updates a mirror from an archive. If a branch, package, or version is
+supplied, only changes under it are mirrored.
+ """
+ return
+
+def help_tree_spec():
+ print """Specifying revisions (default: tree)
+Revisions may be specified by alias, revision, version or patchlevel.
+Revisions or versions may be fully qualified. Unqualified revisions, versions,
+or patchlevels use the archive of the current project tree. Versions will
+use the latest patchlevel in the tree. Patchlevels will use the current tree-
+version.
+
+Use "alias" to list available (user and automatic) aliases."""
+
+def help_aliases(tree):
+ print """Auto-generated aliases
+ acur : The latest revision in the archive of the tree-version. You can specfy
+ a different version like so: acur:foo--bar--0 (aliases can be used)
+ tcur : (tree current) The latest revision in the tree of the tree-version.
+ You can specify a different version like so: tcur:foo--bar--0 (aliases
+ can be used).
+tprev : (tree previous) The previous revision in the tree of the tree-version.
+ To specify an older revision, use a number, e.g. "tprev:4"
+ tanc : (tree ancestor) The ancestor revision of the tree
+ To specify an older revision, use a number, e.g. "tanc:4"
+tdate : (tree date) The latest revision from a given date (e.g. "tdate:July 6")
+ tmod : (tree modified) The latest revision to modify a given file
+ (e.g. "tmod:engine.cpp" or "tmod:engine.cpp:16")
+ ttag : (tree tag) The revision that was tagged into the current tree revision,
+ according to the tree.
+tagcur: (tag current) The latest revision of the version that the current tree
+ was tagged from.
+mergeanc : The common ancestor of the current tree and the specified revision.
+ Defaults to the first partner-version's latest revision or to tagcur.
+ """
+ print "User aliases"
+ for parts in ancillary.iter_all_alias(tree):
+ print parts[0].rjust(10)+" : "+parts[1]
+
+
+class Inventory(BaseCommand):
+ """List the status of files in the tree"""
+ def __init__(self):
+ self.description=self.__doc__
+
+ def do_command(self, cmdargs):
+ """
+ Master function that perfoms the "revision" command.
+ """
+
+ parser=self.get_parser()
+ (options, args) = parser.parse_args(cmdargs)
+ tree = arch.tree_root()
+ categories = []
+
+ if (options.source):
+ categories.append(arch_core.SourceFile)
+ if (options.precious):
+ categories.append(arch_core.PreciousFile)
+ if (options.backup):
+ categories.append(arch_core.BackupFile)
+ if (options.junk):
+ categories.append(arch_core.JunkFile)
+
+ if len(categories) == 1:
+ show_leading = False
+ else:
+ show_leading = True
+
+ if len(categories) == 0:
+ categories = None
+
+ if options.untagged:
+ categories = arch_core.non_root
+ show_leading = False
+ tagged = False
+ else:
+ tagged = None
+
+ for file in arch_core.iter_inventory_filter(tree, None,
+ control_files=options.control_files,
+ categories = categories, tagged=tagged):
+ print arch_core.file_line(file,
+ category = show_leading,
+ untagged = show_leading,
+ id = options.ids)
+
+ def get_parser(self):
+ """
+ Returns the options parser to use for the "revision" command.
+
+ :rtype: cmdutil.CmdOptionParser
+ """
+ parser=cmdutil.CmdOptionParser("fai inventory [options]")
+ parser.add_option("--ids", action="store_true", dest="ids",
+ help="Show file ids")
+ parser.add_option("--control", action="store_true",
+ dest="control_files", help="include control files")
+ parser.add_option("--source", action="store_true", dest="source",
+ help="List source files")
+ parser.add_option("--backup", action="store_true", dest="backup",
+ help="List backup files")
+ parser.add_option("--precious", action="store_true", dest="precious",
+ help="List precious files")
+ parser.add_option("--junk", action="store_true", dest="junk",
+ help="List junk files")
+ parser.add_option("--unrecognized", action="store_true",
+ dest="unrecognized", help="List unrecognized files")
+ parser.add_option("--untagged", action="store_true",
+ dest="untagged", help="List only untagged files")
+ return parser
+
+ def help(self, parser=None):
+ """
+ Prints a help message.
+
+ :param parser: If supplied, the parser to use for generating help. If \
+ not supplied, it is retrieved.
+ :type parser: cmdutil.CmdOptionParser
+ """
+ if parser==None:
+ parser=self.get_parser()
+ parser.print_help()
+ print """
+Lists the status of files in the archive:
+S source
+P precious
+B backup
+J junk
+U unrecognized
+T tree root
+? untagged-source
+Leading letter are not displayed if only one kind of file is shown
+ """
+ return
+
+
+class Alias(BaseCommand):
+ """List or adjust aliases"""
+ def __init__(self):
+ self.description=self.__doc__
+
+ def get_completer(self, arg, index):
+ if index > 2:
+ return ()
+ try:
+ self.tree = arch.tree_root()
+ except:
+ self.tree = None
+
+ if index == 0:
+ return [part[0]+" " for part in ancillary.iter_all_alias(self.tree)]
+ elif index == 1:
+ return cmdutil.iter_revision_completions(arg, self.tree)
+
+
+ def do_command(self, cmdargs):
+ """
+ Master function that perfoms the "revision" command.
+ """
+
+ parser=self.get_parser()
+ (options, args) = parser.parse_args(cmdargs)
+ try:
+ self.tree = arch.tree_root()
+ except:
+ self.tree = None
+
+
+ try:
+ options.action(args, options)
+ except cmdutil.ForbiddenAliasSyntax, e:
+ raise CommandFailedWrapper(e)
+
+ def arg_dispatch(self, args, options):
+ """Add, modify, or list aliases, depending on number of arguments
+
+ :param args: The list of commandline arguments
+ :type args: list of str
+ :param options: The commandline options
+ """
+ if len(args) == 0:
+ help_aliases(self.tree)
+ return
+ elif len(args) == 1:
+ self.print_alias(args[0])
+ elif (len(args)) == 2:
+ self.add(args[0], args[1], options)
+ else:
+ raise cmdutil.GetHelp
+
+ def print_alias(self, alias):
+ answer = None
+ for pair in ancillary.iter_all_alias(self.tree):
+ if pair[0] == alias:
+ answer = pair[1]
+ if answer is not None:
+ print answer
+ else:
+ print "The alias %s is not assigned." % alias
+
+ def add(self, alias, expansion, options):
+ """Add or modify aliases
+
+ :param alias: The alias name to create/modify
+ :type alias: str
+ :param expansion: The expansion to assign to the alias name
+ :type expansion: str
+ :param options: The commandline options
+ """
+ newlist = ""
+ written = False
+ new_line = "%s=%s\n" % (alias, cmdutil.expand_alias(expansion,
+ self.tree))
+ ancillary.check_alias(new_line.rstrip("\n"), [alias, expansion])
+
+ for pair in self.get_iterator(options):
+ if pair[0] != alias:
+ newlist+="%s=%s\n" % (pair[0], pair[1])
+ elif not written:
+ newlist+=new_line
+ written = True
+ if not written:
+ newlist+=new_line
+ self.write_aliases(newlist, options)
+
+ def delete(self, args, options):
+ """Delete the specified alias
+
+ :param args: The list of arguments
+ :type args: list of str
+ :param options: The commandline options
+ """
+ deleted = False
+ if len(args) != 1:
+ raise cmdutil.GetHelp
+ newlist = ""
+ for pair in self.get_iterator(options):
+ if pair[0] != args[0]:
+ newlist+="%s=%s\n" % (pair[0], pair[1])
+ else:
+ deleted = True
+ if not deleted:
+ raise errors.NoSuchAlias(args[0])
+ self.write_aliases(newlist, options)
+
+ def get_alias_file(self, options):
+ """Return the name of the alias file to use
+
+ :param options: The commandline options
+ """
+ if options.tree:
+ if self.tree is None:
+ self.tree == arch.tree_root()
+ return str(self.tree)+"/{arch}/+aliases"
+ else:
+ return "~/.aba/aliases"
+
+ def get_iterator(self, options):
+ """Return the alias iterator to use
+
+ :param options: The commandline options
+ """
+ return ancillary.iter_alias(self.get_alias_file(options))
+
+ def write_aliases(self, newlist, options):
+ """Safely rewrite the alias file
+ :param newlist: The new list of aliases
+ :type newlist: str
+ :param options: The commandline options
+ """
+ filename = os.path.expanduser(self.get_alias_file(options))
+ file = cmdutil.NewFileVersion(filename)
+ file.write(newlist)
+ file.commit()
+
+
+ def get_parser(self):
+ """
+ Returns the options parser to use for the "alias" command.
+
+ :rtype: cmdutil.CmdOptionParser
+ """
+ parser=cmdutil.CmdOptionParser("fai alias [ALIAS] [NAME]")
+ parser.add_option("-d", "--delete", action="store_const", dest="action",
+ const=self.delete, default=self.arg_dispatch,
+ help="Delete an alias")
+ parser.add_option("--tree", action="store_true", dest="tree",
+ help="Create a per-tree alias", default=False)
+ return parser
+
+ def help(self, parser=None):
+ """
+ Prints a help message.
+
+ :param parser: If supplied, the parser to use for generating help. If \
+ not supplied, it is retrieved.
+ :type parser: cmdutil.CmdOptionParser
+ """
+ if parser==None:
+ parser=self.get_parser()
+ parser.print_help()
+ print """
+Lists current aliases or modifies the list of aliases.
+
+If no arguments are supplied, aliases will be listed. If two arguments are
+supplied, the specified alias will be created or modified. If -d or --delete
+is supplied, the specified alias will be deleted.
+
+You can create aliases that refer to any fully-qualified part of the
+Arch namespace, e.g.
+archive,
+archive/category,
+archive/category--branch,
+archive/category--branch--version (my favourite)
+archive/category--branch--version--patchlevel
+
+Aliases can be used automatically by native commands. To use them
+with external or tla commands, prefix them with ^ (you can do this
+with native commands, too).
+"""
+
+
+class RequestMerge(BaseCommand):
+ """Submit a merge request to Bug Goo"""
+ def __init__(self):
+ self.description=self.__doc__
+
+ def do_command(self, cmdargs):
+ """Submit a merge request
+
+ :param cmdargs: The commandline arguments
+ :type cmdargs: list of str
+ """
+ cmdutil.find_editor()
+ parser = self.get_parser()
+ (options, args) = parser.parse_args(cmdargs)
+ try:
+ self.tree=arch.tree_root()
+ except:
+ self.tree=None
+ base, revisions = self.revision_specs(args)
+ message = self.make_headers(base, revisions)
+ message += self.make_summary(revisions)
+ path = self.edit_message(message)
+ message = self.tidy_message(path)
+ if cmdutil.prompt("Send merge"):
+ self.send_message(message)
+ print "Merge request sent"
+
+ def make_headers(self, base, revisions):
+ """Produce email and Bug Goo header strings
+
+ :param base: The base revision to apply merges to
+ :type base: `arch.Revision`
+ :param revisions: The revisions to replay into the base
+ :type revisions: list of `arch.Patchlog`
+ :return: The headers
+ :rtype: str
+ """
+ headers = "To: gnu-arch-users@gnu.org\n"
+ headers += "From: %s\n" % options.fromaddr
+ if len(revisions) == 1:
+ headers += "Subject: [MERGE REQUEST] %s\n" % revisions[0].summary
+ else:
+ headers += "Subject: [MERGE REQUEST]\n"
+ headers += "\n"
+ headers += "Base-Revision: %s\n" % base
+ for revision in revisions:
+ headers += "Revision: %s\n" % revision.revision
+ headers += "Bug: \n\n"
+ return headers
+
+ def make_summary(self, logs):
+ """Generate a summary of merges
+
+ :param logs: the patchlogs that were directly added by the merges
+ :type logs: list of `arch.Patchlog`
+ :return: the summary
+ :rtype: str
+ """
+ summary = ""
+ for log in logs:
+ summary+=str(log.revision)+"\n"
+ summary+=log.summary+"\n"
+ if log.description.strip():
+ summary+=log.description.strip('\n')+"\n\n"
+ return summary
+
+ def revision_specs(self, args):
+ """Determine the base and merge revisions from tree and arguments.
+
+ :param args: The parsed arguments
+ :type args: list of str
+ :return: The base revision and merge revisions
+ :rtype: `arch.Revision`, list of `arch.Patchlog`
+ """
+ if len(args) > 0:
+ target_revision = cmdutil.determine_revision_arch(self.tree,
+ args[0])
+ else:
+ target_revision = cmdutil.tree_latest(self.tree)
+ if len(args) > 1:
+ merges = [ arch.Patchlog(cmdutil.determine_revision_arch(
+ self.tree, f)) for f in args[1:] ]
+ else:
+ if self.tree is None:
+ raise CantDetermineRevision("", "Not in a project tree")
+ merge_iter = cmdutil.iter_new_merges(self.tree,
+ target_revision.version,
+ False)
+ merges = [f for f in cmdutil.direct_merges(merge_iter)]
+ return (target_revision, merges)
+
+ def edit_message(self, message):
+ """Edit an email message in the user's standard editor
+
+ :param message: The message to edit
+ :type message: str
+ :return: the path of the edited message
+ :rtype: str
+ """
+ if self.tree is None:
+ path = os.get_cwd()
+ else:
+ path = self.tree
+ path += "/,merge-request"
+ file = open(path, 'w')
+ file.write(message)
+ file.flush()
+ cmdutil.invoke_editor(path)
+ return path
+
+ def tidy_message(self, path):
+ """Validate and clean up message.
+
+ :param path: The path to the message to clean up
+ :type path: str
+ :return: The parsed message
+ :rtype: `email.Message`
+ """
+ mail = email.message_from_file(open(path))
+ if mail["Subject"].strip() == "[MERGE REQUEST]":
+ raise BlandSubject
+
+ request = email.message_from_string(mail.get_payload())
+ if request.has_key("Bug"):
+ if request["Bug"].strip()=="":
+ del request["Bug"]
+ mail.set_payload(request.as_string())
+ return mail
+
+ def send_message(self, message):
+ """Send a message, using its headers to address it.
+
+ :param message: The message to send
+ :type message: `email.Message`"""
+ server = smtplib.SMTP()
+ server.sendmail(message['From'], message['To'], message.as_string())
+ server.quit()
+
+ def help(self, parser=None):
+ """Print a usage message
+
+ :param parser: The options parser to use
+ :type parser: `cmdutil.CmdOptionParser`
+ """
+ if parser is None:
+ parser = self.get_parser()
+ parser.print_help()
+ print """
+Sends a merge request formatted for Bug Goo. Intended use: get the tree
+you'd like to merge into. Apply the merges you want. Invoke request-merge.
+The merge request will open in your $EDITOR.
+
+When no TARGET is specified, it uses the current tree revision. When
+no MERGE is specified, it uses the direct merges (as in "revisions
+--direct-merges"). But you can specify just the TARGET, or all the MERGE
+revisions.
+"""
+
+ def get_parser(self):
+ """Produce a commandline parser for this command.
+
+ :rtype: `cmdutil.CmdOptionParser`
+ """
+ parser=cmdutil.CmdOptionParser("request-merge [TARGET] [MERGE1...]")
+ return parser
+
+commands = {
+'changes' : Changes,
+'help' : Help,
+'update': Update,
+'apply-changes':ApplyChanges,
+'cat-log': CatLog,
+'commit': Commit,
+'revision': Revision,
+'revisions': Revisions,
+'get': Get,
+'revert': Revert,
+'shell': Shell,
+'add-id': AddID,
+'merge': Merge,
+'elog': ELog,
+'mirror-archive': MirrorArchive,
+'ninventory': Inventory,
+'alias' : Alias,
+'request-merge': RequestMerge,
+}
+suggestions = {
+'apply-delta' : "Try \"apply-changes\".",
+'delta' : "To compare two revisions, use \"changes\".",
+'diff-rev' : "To compare two revisions, use \"changes\".",
+'undo' : "To undo local changes, use \"revert\".",
+'undelete' : "To undo only deletions, use \"revert --deletions\"",
+'missing-from' : "Try \"revisions --missing-from\".",
+'missing' : "Try \"revisions --missing\".",
+'missing-merge' : "Try \"revisions --partner-missing\".",
+'new-merges' : "Try \"revisions --new-merges\".",
+'cachedrevs' : "Try \"revisions --cacherevs\". (no 'd')",
+'logs' : "Try \"revisions --logs\"",
+'tree-source' : "Use the \"^ttag\" alias (\"revision ^ttag\")",
+'latest-revision' : "Use the \"^acur\" alias (\"revision ^acur\")",
+'change-version' : "Try \"update REVISION\"",
+'tree-revision' : "Use the \"^tcur\" alias (\"revision ^tcur\")",
+'rev-depends' : "Use revisions --dependencies",
+'auto-get' : "Plain get will do archive lookups",
+'tagline' : "Use add-id. It uses taglines in tagline trees",
+'emlog' : "Use elog. It automatically adds log-for-merge text, if any",
+'library-revisions' : "Use revisions --library",
+'file-revert' : "Use revert FILE"
+}
+# arch-tag: 19d5739d-3708-486c-93ba-deecc3027fc7