]> scripts.mit.edu Git - wizard.git/commitdiff
Add --continue support to upgrades.
authorEdward Z. Yang <ezyang@mit.edu>
Sat, 15 Aug 2009 21:55:12 +0000 (17:55 -0400)
committerEdward Z. Yang <ezyang@mit.edu>
Sat, 15 Aug 2009 21:55:12 +0000 (17:55 -0400)
Signed-off-by: Edward Z. Yang <ezyang@mit.edu>
tests/test-continue-upgrade-mediawiki.sh [new file with mode: 0755]
wizard/command/upgrade.py

diff --git a/tests/test-continue-upgrade-mediawiki.sh b/tests/test-continue-upgrade-mediawiki.sh
new file mode 100755 (executable)
index 0000000..7411325
--- /dev/null
@@ -0,0 +1,22 @@
+#!/bin/bash -e
+
+TESTNAME="continue_upgrade_mediawiki"
+source setup
+
+wizard install mediawiki-$VERSION-scripts "$TESTDIR" -- --title="TestApp"
+
+# nuke the install
+FROB="includes/DefaultSettings.php"
+mv "$TESTDIR/$FROB" "$TESTDIR/$FROB.bak"
+echo "this is a bad index file" > "$TESTDIR/$FROB"
+
+# attempt an upgrade, this will fail
+TMPTESTDIR=`! wizard upgrade "$TESTDIR"`
+
+# resolve the upgrade
+mv -f "$TESTDIR/$FROB.bak" "$TMPTESTDIR/$FROB"
+OLDDIR=`pwd`
+cd "$TMPTESTDIR"
+git add $FROB
+git commit -m "resolution commit"
+wizard upgrade --continue
index 981273cc94ccd1973457580f7f5ea755f15b3406..d67d5cd517339d51adcf12997c0295e9b496c6a8 100644 (file)
@@ -15,29 +15,44 @@ from wizard import command, deploy, shell, util
 
 def main(argv, baton):
     options, args = parse_args(argv, baton)
-    command.chdir(args[0])
-    d = make_deployment_from_cwd()
-    repo = d.application.repository(options.srv_path)
-    util.set_git_env()
+    if args:
+        command.chdir(args[0])
     sh = shell.Shell()
-    if not options.dry_run:
-        perform_pre_commit(sh)
-    temp_wc_dir = perform_tmp_clone(sh)
-    with util.ChangeDirectory(temp_wc_dir):
-        if options.dry_run:
-            # we delayed performing the pre upgrade commit
-            # until we're in the temporary directory
+    util.set_git_env()
+    if options.continue_:
+        temp_wc_dir = os.getcwd()
+        user_commit, next_commit = open(".git/WIZARD_PARENTS", "r").read().split()
+        repo = open(".git/WIZARD_REPO", "r").read()
+        version = open(".git/WIZARD_UPGRADE_VERSION", "r").read()
+        command.chdir(sh.eval("git", "config", "remote.origin.url"))
+    else:
+        d = make_deployment_from_cwd()
+        repo = d.application.repository(options.srv_path)
+        version = calculate_newest_version(sh, repo)
+        if not options.dry_run:
             perform_pre_commit(sh)
-        sh.call("git", "remote", "add", "scripts", repo)
-        sh.call("git", "fetch", "scripts")
-        version = sh.eval("git", "--git-dir="+repo, "describe", "--tags", "master")
-        user_commit = sh.eval("git", "rev-parse", "HEAD")
-        next_commit = sh.eval("git", "rev-parse", version)
-        perform_merge(sh, repo, d, version)
-        # Make it possible to resume here
-        new_tree = sh.eval("git", "rev-parse", "HEAD^{tree}")
+        temp_wc_dir = perform_tmp_clone(sh)
+        with util.ChangeDirectory(temp_wc_dir):
+            if options.dry_run:
+                # we delayed performing the pre upgrade commit
+                # until we're in the temporary directory
+                perform_pre_commit(sh)
+            sh.call("git", "remote", "add", "scripts", repo)
+            sh.call("git", "fetch", "scripts")
+            user_commit, next_commit = calculate_parents(sh, version)
+            # save variables so that --continue will work
+            # yeah yeah no trailing newline whatever
+            open(".git/WIZARD_REPO", "w").write(repo)
+            open(".git/WIZARD_UPGRADE_VERSION", "w").write(version)
+            open(".git/WIZARD_PARENTS", "w").write("%s\n%s" % (user_commit, next_commit))
+            perform_merge(sh, repo, d, version)
+    # variables: version, user_commit, next_commit, temp_wc_dir
+    with util.ChangeDirectory(temp_wc_dir):
         message = make_commit_message(version)
+        new_tree = sh.eval("git", "rev-parse", "HEAD^{tree}")
         final_commit = sh.eval("git", "commit-tree", new_tree, "-p", user_commit, "-p", next_commit, input=message)
