]> git.decadent.org.uk Git - dak.git/blobdiff - dak/transitions.py
Merge first version of Marks cleanup branch
[dak.git] / dak / transitions.py
old mode 100755 (executable)
new mode 100644 (file)
index 530ef0c..374beab
@@ -23,7 +23,7 @@
 
 ################################################################################
 
-import os, pg, sys, time, errno, fcntl, tempfile, pwd
+import os, pg, sys, time, errno, fcntl, tempfile, pwd, re
 import apt_pkg
 import daklib.database
 import daklib.utils
@@ -34,6 +34,8 @@ Cnf = None
 Options = None
 projectB = None
 
+re_broken_package = re.compile(r"[a-zA-Z]\w+\s+\-.*")
+
 ################################################################################
 
 #####################################
@@ -73,7 +75,7 @@ def init():
 
     projectB = pg.connect(Cnf["DB::Name"], Cnf["DB::Host"], int(Cnf["DB::Port"]))
     daklib.database.init(Cnf, projectB)
-    
+
 ################################################################################
 
 def usage (exit_code=0):
@@ -110,42 +112,66 @@ def load_transitions(trans_file):
 
     # lets do further validation here
     checkkeys = ["source", "reason", "packages", "new", "rm"]
-    for test in trans:
-        t = trans[test]
-
-        # First check if we know all the keys for the transition and if they have
-        # the right type (and for the packages also if the list has the right types
-        # included, ie. not a list in list, but only str in the list)
-        for key in t:
-            if key not in checkkeys:
-                print "ERROR: Unknown key %s in transition %s" % (key, test)
-                failure = True
-
-            if key == "packages":
-                if type(t[key]) != list:
-                    print "ERROR: Unknown type %s for packages in transition %s." % (type(t[key]), test)
-                    failure = True
 
-                try:
-                    for package in t["packages"]:
-                        if type(package) != str:
-                            print "ERROR: Packages list contains invalid type %s (as %s) in transition %s" % (type(package), package, test)
-                            failure = True
-                except TypeError:
-                    # In case someone has an empty packages list
-                    print "ERROR: No packages defined in transition %s" % (test)
+    # If we get an empty definition - we just have nothing to check, no transitions defined
+    if type(trans) != dict:
+        # This can be anything. We could have no transitions defined. Or someone totally fucked up the
+        # file, adding stuff in a way we dont know or want. Then we set it empty - and simply have no
+        # transitions anymore. User will see it in the information display after he quit the editor and
+        # could fix it
+        trans = ""
+        return trans
+
+    try:
+        for test in trans:
+            t = trans[test]
+
+            # First check if we know all the keys for the transition and if they have
+            # the right type (and for the packages also if the list has the right types
+            # included, ie. not a list in list, but only str in the list)
+            for key in t:
+                if key not in checkkeys:
+                    print "ERROR: Unknown key %s in transition %s" % (key, test)
                     failure = True
-                    continue
 
-            elif type(t[key]) != str:
-                print "ERROR: Unknown type %s for key %s in transition %s" % (type(t[key]), key, test)
-                failure = True
+                if key == "packages":
+                    if type(t[key]) != list:
+                        print "ERROR: Unknown type %s for packages in transition %s." % (type(t[key]), test)
+                        failure = True
+                    try:
+                        for package in t["packages"]:
+                            if type(package) != str:
+                                print "ERROR: Packages list contains invalid type %s (as %s) in transition %s" % (type(package), package, test)
+                                failure = True
+                            if re_broken_package.match(package):
+                                # Someone had a space too much (or not enough), we have something looking like
+                                # "package1 - package2" now.
+                                print "ERROR: Invalid indentation of package list in transition %s, around package(s): %s" % (test, package)
+                                failure = True
+                    except TypeError:
+                        # In case someone has an empty packages list
+                        print "ERROR: No packages defined in transition %s" % (test)
+                        failure = True
+                        continue
+
+                elif type(t[key]) != str:
+                    if key == "new" and type(t[key]) == int:
+                        # Ok, debian native version
+                        continue
+                    else:
+                        print "ERROR: Unknown type %s for key %s in transition %s" % (type(t[key]), key, test)
+                        failure = True
+
+            # And now the other way round - are all our keys defined?
+            for key in checkkeys:
+                if key not in t:
+                    print "ERROR: Missing key %s in transition %s" % (key, test)
+                    failure = True
+    except TypeError:
+        # In case someone defined very broken things
+        print "ERROR: Unable to parse the file"
+        failure = True
 
