| The Gaudi Framework v27r1

- Main Page
- Related Pages
- Modules
- Namespaces
- Classes
- Files

- File List
- File Members

validate_patch.py
Go to the documentation of this file.
1 #!/usr/bin/env python
2 """
3 Simple script for automatic validation of a patch.
4
5 Usage:
6 validate_patch.py <savannah patch id>
7 validate_patch.py file.patch
8 """
9
10 __author__ = "Marco Clemencic <marco.clemencic@cern.ch>"
11
12 import os, sys
13 import logging
14 from shutil import rmtree
15 from tempfile import mkdtemp
16 from subprocess import Popen, PIPE
17
18 from HTMLParser import HTMLParser
19 from urllib import urlopen
20
21 class PatchData(object):
22 def __init__(self, id = None, title = None, files = None):
23 self.id = None
24 self.title = None
25 if files is None:
26 self.files = []
27 def __repr__(self):
28 r = self.__class__.__name__ + "("
29 fields = []
30 if self.id is not None:
31 fields.append("id=%r" % self.id)
32 if self.title is not None:
33 fields.append("title=%r" % self.title)
34 if self.files:
35 fields.append("files=%r" % self.files)
36 return "%s(%s)" % (self.__class__.__name__, ",".join(fields))
37
38 ## parse the
39 class SavannahParser(HTMLParser):
40 __attachments_id__ = "hidsubpartcontentattached"
41 def __init__(self):
42 HTMLParser.__init__(self)
43 # data collected
44 self.patch = None
45
46 # parsing flags and temporary data
47 self._parsingAttachments = 0 # depth of span tag in the attachment block
48 self._currentFileId = None
49 self._currentFileData = ""
50
51 # temporary storage
52
53 def handle_starttag(self, tag, attrs):
54 attrs = dict(attrs)
55 if tag == "html":
56 # new file: new patch data
57 self.patch = PatchData()
58 elif tag == "span":
59 if attrs.get("id", None) == self.__attachments_id__:
60 self._parsingAttachments = 1
61 elif self._parsingAttachments:
62 self._parsingAttachments += 1
63 elif (self._parsingAttachments
64 and tag == "a"
65 and "file_id=" in attrs.get("href", "")):
66 self._currentFileId = attrs["href"].split("file_id=")[-1]
67 def handle_endtag(self, tag):
68 if tag == "span" and self._parsingAttachments:
69 self._parsingAttachments -= 1
70 elif tag == "a" and self._currentFileId:
71 #print self._currentFileData
72 filename = self._currentFileData.split(":")[-1].strip()
73 #print filename, self._currentFileId
74 self.patch.files.append((filename, int(self._currentFileId)))
75 self._currentFileId = None
76 self._currentFileData = ""
77
78 def handle_data(self, data):
79 if self._currentFileId:
80 data = data.replace("&nbsp;", " ")
81 self._currentFileData += data
82
83 def get_patch_info_x(patch):
84 patch = int(patch)
85 server = "savannah.cern.ch"
86 path = "/patch/?%d" % patch
87 conn = httplib.HTTPSConnection(server)
88 conn.request("GET", path)
89 r = conn.getresponse()
90 if r.status == 200:
91 pass
92 else:
93 raise RuntimeError(r.status, r.reason, "https://" + server + path)
94 parser = SavannahParser()
95 parser.feed(r.read())
96 parser.close()
97 conn.close()
98 return parser.patch
99
100 def get_patch_info(patch):
101 patch = int(patch)
102 parser = SavannahParser()
103 parser.feed(urlopen("https://savannah.cern.ch/patch/?%d" % patch).read())
104 parser.close()
105 return parser.patch
106
107 def get_patch_data(file_id):
108 file_id = int(file_id)
109 return urlopen("https://savannah.cern.ch/patch/download.php?file_id=%d" % file_id).read()
110
111 class TempDir(object):
112 """Class to create a temporary directory."""
113 def __init__(self, suffix="", prefix="tmp", dir=None, keep_var="KEEPTEMPDIR"):
114 """Constructor.
115
116 'keep_var' is used to define which environment variable will prevent the
117 deletion of the directory.
118
119 The other arguments are the same as tempfile.mkdtemp.
120 """
121 self._keep_var = keep_var
122 self._name = mkdtemp(suffix, prefix, dir)
123
124 def getName(self):
125 """Returns the name of the temporary directory"""
126 return self._name
127
128 def __str__(self):
129 """Convert to string."""
130 return self.getName()
131
132 def __del__(self):
133 """Destructor.
134
135 Remove the temporary directory.
136 """
137 if self._name:
138 if self._keep_var in os.environ:
139 logging.info("%s set: I do not remove the temporary directory '%s'",
140 self._keep_var, self._name)
141 return
142 rmtree(self._name)
143
144 def check_out_gaudi(path):
145 return Popen(["svn", "co", "http://svnweb.cern.ch/guest/gaudi/Gaudi/trunk", os.path.join(path, "Gaudi")]).wait()
146
147 def apply_patch(patch_data, path):
148 proc = Popen(["patch", "-p0", "--batch"], cwd = path, stdin = PIPE)
149 proc.communicate(patch_data)
150 return proc.returncode
151
152 def check(path):
153 return Popen(" ".join(["cmt", "show", "projects"]), shell = True, cwd = path).wait()
154
155 def build(path):
156 if "LBCONFIGURATIONROOT" in os.environ:
157 cmd = ["make",
158 "-f", os.path.join(os.environ["LBCONFIGURATIONROOT"], "data", "Makefile")]
159 if "use-distcc" in os.environ.get("CMTEXTRATAGS",""):
160 cmd += ["-j", "6"]
161 else:
162 cmd = ["cmt", "-pack=GaudiRelease", "broadcast", "cmt", "make", "all_groups"]
163 return Popen(" ".join(cmd),
164 shell = True,
165 cwd = path).wait()
166 def test(path):
167 cmd = ["cmt", "-pack=GaudiRelease", "TestProject"]
168 proc = Popen(" ".join(cmd),
169 stdout = PIPE,
170 shell = True,
171 cwd = path)
172 output = []
173 while proc.poll() is None:
174 chunk = proc.stdout.read(256)
175 output.append(chunk)
176 sys.stdout.write(chunk)
177 sys.stdout.flush()
178 chunk = proc.stdout.read(256)
179 output.append(chunk)
180 sys.stdout.write(chunk)
181 sys.stdout.flush()
182 if proc.returncode:
183 # immediately return in case of failure
184 return proc.returncode
185 # look for failures in the output
186 output = ("".join(output)).splitlines()
187 for l in output:
188 l = l.strip()
189 if ": FAIL" in l or ": ERROR" in l:
190 return 1
191 return 0
192
193 def main():
194 logging.basicConfig()
195 if len(sys.argv) != 2:
196 print """Usage:
197 validate_patch.py <savannah patch id>
198 validate_patch.py file.patch
199 """
200 return 2
201 patch_id = sys.argv[1]
202 if os.path.isfile(patch_id):
203 patch_data = open(patch_id, "rb").read()
204 else:
205 patch = get_patch_info(patch_id)
206 patch_file_id = patch.files[0][1]
207 patch_data = get_patch_data(patch_file_id)
208
209 td = TempDir(prefix = patch_id + "-")
210 if check_out_gaudi(str(td)) != 0:
211 print "Sorry, problems checking out Gaudi. Try again."
212 return 0
213 top_dir = os.path.join(str(td), "Gaudi")
214 open(os.path.join(top_dir, patch_id) ,"wb").write(patch_data)
215
216 revision = -1
217 for l in Popen(["svn", "info", top_dir], stdout = PIPE).communicate()[0].splitlines():
218 if l.startswith("Revision:"):
219 revision = int(l.split()[-1])
220 break
221
222 actions = [(lambda path: apply_patch(patch_data, path), "application of the patch"),
223 (check, "check of the configuration"),
224 (build, "build"),
225 (test, "test"),
226 ]
227 failure = False
228 for action, title in actions:
229 if action(top_dir) != 0:
230 failure = title
231 break
232
233 if failure:
234 print "*** Patch %s failed during %s (using revision r%d) ***" % (patch_id, failure, revision)
235 return 1
236
237 print "*** Patch %s succeeded (using revision r%d) ***" % (patch_id, revision)
238 return 0
239
240 if __name__ == "__main__":
241 sys.exit(main())
validate_patch.SavannahParser._currentFileId
_currentFileId
Definition: validate_patch.py:48
validate_patch.PatchData.title
title
Definition: validate_patch.py:24
validate_patch.check
def check(path)
Definition: validate_patch.py:152
validate_patch.get_patch_data
def get_patch_data(file_id)
Definition: validate_patch.py:107
validate_patch.SavannahParser.handle_starttag
def handle_starttag(self, tag, attrs)
Definition: validate_patch.py:53
validate_patch.SavannahParser.__init__
def __init__(self)
Definition: validate_patch.py:41
validate_patch.build
def build(path)
Definition: validate_patch.py:155
validate_patch.TempDir.__str__
def __str__(self)
Definition: validate_patch.py:128
validate_patch.SavannahParser._parsingAttachments
_parsingAttachments
Definition: validate_patch.py:47
validate_patch.TempDir._name
_name
Definition: validate_patch.py:122
validate_patch.PatchData.__init__
def __init__
Definition: validate_patch.py:22
validate_patch.SavannahParser.handle_data
def handle_data(self, data)
Definition: validate_patch.py:78
validate_patch.get_patch_info_x
def get_patch_info_x(patch)
Definition: validate_patch.py:83
validate_patch.PatchData
Definition: validate_patch.py:21
validate_patch.apply_patch
def apply_patch(patch_data, path)
Definition: validate_patch.py:147
validate_patch.SavannahParser.handle_endtag
def handle_endtag(self, tag)
Definition: validate_patch.py:67
validate_patch.SavannahParser.patch
patch
Definition: validate_patch.py:44
validate_patch.PatchData.__repr__
def __repr__(self)
Definition: validate_patch.py:27
validate_patch.SavannahParser._currentFileData
_currentFileData
Definition: validate_patch.py:49
compareRootHistos.action
string action
Definition: compareRootHistos.py:320
validate_patch.PatchData.id
id
Definition: validate_patch.py:23
validate_patch.main
def main()
Definition: validate_patch.py:193
validate_patch.TempDir.__del__
def __del__(self)
Definition: validate_patch.py:132
validate_patch.TempDir.getName
def getName(self)
Definition: validate_patch.py:124
validate_patch.TempDir._keep_var
_keep_var
Definition: validate_patch.py:121
validate_patch.PatchData.files
files
Definition: validate_patch.py:26
validate_patch.get_patch_info
def get_patch_info(patch)
Definition: validate_patch.py:100
validate_patch.test
def test(path)
Definition: validate_patch.py:166
validate_patch.TempDir
Definition: validate_patch.py:111
validate_patch.TempDir.__init__
def __init__
Definition: validate_patch.py:113
validate_patch.SavannahParser
parse the
Definition: validate_patch.py:39
validate_patch.check_out_gaudi
def check_out_gaudi(path)
Definition: validate_patch.py:144
validate_patch.SavannahParser.__attachments_id__
string __attachments_id__
Definition: validate_patch.py:40