]> scripts.mit.edu Git - wizard.git/commitdiff
Flesh out research errors, fix bad merge commit.
authorEdward Z. Yang <ezyang@mit.edu>
Sat, 22 Aug 2009 02:07:00 +0000 (22:07 -0400)
committerEdward Z. Yang <ezyang@mit.edu>
Sat, 22 Aug 2009 02:07:00 +0000 (22:07 -0400)
Signed-off-by: Edward Z. Yang <ezyang@mit.edu>
wizard/command/mass_migrate.py
wizard/command/migrate.py
wizard/command/research.py
wizard/deploy.py

index a304ff5de6d8d6c73fb31d74c671d75dbc14b937..b3198dcbef2cb9a9f89395bd94f70e5746462453 100644 (file)
@@ -6,6 +6,7 @@ import pwd
 import hashlib
 import errno
 import time
+import itertools
 
 import wizard
 from wizard import deploy, util, shell, sset, command
@@ -23,11 +24,10 @@ def main(argv, baton):
     errors = {}
     i = 0
     # [] needed to workaround subtle behavior of frozenset("")
-    for d in deploy.parse_install_lines([app], options.versions_path):
+    deploys = deploy.parse_install_lines([app], options.versions_path)
+    requested_deploys = itertools.islice(deploys, options.limit)
+    for i, d in enumerate(requested_deploys, 1)
         # check if we want to punt due to --limit
-        i += 1
-        if options.limit and i > options.limit:
-            break
         if d.location in seen:
             continue
         if is_root and not security_check_homedir(d):
index 22cb38e99169d8af15de27622436815fe38b7960..937dc52d2ba38183a96fc47ce02676c0b37c84bc 100644 (file)
@@ -90,55 +90,6 @@ def perform_force(options):
     has_git = os.path.isdir(".git")
     has_scripts = os.path.isdir(".scripts")
 
-<<<<<<< HEAD
-    # deal with old-style migration
-    if os.path.isfile(".scripts/old-version") and not os.path.isfile(".scripts-version"):
-        os.rename(".scripts/old-version", ".scripts-version")
-
-    if not has_git and has_scripts:
-        if not options.force:
-            raise CorruptedAutoinstallError(dir)
-    elif has_git and not has_scripts:
-        # can't force this
-        raise AlreadyVersionedError(dir)
-    elif has_git and has_scripts:
-        if not options.force:
-            raise AlreadyMigratedError(dir)
-
-    if options.force:
-        def rm_with_backup(file):
-            prefix = "%s.bak" % file
-            name = None
-            for i in itertools.count():
-                name = "%s.%d" % (prefix, i)
-                if not os.path.exists(name):
-                    break
-            logging.warning("Force removing %s directory (backup at %s)" % (file, name))
-            os.rename(file, name)
-        if has_git:
-            if not options.dry_run:
-                rm_with_backup(".git")
-        if has_scripts:
-            if not options.dry_run:
-                rm_with_backup(".scripts")
-
-def make_deployment():
-    try:
-        return deploy.Deployment(".")
-    except IOError as e:
-        if e.errno == errno.ENOENT:
-            raise NotAutoinstallError(dir)
-        else: raise e
-
-def check_if_tag_exists(sh, repo, tag, version):
-    # check if the version we're trying to convert exists. We assume
-    # a convention here, namely, app-1.2.3-scripts is what we want. If
-    # you broke the convention... shame on you.
-    try:
-        sh.call("git", "--git-dir", repo, "rev-parse", tag)
-    except shell.CallError:
-        raise NoTagError(version)
-=======
     if has_git:
         logging.warning("Force removing .git directory")
         if not options.dry_run: backup = safe_unlink(".git")
@@ -158,7 +109,6 @@ def safe_unlink(file):
             break
     os.rename(file, name)
     return name
->>>>>>> 255245146b500845fa13a75bfbeb6cece074417c
 
 def make_repository(sh, options, repo, tag):
     sh.call("git", "init") # create repository
index 53f3d4a43791eba7f38785f4075282d567a4afc4..46164e7132d3622d89de437a05750f3fd2305483 100644 (file)
 import logging
 import traceback
 import os.path
+import itertools
+import random
 
 from wizard import command, deploy, shell, util
 
 def main(argv, baton):
     options, show = parse_args(argv, baton)
     sh = shell.Shell()