-        # And now the other way round - are all our keys defined?
-        for key in checkkeys:
-            if key not in t:
-                print "ERROR: Missing key %s in transition %s" % (key, test)
-                failure = True
 
     if failure:
         return None
@@ -157,9 +183,9 @@ def load_transitions(trans_file):
 #####################################
 #### This may run within sudo !! ####
 #####################################
-def lock_file(file):
+def lock_file(f):
     for retry in range(10):
-        lock_fd = os.open(file, os.O_RDWR | os.O_CREAT)
+        lock_fd = os.open(f, os.O_RDWR | os.O_CREAT)
         try:
             fcntl.lockf(lock_fd, fcntl.LOCK_EX | fcntl.LOCK_NB)
             return lock_fd
@@ -171,7 +197,7 @@ def lock_file(file):
             else:
                 raise
 
-    daklib.utils.fubar("Couldn't obtain lock for %s." % (lockfile))
+    daklib.utils.fubar("Couldn't obtain lock for %s." % (f))
 
 ################################################################################
 
@@ -187,7 +213,7 @@ def write_transitions(from_trans):
 
     trans_file = Cnf["Dinstall::Reject::ReleaseTransitions"]
     trans_temp = trans_file + ".tmp"
-  
+
     trans_lock = lock_file(trans_file)
     temp_lock  = lock_file(trans_temp)
 
@@ -217,7 +243,7 @@ def write_transitions_from_file(from_file):
         sys.exit(3)
 
     if Options["sudo"]:
-        os.spawnl(os.P_WAIT, "/usr/bin/sudo", "/usr/bin/sudo", "-u", "dak", "-H", 
+        os.spawnl(os.P_WAIT, "/usr/bin/sudo", "/usr/bin/sudo", "-u", "dak", "-H",
               "/usr/local/bin/dak", "transitions", "--import", from_file)
     else:
         trans = load_transitions(from_file)
@@ -231,7 +257,7 @@ def temp_transitions_file(transitions):
     # NB: file is unlinked by caller, but fd is never actually closed.
     # We need the chmod, as the file is (most possibly) copied from a
     # sudo-ed script and would be unreadable if it has default mkstemp mode
-    
+
     (fd, path) = tempfile.mkstemp("", "transitions", Cnf["Transitions::TempPath"])
     os.chmod(path, 0644)
     f = open(path, "w")
@@ -251,7 +277,7 @@ def edit_transitions():
         if result != 0:
             os.unlink(edit_file)
             daklib.utils.fubar("%s invocation failed for %s, not removing tempfile." % (editor, edit_file))
-    
+
         # Now try to load the new file
         test = load_transitions(edit_file)
 
@@ -266,8 +292,8 @@ def edit_transitions():
             print "------------------------------------------------------------------------"
             transition_info(test)
 
-           prompt = "[S]ave, Edit again, Drop changes?"
-           default = "S"
+            prompt = "[S]ave, Edit again, Drop changes?"
+            default = "S"
 
         answer = "XXX"
         while prompt.find(answer) == -1:
@@ -351,7 +377,7 @@ def check_transitions(transitions):
             print "Committing"
             for remove in to_remove:
                 del transitions[remove]
-    
+
             edit_file = temp_transitions_file(transitions)
             write_transitions_from_file(edit_file)
 
@@ -363,14 +389,14 @@ def check_transitions(transitions):
 ################################################################################
 
 def print_info(trans, source, expected, rm, reason, packages):
-        print """Looking at transition: %s
- Source:      %s
- New Version: %s
- Responsible: %s
- Description: %s
- Blocked Packages (total: %d): %s
+    print """Looking at transition: %s
+Source:      %s
+New Version: %s
+Responsible: %s
+Description: %s
+Blocked Packages (total: %d): %s
 """ % (trans, source, expected, rm, reason, len(packages), ", ".join(packages))
-        return
+    return
 
 ################################################################################
 
@@ -409,7 +435,7 @@ def main():
     #### This can run within sudo !! ####
     #####################################
     init()
-    
+
     # Check if there is a file defined (and existant)
     transpath = Cnf.get("Dinstall::Reject::ReleaseTransitions", "")
     if transpath == "":
@@ -428,7 +454,7 @@ def main():
         daklib.utils.warn("Temporary path %s not found." %
                           (Cnf["Transitions::TempPath"]))
         sys.exit(1)
-   
+
     if Options["import"]:
         try:
             write_transitions_from_file(Options["import"])
@@ -459,7 +485,7 @@ def main():
         transition_info(transitions)
 
     sys.exit(0)
-    
+
 ################################################################################
 
 if __name__ == '__main__':