]> scripts.mit.edu Git - wizard.git/blobdiff - wizard/command/upgrade.py
Implement 'wizard backup'. Other minor refactorings:
[wizard.git] / wizard / command / upgrade.py
index f4acaf7856dea58a6ba686e283483eb4657fbe32..9f388e047eb4d8820a7ff82cd75f23cc4f096db3 100644 (file)
@@ -1,5 +1,6 @@
 import optparse
 import sys
+import distutils.version
 import os
 import shutil
 import logging.handlers
@@ -9,15 +10,14 @@ import itertools
 
 from wizard import command, deploy, shell, util
 
-# XXX: need errors for history sanity checking (if the user is on a completely
-# different history tree, we should abort, and manually figure out the
-# appropriate rebase)
-# $(git merge-base P C) == $(git rev-parse P)
-
 def main(argv, baton):
     options, args = parse_args(argv, baton)
     if args:
-        command.chdir(args[0])
+        dir = args[0]
+    else:
+        dir = "."
+    shell.drop_priviledges(dir, options.log_file)
+    util.chdir(dir)
     sh = shell.Shell()
     util.set_git_env()
     if options.continue_:
@@ -25,20 +25,28 @@ def main(argv, baton):
         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"))
-        d = make_deployment_from_cwd()
+        util.chdir(sh.eval("git", "config", "remote.origin.url"))
+        d = deploy.Deployment(".")
+        try:
+            sh.call("git", "status")
+            raise LocalChangesError()
+        except shell.CallError:
+            pass
     else:
-        d = make_deployment_from_cwd()
+        d = deploy.Deployment(".")
+        d.verify()
+        d.verifyTag(options.srv_path)
+        d.verifyGit(options.srv_path)
+        d.verifyConfigured()
+        d.verifyVersion()
         repo = d.application.repository(options.srv_path)
         version = calculate_newest_version(sh, repo)
+        if version == d.app_version.scripts_tag and not options.force:
+            raise AlreadyUpgraded
         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
-                perform_pre_commit(sh)
             sh.call("git", "remote", "add", "scripts", repo)
             sh.call("git", "fetch", "scripts")
             user_commit, next_commit = calculate_parents(sh, version)
@@ -71,23 +79,13 @@ def main(argv, baton):
     #   - merge could fail (race); that's /really/ dangerous.
     sh.call("git", "pull", temp_wc_dir, "master")
     # run update script
-    d.application.upgrade(options)
+    version_obj = distutils.version.LooseVersion(version.partition('-')[2])
+    d.application.upgrade(version_obj, options)
     # XXX: frob .htaccess to make site accessible
     # XXX:  - check if .htaccess changed, first.  Upgrade
     #       process might have frobbed it.  Don't be
     #       particularly worried if the segment dissappeared
 
-def make_deployment_from_cwd():
-    if not os.path.isdir(".git"):
-        raise NotAutoinstallError()
-    try:
-        d = deploy.Deployment(".")
-    except IOError as e:
-        if e.errno == errno.ENOENT:
-            raise NotAutoinstallError()
-        else: raise e
-    return d
-
 def make_commit_message(version):
     message = "Upgraded autoinstall in %s to %s.\n\n%s" % (util.get_dir_owner(), version, util.get_git_footer())
     try:
@@ -152,6 +150,7 @@ def perform_merge(sh, repo, d, version):
         sh.call("git", "merge", next_virtual_commit)
     except shell.CallError:
         print os.getcwd()
+        logging.info("Conflict info:\n", sh.eval("git", "diff"))
         raise MergeFailed
 
 def parse_args(argv, baton):
@@ -168,6 +167,8 @@ WARNING: This is still experimental."""
     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.")
+    parser.add_option("--force", dest="force", action="store_true",
+            default=False, help="Force running upgrade even if it's already at latest version.")
     baton.push(parser, "srv_path")
     options, args = parser.parse_all(argv)
     if len(args) > 1:
@@ -178,13 +179,11 @@ class Error(command.Error):
     """Base exception for all exceptions raised by upgrade"""
     pass
 
-class NotAutoinstallError(Error):
+class AlreadyUpgraded(Error):
     def __str__(self):
         return """
 
-ERROR: Could not find .git file. Are you sure
-this is an autoinstalled application? Did you remember
-to migrate it?"""
+ERROR: This autoinstall is already at the latest version."""
 
 class MergeFailed(Error):
     def __str__(self):
@@ -195,3 +194,14 @@ 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`."""
+
+class LocalChangesError(Error):
+    def __str__(self):
+        return """
+
+ERROR: Local changes occurred in the install while the merge was
+being processed so that a pull would not result in a fast-forward.
+The best way to resolve this is probably to attempt an upgrade again,
+with git rerere to remember merge resolutions (XXX: not sure if
+this actually works)."""
+