--- orig/commands.py +++ mod/commands.py @@ -19,25 +19,31 @@ import arch import arch.util import arch.arch + +import pylon.errors +from pylon.errors import * +from pylon import errors +from pylon import util +from pylon import arch_core +from pylon import arch_compound +from pylon import ancillary +from pylon import misc +from pylon import paths + 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 +import textwrap __docformat__ = "restructuredtext" __doc__ = "Implementation of user (sub) commands" @@ -257,7 +263,7 @@ tree=arch.tree_root() if len(args) == 0: - a_spec = cmdutil.comp_revision(tree) + a_spec = ancillary.comp_revision(tree) else: a_spec = cmdutil.determine_revision_tree(tree, args[0]) cmdutil.ensure_archive_registered(a_spec.archive) @@ -284,7 +290,7 @@ changeset=options.changeset tmpdir = None else: - tmpdir=cmdutil.tmpdir() + tmpdir=util.tmpdir() changeset=tmpdir+"/changeset" try: delta=arch.iter_delta(a_spec, b_spec, changeset) @@ -304,14 +310,14 @@ if status > 1: return if (options.perform_diff): - chan = cmdutil.ChangesetMunger(changeset) + chan = arch_compound.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: + if isinstance(b_spec, arch.Revision): + b_dir = b_spec.library_find() + else: + b_dir = b_spec + a_dir = a_spec.library_find() diffopts = options.diffopts.split() cmdutil.show_custom_diffs(chan, diffopts, a_dir, b_dir) else: @@ -517,7 +523,7 @@ except arch.errors.TreeRootError, e: print e return - from_revision=cmdutil.tree_latest(tree) + from_revision = arch_compound.tree_latest(tree) if from_revision==to_revision: print "Tree is already up to date with:\n"+str(to_revision)+"." return @@ -592,6 +598,9 @@ if len(args) == 0: args = None + if options.version is None: + return options, tree.tree_version, args + revision=cmdutil.determine_revision_arch(tree, options.version) return options, revision.get_version(), args @@ -601,11 +610,16 @@ """ tree=arch.tree_root() options, version, files = self.parse_commandline(cmdargs, tree) + ancestor = None if options.__dict__.has_key("base") and options.base: base = cmdutil.determine_revision_tree(tree, options.base) + ancestor = base else: - base = cmdutil.submit_revision(tree) - + base = ancillary.submit_revision(tree) + ancestor = base + if ancestor is None: + ancestor = arch_compound.tree_latest(tree, version) + writeversion=version archive=version.archive source=cmdutil.get_mirror_source(archive) @@ -625,18 +639,26 @@ 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(): + last_revision = None + if ancestor is None: + if cmdutil.prompt("Import from commit"): + return do_import(version) + else: + raise NoVersionLogs(version) + try: + arch_last_revision = version.iter_revisions(True).next() + except StopIteration, e: + arch_last_revision = None + + if last_revision != arch_last_revision: + print "Tree is not up to date with %s" % str(version) if not cmdutil.prompt("Out of date"): raise OutOfDate else: allow_old=True try: - if not cmdutil.has_changed(version): + if not cmdutil.has_changed(ancestor): if not cmdutil.prompt("Empty commit"): raise EmptyCommit except arch.util.ExecProblem, e: @@ -645,15 +667,15 @@ raise MissingID(e) else: raise - log = tree.log_message(create=False) + log = tree.log_message(create=False, version=version) if log is None: try: if cmdutil.prompt("Create log"): - edit_log(tree) + edit_log(tree, version) except cmdutil.NoEditorSpecified, e: raise CommandFailed(e) - log = tree.log_message(create=False) + log = tree.log_message(create=False, version=version) if log is None: raise NoLogMessage if log["Summary"] is None or len(log["Summary"].strip()) == 0: @@ -837,23 +859,24 @@ if spec is not None: revision = cmdutil.determine_revision_tree(tree, spec) else: - revision = cmdutil.comp_revision(tree) + revision = ancillary.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 + munger = arch_compound.MungeOpts() + munger.set_hunk_prompt(cmdutil.colorize, cmdutil.user_hunk_confirm, + 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 = cmdutil.arch_compound.MungeOpts(True) munger.all_types(True) if len(args) > 0: - t_cwd = cmdutil.tree_cwd(tree) + t_cwd = arch_compound.tree_cwd(tree) for name in args: if len(t_cwd) > 0: t_cwd += "/" @@ -878,7 +901,7 @@ if options.pattern_files: munger.add_keep_pattern(options.pattern_files) - for line in cmdutil.revert(tree, revision, munger, + for line in arch_compound.revert(tree, revision, munger, not options.no_output): cmdutil.colorize(line) @@ -1042,18 +1065,13 @@ 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" + self.cl_revisions = [] def do_command(self, cmdargs): """ @@ -1066,224 +1084,68 @@ self.tree = arch.tree_root() except arch.errors.TreeRootError: self.tree = None + if options.type == "default": + options.type = "archive" try: - iter = self.get_iterator(options.type, args, options.reverse, - options.modified) + iter = cmdutil.revision_iterator(self.tree, options.type, args, + options.reverse, options.modified, + options.shallow) except cmdutil.CantDetermineRevision, e: raise CommandFailedWrapper(e) - + except cmdutil.CantDetermineVersion, 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) - - + try: + for revision in iter: + log = None + if isinstance(revision, arch.Patchlog): + log = revision + revision=revision.revision + out = options.display(revision) + if out is not None: + print out + 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 + if len(self.cl_revisions) > 0: + print pylon.changelog_for_merge(self.cl_revisions) + except pylon.errors.TreeRootNone: + raise CommandFailedWrapper( + Exception("This option can only be used in a project tree.")) + + def changelog_append(self, revision): + if isinstance(revision, arch.Revision): + revision=arch.Patchlog(revision) + self.cl_revisions.append(revision) + def get_parser(self): """ Returns the options parser to use for the "revision" command. :rtype: cmdutil.CmdOptionParser """ - parser=cmdutil.CmdOptionParser("fai revisions [revision]") + parser=cmdutil.CmdOptionParser("fai revisions [version/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]") + cmdutil.add_revision_iter_options(select) parser.add_option("", "--skip", dest="skip", help="Skip revisions. Positive numbers skip from " "beginning, negative skip from end.", @@ -1312,6 +1174,9 @@ format.add_option("--cacherev", action="store_const", const=paths.determine_cacherev_path, dest="display", help="Show location of cacherev file") + format.add_option("--changelog", action="store_const", + const=self.changelog_append, 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") @@ -1448,6 +1313,7 @@ if os.access(self.history_file, os.R_OK) and \ os.path.isfile(self.history_file): readline.read_history_file(self.history_file) + self.cwd = os.getcwd() def write_history(self): readline.write_history_file(self.history_file) @@ -1470,16 +1336,21 @@ def set_prompt(self): if self.tree is not None: try: - version = " "+self.tree.tree_version.nonarch + prompt = pylon.alias_or_version(self.tree.tree_version, + self.tree, + full=False) + if prompt is not None: + prompt = " " + prompt except: - version = "" + prompt = "" else: - version = "" - self.prompt = "Fai%s> " % version + prompt = "" + self.prompt = "Fai%s> " % prompt def set_title(self, command=None): try: - version = self.tree.tree_version.nonarch + version = pylon.alias_or_version(self.tree.tree_version, self.tree, + full=False) except: version = "[no version]" if command is None: @@ -1489,8 +1360,15 @@ def do_cd(self, line): if line == "": line = "~" + line = os.path.expanduser(line) + if os.path.isabs(line): + newcwd = line + else: + newcwd = self.cwd+'/'+line + newcwd = os.path.normpath(newcwd) try: - os.chdir(os.path.expanduser(line)) + os.chdir(newcwd) + self.cwd = newcwd except Exception, e: print e try: @@ -1523,7 +1401,7 @@ except cmdutil.CantDetermineRevision, e: print e except Exception, e: - print "Unhandled error:\n%s" % cmdutil.exception_str(e) + print "Unhandled error:\n%s" % errors.exception_str(e) elif suggestions.has_key(args[0]): print suggestions[args[0]] @@ -1574,7 +1452,7 @@ arg = line.split()[-1] else: arg = "" - iter = iter_munged_completions(iter, arg, text) + iter = cmdutil.iter_munged_completions(iter, arg, text) except Exception, e: print e return list(iter) @@ -1604,10 +1482,11 @@ else: arg = "" if arg.startswith("-"): - return list(iter_munged_completions(iter, arg, text)) + return list(cmdutil.iter_munged_completions(iter, arg, + text)) else: - return list(iter_munged_completions( - iter_file_completions(arg), arg, text)) + return list(cmdutil.iter_munged_completions( + cmdutil.iter_file_completions(arg), arg, text)) elif cmd == "cd": @@ -1615,13 +1494,13 @@ arg = args.split()[-1] else: arg = "" - iter = iter_dir_completions(arg) - iter = iter_munged_completions(iter, arg, text) + iter = cmdutil.iter_dir_completions(arg) + iter = cmdutil.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)) + iter = cmdutil.iter_file_completions(arg) + return list(cmdutil.iter_munged_completions(iter, arg, text)) else: return self.completenames(text, line, begidx, endidx) except Exception, e: @@ -1636,44 +1515,8 @@ 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) + treepath = arch_compound.tree_cwd(tree) if len(treepath) > 0: dirs = [treepath] else: @@ -1701,7 +1544,7 @@ :return: An iterator of all matching untagged files :rtype: iterator of str """ - treepath = cmdutil.tree_cwd(tree) + treepath = arch_compound.tree_cwd(tree) if len(treepath) > 0: dirs = [treepath] else: @@ -1743,8 +1586,8 @@ :param arg: The prefix to match :type arg: str """ - treepath = cmdutil.tree_cwd(tree) - tmpdir = cmdutil.tmpdir() + treepath = arch_compound.tree_cwd(tree) + tmpdir = util.tmpdir() changeset = tmpdir+"/changeset" completions = [] revision = cmdutil.determine_revision_tree(tree) @@ -1756,14 +1599,6 @@ 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" @@ -1795,7 +1630,11 @@ parser=self.get_parser() (options, args) = parser.parse_args(cmdargs) - tree = arch.tree_root() + try: + tree = arch.tree_root() + except arch.errors.TreeRootError, e: + raise pylon.errors.CommandFailedWrapper(e) + if (len(args) == 0) == (options.untagged == False): raise cmdutil.GetHelp @@ -1809,13 +1648,22 @@ if options.id_type == "tagline": if method != "tagline": if not cmdutil.prompt("Tagline in other tree"): - if method == "explicit": - options.id_type == explicit + if method == "explicit" or method == "implicit": + options.id_type == method else: print "add-id not supported for \"%s\" tagging method"\ % method return + elif options.id_type == "implicit": + if method != "implicit": + if not cmdutil.prompt("Implicit in other tree"): + if method == "explicit" or method == "tagline": + options.id_type == method + 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"): @@ -1824,7 +1672,8 @@ return if options.id_type == "auto": - if method != "tagline" and method != "explicit": + if method != "tagline" and method != "explicit" \ + and method !="implicit": print "add-id not supported for \"%s\" tagging method" % method return else: @@ -1852,10 +1701,12 @@ previous_files.extend(files) if id_type == "explicit": cmdutil.add_id(files) - elif id_type == "tagline": + elif id_type == "tagline" or id_type == "implicit": for file in files: try: - cmdutil.add_tagline_or_explicit_id(file) + implicit = (id_type == "implicit") + cmdutil.add_tagline_or_explicit_id(file, False, + implicit) except cmdutil.AlreadyTagged: print "\"%s\" already has a tagline." % file except cmdutil.NoCommentSyntax: @@ -1888,6 +1739,9 @@ parser.add_option("--tagline", action="store_const", const="tagline", dest="id_type", help="Use a tagline id") + parser.add_option("--implicit", action="store_const", + const="implicit", dest="id_type", + help="Use an implicit id (deprecated)") parser.add_option("--untagged", action="store_true", dest="untagged", default=False, help="tag all untagged files") @@ -1926,27 +1780,7 @@ 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 + return cmdutil.merge_completions(self.tree, arg, index) def do_command(self, cmdargs): """ @@ -1961,7 +1795,7 @@ if self.tree is None: raise arch.errors.TreeRootError(os.getcwd()) - if cmdutil.has_changed(self.tree.tree_version): + if cmdutil.has_changed(ancillary.comp_revision(self.tree)): raise UncommittedChanges(self.tree) if len(args) > 0: @@ -2027,14 +1861,14 @@ :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) + other_tree = arch_compound.find_or_make_local_revision(other_revision) try: if action == "native-merge": - ancestor = cmdutil.merge_ancestor2(self.tree, other_tree, - other_revision) + ancestor = arch_compound.merge_ancestor2(self.tree, other_tree, + other_revision) elif action == "update": - ancestor = cmdutil.tree_latest(self.tree, - other_revision.version) + ancestor = arch_compound.tree_latest(self.tree, + other_revision.version) except CantDetermineRevision, e: raise CommandFailedWrapper(e) cmdutil.colorize(arch.Chatter("* Found common ancestor %s" % ancestor)) @@ -2104,7 +1938,10 @@ if self.tree is None: raise arch.errors.TreeRootError - edit_log(self.tree) + try: + edit_log(self.tree, self.tree.tree_version) + except pylon.errors.NoEditorSpecified, e: + raise pylon.errors.CommandFailedWrapper(e) def get_parser(self): """ @@ -2132,7 +1969,7 @@ """ return -def edit_log(tree): +def edit_log(tree, version): """Makes and edits the log for a tree. Does all kinds of fancy things like log templates and merge summaries and log-for-merge @@ -2141,28 +1978,29 @@ """ #ensure we have an editor before preparing the log cmdutil.find_editor() - log = tree.log_message(create=False) + log = tree.log_message(create=False, version=version) 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 = tree.log_message(create=True, version=version) 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 + template = pylon.log_template_path(tree) 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) + comp_version = ancillary.comp_revision(tree).version + new_merges = cmdutil.iter_new_merges(tree, comp_version) + new_merges = cmdutil.direct_merges(new_merges) + log["Summary"] = pylon.merge_summary(new_merges, + version) if len(new_merges) > 0: if cmdutil.prompt("Log for merge"): - mergestuff = cmdutil.log_for_merge(tree) + if cmdutil.prompt("changelog for merge"): + mergestuff = "Patches applied:\n" + mergestuff += pylon.changelog_for_merge(new_merges) + else: + mergestuff = cmdutil.log_for_merge(tree, comp_version) log.description += mergestuff log.save() try: @@ -2172,29 +2010,6 @@ 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): """ @@ -2268,31 +2083,73 @@ Use "alias" to list available (user and automatic) aliases.""" +auto_alias = [ +"acur", +"The latest revision in the archive of the tree-version. You can specify \ +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.""", +] + + +def is_auto_alias(name): + """Determine whether a name is an auto alias name + + :param name: the name to check + :type name: str + :return: True if the name is an auto alias, false if not + :rtype: bool + """ + return name in [f for (f, v) in pylon.util.iter_pairs(auto_alias)] + + +def display_def(iter, wrap = 80): + """Display a list of definitions + + :param iter: iter of name, definition pairs + :type iter: iter of (str, str) + :param wrap: The width for text wrapping + :type wrap: int + """ + vals = list(iter) + maxlen = 0 + for (key, value) in vals: + if len(key) > maxlen: + maxlen = len(key) + for (key, value) in vals: + tw=textwrap.TextWrapper(width=wrap, + initial_indent=key.rjust(maxlen)+" : ", + subsequent_indent="".rjust(maxlen+3)) + print tw.fill(value) + + 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 """Auto-generated aliases""" + display_def(pylon.util.iter_pairs(auto_alias)) print "User aliases" - for parts in ancillary.iter_all_alias(tree): - print parts[0].rjust(10)+" : "+parts[1] - + display_def(ancillary.iter_all_alias(tree)) class Inventory(BaseCommand): """List the status of files in the tree""" @@ -2428,6 +2285,11 @@ except cmdutil.ForbiddenAliasSyntax, e: raise CommandFailedWrapper(e) + def no_prefix(self, alias): + if alias.startswith("^"): + alias = alias[1:] + return alias + def arg_dispatch(self, args, options): """Add, modify, or list aliases, depending on number of arguments @@ -2438,15 +2300,20 @@ 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 + alias = self.no_prefix(args[0]) + if len(args) == 1: + self.print_alias(alias) + elif (len(args)) == 2: + self.add(alias, args[1], options) + else: + raise cmdutil.GetHelp def print_alias(self, alias): answer = None + if is_auto_alias(alias): + raise pylon.errors.IsAutoAlias(alias, "\"%s\" is an auto alias." + " Use \"revision\" to expand auto aliases." % alias) for pair in ancillary.iter_all_alias(self.tree): if pair[0] == alias: answer = pair[1] @@ -2464,6 +2331,8 @@ :type expansion: str :param options: The commandline options """ + if is_auto_alias(alias): + raise IsAutoAlias(alias) newlist = "" written = False new_line = "%s=%s\n" % (alias, cmdutil.expand_alias(expansion, @@ -2490,14 +2359,17 @@ deleted = False if len(args) != 1: raise cmdutil.GetHelp + alias = self.no_prefix(args[0]) + if is_auto_alias(alias): + raise IsAutoAlias(alias) newlist = "" for pair in self.get_iterator(options): - if pair[0] != args[0]: + if pair[0] != alias: newlist+="%s=%s\n" % (pair[0], pair[1]) else: deleted = True if not deleted: - raise errors.NoSuchAlias(args[0]) + raise errors.NoSuchAlias(alias) self.write_aliases(newlist, options) def get_alias_file(self, options): @@ -2526,7 +2398,7 @@ :param options: The commandline options """ filename = os.path.expanduser(self.get_alias_file(options)) - file = cmdutil.NewFileVersion(filename) + file = util.NewFileVersion(filename) file.write(newlist) file.commit() @@ -2588,10 +2460,13 @@ :param cmdargs: The commandline arguments :type cmdargs: list of str """ - cmdutil.find_editor() parser = self.get_parser() (options, args) = parser.parse_args(cmdargs) try: + cmdutil.find_editor() + except pylon.errors.NoEditorSpecified, e: + raise pylon.errors.CommandFailedWrapper(e) + try: self.tree=arch.tree_root() except: self.tree=None @@ -2655,7 +2530,7 @@ target_revision = cmdutil.determine_revision_arch(self.tree, args[0]) else: - target_revision = cmdutil.tree_latest(self.tree) + target_revision = arch_compound.tree_latest(self.tree) if len(args) > 1: merges = [ arch.Patchlog(cmdutil.determine_revision_arch( self.tree, f)) for f in args[1:] ] @@ -2711,7 +2586,7 @@ :param message: The message to send :type message: `email.Message`""" - server = smtplib.SMTP() + server = smtplib.SMTP("localhost") server.sendmail(message['From'], message['To'], message.as_string()) server.quit() @@ -2763,6 +2638,22 @@ 'alias' : Alias, 'request-merge': RequestMerge, } + +def my_import(mod_name): + module = __import__(mod_name) + components = mod_name.split('.') + for comp in components[1:]: + module = getattr(module, comp) + return module + +def plugin(mod_name): + module = my_import(mod_name) + module.add_command(commands) + +for file in os.listdir(sys.path[0]+"/command"): + if len(file) > 3 and file[-3:] == ".py" and file != "__init__.py": + plugin("command."+file[:-3]) + suggestions = { 'apply-delta' : "Try \"apply-changes\".", 'delta' : "To compare two revisions, use \"changes\".", @@ -2784,6 +2675,7 @@ '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" +'file-revert' : "Use revert FILE", +'join-branch' : "Use replay --logs-only" } # arch-tag: 19d5739d-3708-486c-93ba-deecc3027fc7