import os
import sys
-from wizard import command, shell
+import wizard
+from wizard import deploy, command, shell
def main(argv, baton):
options, args = parse_args(argv, baton)
+ # Make sure this is a Wizard repo
+ if not options.generic:
+ d = deploy.ProductionCopy('.')
+ try:
+ d.verify()
+ except deploy.AlreadyVersionedError:
+ raise NotWizardError
# Determine upstream commit history
# XXX This is a little sloppy (since it also pulls in remotes and
# originals), but if the upstream repo has a clean set of remotes,
# that shouldn't be a problem.
excludes = map(lambda line: line.partition("\t")[0],
- shell.eval("git", "ls-remote", "origin").splitlines())
+ shell.eval("git", "ls-remote", options.remote).splitlines())
# Determine local commits and their parents
local_commits = set()
all_parents = set()
if len(candidates) != 1:
raise "Failed looking for " + hash
mapping[hash] = candidates[0]
+ # Delete no-ops
+ for search, replace in mapping.items():
+ if search == replace:
+ del mapping[search]
+ # Bail out if nothing to do
+ if not mapping:
+ raise NothingToDo
# XXX Make this more robust: given our pre-processing, there is a
# very specific set of parent IDs we expect to see (not necessarily
shell.call("chmod", "a+x", t.name) # necessary?
logging.info("Sed script %s", t.name)
# Do the rewrite
+ maybe_force = []
+ if options.force: maybe_force = ['--force']
+ extra_args = maybe_force + excludes
shell.call("git", "filter-branch", "--parent-filter", t.name, "--",
- "--branches", "--not", *excludes,
+ "--branches", "--not", *extra_args,
stdout=sys.stdout, stderr=sys.stderr)
finally:
# Cleanup
"""
parser = command.WizardOptionParser(usage)
parser.add_option("-f", "--force", dest="force", action="store_true",
- default=False, help="Force overwriting.")
+ default=False, help="Force overwriting (passed to filter-branch).")
+ parser.add_option("--generic", dest="generic", action="store_true",
+ default=False, help="Allow remastering of non-Wizard repositories.")
+ parser.add_option("--remote", dest="remote", metavar="REMOTE",
+ default="origin", help="Rebased remote to remaster off of.")
options, args = parser.parse_all(argv)
if len(args) > 0:
parser.error("too many arguments")
return options, args
+
+## -- Exceptions --
+
+class Error(wizard.Error):
+ """Base error class for this module"""
+ pass
+
+class NotWizardError(Error):
+ """The deployment was not a Wizard installation."""
+ def __str__(self):
+ return """
+
+ERROR: This is not a Wizard Git repository! If you really want to
+use 'wizard remaster' on a non-Wizard repository, pass in
+'--generic'."""
+
+class NothingToDo(Error):
+ """No rewriting necessary."""
+ def __str__(self):
+ return """
+
+ERROR: Nothing to do!"""
parent = repo_rev_parse(self.app_version.wizard_tag)
merge_base = shell.safeCall("git", "merge-base", parent, "HEAD", strip=True)
if merge_base != parent:
+ # XXX Try remastering
raise HeadNotDescendantError(self.app_version.wizard_tag)
def verifyConfigured(self):
ERROR: HEAD is not a descendant of %s. This probably
means that an upstream rebase occurred, and new tags were
-pulled, but local user commits were never rebased.""" % self.tag
+pulled, but local user commits were never rebased. Try
+running 'wizard remaster'.""" % self.tag
class VersionDetectionError(Error):
"""Could not detect real version of application."""