-    for d in deploy.parse_install_lines(show, options.versions_path):
-        try:
-            d.verify()
-            d.verifyTag(options.srv_path)
-            d.verifyGit(options.srv_path)
-            d.verifyConfigured()
-            print d.location
-            with util.ChangeDirectory(d.location):
-                print sh.safeCall('git', 'diff', '--stat', d.app_version.scripts_tag, 'HEAD', strip=True)
-        except deploy.Error as e:
-            continue
+    deploys = deploy.parse_install_lines(show, options.versions_path)
+    stats = {}
+    iffy = 0
+    clean = 0
+    total = 0
+    deploys = itertools.islice(deploys, options.limit)
+    if options.sample:
+        deploys = random.sample(list(deploys), options.sample)
+    try:
+        for d in deploys:
+            logging.info("Processing " + d.location)
+            try:
+                d.verify()
+                d.verifyTag(options.srv_path)
+                d.verifyGit(options.srv_path)
+                d.verifyConfigured()
+                with util.ChangeDirectory(d.location):
+                    results = []
+                    out = sh.safeCall('git', 'diff', '--numstat', d.app_version.scripts_tag, strip=True)
+                    total += 1
+                    for line in out.split("\n"):
+                        added, deleted, filename = line.split(None, 3)
+                        if filename.endswith("php.ini"): continue
+                        if added == '-': continue
+                        if deleted == '-': continue
+                        added = int(added)
+                        deleted = int(deleted)
+                        # hook
+                        if filename == "LocalSettings.php":
+                            if added == deleted == 10:
+                                continue
+                            elif added == deleted == 9:
+                                continue
+                        elif filename == "AdminSettings.php":
+                            if added == 0 and deleted == 20:
+                                continue
+                        elif filename == "config/index.php" or filename == "config/index.php5":
+                            if added == 0:
+                                continue
+                        if not added and not deleted:
+                            continue
+                        results.append((added,deleted,filename))
+                    if len(results) > options.filter:
+                        print "-       -       " +  d.location
+                        iffy += 1
+                        continue
+                    if not results:
+                        clean += 1
+                    for added,deleted,filename in results:
+                        stats.setdefault(filename, 0)
+                        stats[filename] += 1
+                        # hook
+                        if filename == "LocalSettings.php" and not options.verbose:
+                            continue
+                        print "%-7d %-7d %s/%s" % (added,deleted,d.location,filename)
+            except (deploy.NotConfiguredError, deploy.NotMigratedError):
+                # XXX: These should error, but for now don't
+                pass
+            except (deploy.Error, shell.CallError):
+                logging.error("%s in %s" % (traceback.format_exc(), d.location))
+            except KeyboardInterrupt:
+                raise
+            except:
+                logging.critical("%s in %s" % (traceback.format_exc(), d.location))
+    except KeyboardInterrupt:
+        print
+        print "Caught signal..."
+        pass
+    print '-' * 50
+    for filename in sorted(stats.keys()):
+        count = stats[filename]
+        if not count: continue
+        print "%-7d %s" % (count, filename)
+    print '-' * 50
+    print "%d out of %d (%.1f%%) had large diffstats" % (iffy, total, float(iffy)/total*100)
+    print "%d out of %d (%.1f%%) had clean diffstats" % (clean, total, float(clean)/total*100)
 
 def parse_args(argv, baton):
     usage = """usage: %prog research APP
 
 Tells you how spectacularly an upgrade here will explode."""
     parser = command.WizardOptionParser(usage)
+    parser.add_option("--limit", dest="limit", type="int",
+            default=None, help="Limit the number of autoinstalls to look at.")
+    parser.add_option("--sample", dest="sample", type="int", metavar="N",
+            default=None, help="Instead of researching all installs, research a random sample of N size.")
+    parser.add_option("--filter", dest="filter", type="int", metavar="N",
+            default=4, help="How many files are permitted in a diffstat before treating the install as having a 'large diffstat'")
     baton.push(parser, "srv_path")
     baton.push(parser, "versions_path")
     options, args = parser.parse_all(argv)
index f6292b9d091cc68f66a033b39c1559fb128f3608..e591d36426ba46ecd288b6b636513cae56ea761b 100644 (file)
@@ -135,7 +135,7 @@ class Deployment(object):
         """
         repo = self.application.repository(srv_path)
         try:
-            shell.Shell().eval("git", "--git-dir", repo, "rev-parse", self.app_version.scripts_tag)
+            shell.Shell().eval("git", "--git-dir", repo, "rev-parse", self.app_version.scripts_tag, '--')
         except shell.CallError:
             raise NoTagError(self.app_version.scripts_tag)
 
@@ -152,17 +152,20 @@ class Deployment(object):
             def repo_rev_parse(tag):
                 return sh.eval("git", "--git-dir", repo, "rev-parse", tag)
             def self_rev_parse(tag):
-                return sh.safeCall("git", "rev-parse", tag, strip=True)
+                try:
+                    return sh.safeCall("git", "rev-parse", tag, strip=True)
+                except shell.CallError:
+                    raise NoLocalTagError(tag)
             def compare_tags(tag):
                 return repo_rev_parse(tag) == self_rev_parse(tag)
             if not compare_tags(self.app_version.pristine_tag):
-                raise InconsistentPristineTagError()
+                raise InconsistentPristineTagError(self.app_version.pristine_tag)
             if not compare_tags(self.app_version.scripts_tag):
-                raise InconsistentScriptsTagError()
+                raise InconsistentScriptsTagError(self.app_version.scripts_tag)
             parent = repo_rev_parse(self.app_version.scripts_tag)
             merge_base = sh.safeCall("git", "merge-base", parent, "HEAD", strip=True)
             if merge_base != parent:
-                raise HeadNotDescendantError()
+                raise HeadNotDescendantError(self.app_version.scripts_tag)
 
     def verifyConfigured(self):
         """
@@ -543,6 +546,42 @@ class NoTagError(Error):
 
 ERROR: Could not find tag %s in repository.""" % self.tag
 
+class NoLocalTagError(Error):
+    def __init__(self, tag):
+        self.tag = tag
+    def __str__(self):
+        return """
+
+ERROR: Could not find tag %s in local repository.""" % self.tag
+
+class InconsistentPristineTagError(Error):
+    def __init__(self, tag):
+        self.tag = tag
+    def __str__(self):
+        return """
+
+ERROR: Local pristine tag %s did not match repository's.  This
+probably means an upstream rebase occured.""" % self.tag
+
+class InconsistentScriptsTagError(Error):
+    def __init__(self, tag):
+        self.tag = tag
+    def __str__(self):
+        return """
+
+ERROR: Local scripts tag %s did not match repository's.  This
+probably means an upstream rebase occurred.""" % self.tag
+
+class HeadNotDescendantError(Error):
+    def __init__(self, tag):
+        self.tag = tag
+    def __str__(self):
+        return """
+
+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
+
 _application_list = [
     "mediawiki", "wordpress", "joomla", "e107", "gallery2",
     "phpBB", "advancedbook", "phpical", "trac", "turbogears", "django",