+        # a master branch may not necessarily exist if the user
+        # was manually installed to an earlier version
         try:
             sh.call("git", "checkout", "-b", "master", "--")
         except shell.CallError:
@@ -75,6 +90,15 @@ def make_commit_message(version):
         message += "\nUpgraded-by: " + util.get_operator_git()
     except util.NoOperatorInfo:
         pass
+    return message
+
+def calculate_newest_version(sh, repo):
+    return sh.eval("git", "--git-dir="+repo, "describe", "--tags", "master")
+
+def calculate_parents(sh, version):
+    user_commit = sh.eval("git", "rev-parse", "HEAD")
+    next_commit = sh.eval("git", "rev-parse", version)
+    return user_commit, next_commit
 
 def perform_pre_commit(sh):
     try:
@@ -96,36 +120,36 @@ def perform_tmp_clone(sh):
     return temp_wc_dir
 
 def perform_merge(sh, repo, d, version):
+    # naive merge algorithm:
+    # sh.call("git", "merge", "-m", message, "scripts/master")
+    # crazy merge algorithm:
+    def make_virtual_commit(tag, parents = []):
+        """WARNING: Changes state of Git repository"""
+        sh.call("git", "checkout", tag, "--")
+        d.parametrize(".")
+        for file in d.application.parametrized_files:
+            try:
+                sh.call("git", "add", "--", file)
+            except shell.CallError:
+                pass
+        virtual_tree = sh.eval("git", "write-tree")
+        parent_args = itertools.chain(*(["-p", p] for p in parents))
+        virtual_commit = sh.eval("git", "commit-tree", virtual_tree, *parent_args, input="")
+        sh.call("git", "reset", "--hard")
+        return virtual_commit
+    user_tree = sh.eval("git", "rev-parse", "HEAD^{tree}")
+    base_virtual_commit = make_virtual_commit(d.app_version.pristine_tag)
+    next_virtual_commit = make_virtual_commit(version, [base_virtual_commit])
+    user_virtual_commit = sh.eval("git", "commit-tree", user_tree, "-p", base_virtual_commit, input="")
+    sh.call("git", "checkout", user_virtual_commit, "--")
     try:
-        # naive merge algorithm:
-        # sh.call("git", "merge", "-m", message, "scripts/master")
-        # crazy merge algorithm:
-        def make_virtual_commit(tag, parents = []):
-            """WARNING: Changes state of Git repository"""
-            sh.call("git", "checkout", tag, "--")
-            d.parametrize(".")
-            for file in d.application.parametrized_files:
-                try:
-                    sh.call("git", "add", "--", file)
-                except shell.CallError:
-                    pass
-            virtual_tree = sh.eval("git", "write-tree")
-            parent_args = itertools.chain(*(["-p", p] for p in parents))
-            virtual_commit = sh.eval("git", "commit-tree", virtual_tree, *parent_args, input="")
-            sh.call("git", "reset", "--hard")
-            return virtual_commit
-        user_tree = sh.eval("git", "rev-parse", "HEAD^{tree}")
-        base_virtual_commit = make_virtual_commit(d.app_version.pristine_tag)
-        next_virtual_commit = make_virtual_commit(version, [base_virtual_commit])
-        user_virtual_commit = sh.eval("git", "commit-tree", user_tree, "-p", base_virtual_commit, input="")
-        sh.call("git", "checkout", user_virtual_commit, "--")
         sh.call("git", "merge", next_virtual_commit)
     except shell.CallError:
         print os.getcwd()
         raise MergeFailed
 
 def parse_args(argv, baton):
-    usage = """usage: %prog upgrade [ARGS] DIR
+    usage = """usage: %prog upgrade [ARGS] [DIR]
 
 Upgrades an autoinstall to the latest version.  This involves
 updating files and running .scripts/update.
@@ -134,12 +158,13 @@ WARNING: This is still experimental."""
     parser = command.WizardOptionParser(usage)
     parser.add_option("--dry-run", dest="dry_run", action="store_true",
             default=False, help="Prints would would be run without changing anything")
+    # notice trailing underscore
+    parser.add_option("--continue", dest="continue_", action="store_true",
+            default=False, help="Continues an upgrade that has had its merge manually resolved using the current working directory as the resolved copy.")
     baton.push(parser, "srv_path")
     options, args = parser.parse_all(argv)
     if len(args) > 1:
         parser.error("too many arguments")
-    elif not args:
-        parser.error("must specify directory")
     return options, args
 
 class Error(command.Error):
@@ -159,6 +184,8 @@ class MergeFailed(Error):
     def __str__(self):
         return """
 
-ERROR: Merge failed.  Change directory to the temporary
-directory and manually resolve the merge.
-"""
+ERROR: Merge failed.  Resolve the merge by cd'ing to the
+temporary directory, finding conflicted files with `git status`,
+resolving the files, adding them using `git add`, and then
+committing your changes with `git commit` (your log message
+will be ignored), and then running `wizard upgrade --continue`."""