Gaudi Framework, version v22r0

Home   Generated: 9 Feb 2011

validate_patch.py

Go to the documentation of this file.
00001 #!/usr/bin/env python
00002 """
00003 Simple script for automatic validation of a patch.
00004 
00005 Usage:
00006    validate_patch.py <savannah patch id>
00007    validate_patch.py file.patch
00008 """
00009 
00010 __author__ = "Marco Clemencic <marco.clemencic@cern.ch>"
00011 
00012 import os, sys
00013 import logging
00014 from shutil import rmtree
00015 from tempfile import mkdtemp
00016 from subprocess import Popen, PIPE
00017 
00018 from HTMLParser import HTMLParser
00019 from urllib import urlopen
00020 
00021 class PatchData(object):
00022     def __init__(self, id = None, title = None, files = None):
00023         self.id = None
00024         self.title = None
00025         if files is None:
00026             self.files = []
00027     def __repr__(self):
00028         r = self.__class__.__name__ + "("
00029         fields = []
00030         if self.id is not None:
00031             fields.append("id=%r" % self.id)
00032         if self.title is not None:
00033             fields.append("title=%r" % self.title)
00034         if self.files:
00035             fields.append("files=%r" % self.files)
00036         return "%s(%s)" % (self.__class__.__name__, ",".join(fields))
00037 
00038 ## parse the 
00039 class SavannahParser(HTMLParser):
00040     __attachments_id__ = "hidsubpartcontentattached"
00041     def __init__(self):
00042         HTMLParser.__init__(self)
00043         # data collected
00044         self.patch = None
00045         
00046         # parsing flags and temporary data
00047         self._parsingAttachments = 0 # depth of span tag in the attachment block
00048         self._currentFileId = None
00049         self._currentFileData = ""
00050         
00051         # temporary storage
00052     
00053     def handle_starttag(self, tag, attrs):
00054         attrs = dict(attrs)
00055         if tag == "html":
00056             # new file: new patch data 
00057             self.patch = PatchData()
00058         elif tag == "span":
00059             if attrs.get("id", None) == self.__attachments_id__:
00060                 self._parsingAttachments = 1
00061             elif self._parsingAttachments:
00062                 self._parsingAttachments += 1
00063         elif (self._parsingAttachments
00064               and tag == "a"
00065               and "file_id=" in attrs.get("href", "")):
00066             self._currentFileId = attrs["href"].split("file_id=")[-1]
00067     def handle_endtag(self, tag):
00068         if tag == "span" and self._parsingAttachments:
00069             self._parsingAttachments -= 1
00070         elif tag == "a" and self._currentFileId:
00071             #print self._currentFileData
00072             filename = self._currentFileData.split(":")[-1].strip()
00073             #print filename, self._currentFileId
00074             self.patch.files.append((filename, int(self._currentFileId)))
00075             self._currentFileId = None
00076             self._currentFileData = ""
00077             
00078     def handle_data(self, data):
00079         if self._currentFileId:
00080             data = data.replace("&nbsp;", " ")
00081             self._currentFileData += data
00082 
00083 def get_patch_info_x(patch):
00084     patch = int(patch)
00085     server = "savannah.cern.ch"
00086     path =  "/patch/?%d" % patch
00087     conn = httplib.HTTPSConnection(server)
00088     conn.request("GET", path)
00089     r = conn.getresponse()
00090     if r.status == 200:
00091         pass
00092     else:
00093         raise RuntimeError(r.status, r.reason, "https://" + server + path)
00094     parser = SavannahParser()
00095     parser.feed(r.read())
00096     parser.close()
00097     conn.close()
00098     return parser.patch
00099 
00100 def get_patch_info(patch):
00101     patch = int(patch)
00102     parser = SavannahParser()
00103     parser.feed(urlopen("https://savannah.cern.ch/patch/?%d" % patch).read())
00104     parser.close()
00105     return parser.patch
00106 
00107 def get_patch_data(file_id):
00108     file_id = int(file_id)
00109     return urlopen("https://savannah.cern.ch/patch/download.php?file_id=%d" % file_id).read()
00110 
00111 class TempDir(object):
00112     """Class to create a temporary directory."""
00113     def __init__(self, suffix="", prefix="tmp", dir=None, keep_var="KEEPTEMPDIR"):
00114         """Constructor.
00115         
00116         'keep_var' is used to define which environment variable will prevent the
00117         deletion of the directory.
00118         
00119         The other arguments are the same as tempfile.mkdtemp.
00120         """
00121         self._keep_var = keep_var 
00122         self._name = mkdtemp(suffix, prefix, dir)
00123 
00124     def getName(self):
00125         """Returns the name of the temporary directory"""
00126         return self._name
00127     
00128     def __str__(self):
00129         """Convert to string."""
00130         return self.getName()
00131 
00132     def __del__(self):
00133         """Destructor.
00134         
00135         Remove the temporary directory.
00136         """
00137         if self._name:
00138             if self._keep_var in os.environ:
00139                 logging.info("%s set: I do not remove the temporary directory '%s'",
00140                              self._keep_var, self._name)
00141                 return
00142             rmtree(self._name)
00143 
00144 def check_out_gaudi(path):
00145     return Popen(["svn", "co", "http://svnweb.cern.ch/guest/gaudi/Gaudi/trunk", os.path.join(path, "Gaudi")]).wait()
00146 
00147 def apply_patch(patch_data, path):
00148     proc = Popen(["patch", "-p0", "--batch"], cwd = path, stdin = PIPE)
00149     proc.communicate(patch_data)
00150     return proc.returncode
00151 
00152 def check(path):
00153     return Popen(" ".join(["cmt", "show", "projects"]), shell = True, cwd = path).wait()
00154 
00155 def build(path):
00156     if "LBCONFIGURATIONROOT" in os.environ:
00157         cmd = ["make",
00158                "-f", os.path.join(os.environ["LBCONFIGURATIONROOT"], "data", "Makefile")]
00159         if "use-distcc" in os.environ.get("CMTEXTRATAGS",""): 
00160                cmd += ["-j", "6"]
00161     else:
00162         cmd = ["cmt", "-pack=GaudiRelease", "broadcast", "cmt", "make", "all_groups"]
00163     return Popen(" ".join(cmd),
00164                  shell = True,
00165                  cwd = path).wait()
00166 def test(path):
00167     cmd = ["cmt", "-pack=GaudiRelease", "TestProject"]
00168     proc = Popen(" ".join(cmd),
00169                  stdout = PIPE,
00170                  shell = True,
00171                  cwd = path)
00172     output = []
00173     while proc.poll() is None:
00174         chunk = proc.stdout.read(256)
00175         output.append(chunk) 
00176         sys.stdout.write(chunk)
00177         sys.stdout.flush()
00178     chunk = proc.stdout.read(256)
00179     output.append(chunk) 
00180     sys.stdout.write(chunk)
00181     sys.stdout.flush()
00182     if proc.returncode:
00183         # immediately return in case of failure
00184         return proc.returncode
00185     # look for failures in the output
00186     output = ("".join(output)).splitlines()
00187     for l in output:
00188         l = l.strip()
00189         if ": FAIL" in l or ": ERROR" in l:
00190             return 1 
00191     return 0
00192 
00193 def main():
00194     logging.basicConfig()
00195     if len(sys.argv) != 2:
00196         print """Usage:
00197    validate_patch.py <savannah patch id>
00198    validate_patch.py file.patch
00199 """
00200         return 2
00201     patch_id = sys.argv[1]
00202     if os.path.isfile(patch_id):
00203         patch_data = open(patch_id, "rb").read()
00204     else:
00205         patch = get_patch_info(patch_id)
00206         patch_file_id = patch.files[0][1]
00207         patch_data = get_patch_data(patch_file_id)
00208     
00209     td = TempDir(prefix = patch_id + "-")
00210     if check_out_gaudi(str(td)) != 0:
00211         print "Sorry, problems checking out Gaudi. Try again."
00212         return 0
00213     top_dir = os.path.join(str(td), "Gaudi")
00214     open(os.path.join(top_dir, patch_id) ,"wb").write(patch_data)
00215     
00216     revision = -1
00217     for l in Popen(["svn", "info", top_dir], stdout = PIPE).communicate()[0].splitlines():
00218         if l.startswith("Revision:"):
00219             revision = int(l.split()[-1])
00220             break
00221     
00222     actions = [(lambda path: apply_patch(patch_data, path), "application of the patch"),
00223                (check, "check of the configuration"),
00224                (build, "build"),
00225                (test, "test"),
00226                ]
00227     failure = False
00228     for action, title in actions:
00229         if action(top_dir) != 0:
00230             failure = title
00231             break
00232     
00233     if failure:
00234         print "*** Patch %s failed during %s (using revision r%d) ***" % (patch_id, failure, revision)
00235         return 1
00236     
00237     print "*** Patch %s succeeded (using revision r%d) ***" % (patch_id, revision)
00238     return 0
00239 
00240 if __name__ == "__main__":
00241     sys.exit(main())
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Defines

Generated at Wed Feb 9 16:24:59 2011 for Gaudi Framework, version v22r0 by Doxygen version 1.6.2 written by Dimitri van Heesch, © 1997-2004