blob: 424b3c7f24219467392e3dffb9330e312a7e1c24 [file] [log] [blame]
Benny Prijono9be224f2008-12-29 17:57:13 +00001#
2# builder.py - PJSIP test scenarios builder
3#
4# Copyright (C) 2008-2009 Teluu Inc. (http://www.teluu.com)
5#
6# This program is free software; you can redistribute it and/or modify
7# it under the terms of the GNU General Public License as published by
8# the Free Software Foundation; either version 2 of the License, or
9# (at your option) any later version.
10#
11# This program is distributed in the hope that it will be useful,
12# but WITHOUT ANY WARRANTY; without even the implied warranty of
13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14# GNU General Public License for more details.
15#
16# You should have received a copy of the GNU General Public License
17# along with this program; if not, write to the Free Software
18# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19#
20
Benny Prijono49048d92008-12-29 14:56:32 +000021import ccdash
22import os
23import platform
24import re
25import subprocess
26import sys
27import time
28
29class Operation:
30 """\
31 The Operation class describes the individual ccdash operation to be
32 performed.
33
34 """
35 # Types:
36 UPDATE = "update" # Update operation
37 CONFIGURE = "configure" # Configure operation
38 BUILD = "build" # Build operation
39 TEST = "test" # Unit test operation
40
41 def __init__(self, type, cmdline, name="", wdir=""):
42 self.type = type
43 self.cmdline = cmdline
44 self.name = name
45 self.wdir = wdir
46 if self.type==self.TEST and not self.name:
47 raise "name required for tests"
48
49 def encode(self, base_dir):
50 s = [self.type]
51 if self.type == self.TEST:
52 s.append(self.name)
53 if self.type != self.UPDATE:
54 s.append(self.cmdline)
55 s.append("-w")
56 if self.wdir:
57 s.append(base_dir + "/" + self.wdir)
58 else:
59 s.append(base_dir)
60 return s
61
62
63#
64# Update operation
65#
66update_ops = [Operation(Operation.UPDATE, "")]
67
68#
69# The standard library tests (e.g. pjlib-test, pjsip-test, etc.)
70#
71std_test_ops= [
72 Operation(Operation.TEST, "./pjlib-test-$SUFFIX", name="pjlib test",
73 wdir="pjlib/bin"),
74 Operation(Operation.TEST, "./pjlib-util-test-$SUFFIX",
75 name="pjlib-util test", wdir="pjlib-util/bin"),
76 Operation(Operation.TEST, "./pjnath-test-$SUFFIX", name="pjnath test",
77 wdir="pjnath/bin"),
78 Operation(Operation.TEST, "./pjmedia-test-$SUFFIX", name="pjmedia test",
79 wdir="pjmedia/bin"),
80 Operation(Operation.TEST, "./pjsip-test-$SUFFIX", name="pjsip test",
81 wdir="pjsip/bin")
82]
83
84#
85# These are operations to build the software on GNU/Posix systems
86#
87gnu_build_ops = [
88 Operation(Operation.CONFIGURE, "./configure"),
89 Operation(Operation.BUILD, "make distclean; make dep && make; cd pjsip-apps/src/python; python setup.py clean build"),
90 #Operation(Operation.BUILD, "python setup.py clean build",
91 # wdir="pjsip-apps/src/python")
92]
93
94#
95# These are pjsua Python based unit test operations
96#
97def build_pjsua_test_ops():
98 ops = []
99 cwd = os.getcwd()
100 os.chdir("../pjsua")
101 os.system("python runall.py --list > list")
102 f = open("list", "r")
103 for e in f:
104 e = e.rstrip("\r\n ")
105 (mod,param) = e.split(None,2)
106 name = mod[4:mod.find(".py")] + "_" + \
107 param[param.find("/")+1:param.find(".py")]
108 ops.append(Operation(Operation.TEST, "python run.py " + e, name=name,
109 wdir="tests/pjsua"))
110 os.chdir(cwd)
111 return ops
112
113#
114# Get gcc version
115#
116def gcc_version(gcc):
117 proc = subprocess.Popen(gcc + " -v", stdout=subprocess.PIPE,
118 stderr=subprocess.STDOUT, shell=True)
119 ver = ""
120 while True:
121 s = proc.stdout.readline()
122 if not s:
123 break
124 if s.find("gcc version") >= 0:
125 ver = s.split(None, 3)[2]
126 break
127 proc.wait()
128 return "gcc-" + ver
129
130#
131# Test config
132#
133class BaseConfig:
134 def __init__(self, base_dir, url, site, group, options=None):
135 self.base_dir = base_dir
136 self.url = url
137 self.site = site
138 self.group = group
139 self.options = options
140
141#
142# Base class for test configurator
143#
144class TestBuilder:
145 def __init__(self, config, build_config_name="",
146 user_mak="", config_site="", exclude=[], not_exclude=[]):
147 self.config = config # BaseConfig instance
148 self.build_config_name = build_config_name # Optional build suffix
149 self.user_mak = user_mak # To be put in user.mak
150 self.config_site = config_site # To be put in config_s..
151 self.saved_user_mak = "" # To restore user.mak
152 self.saved_config_site = "" # To restore config_s..
153 self.exclude = exclude # List of exclude pattern
154 self.not_exclude = not_exclude # List of include pattern
155 self.ccdash_args = [] # ccdash cmd line
156
157 def stamp(self):
158 return time.strftime("%Y%m%d-%H%M", time.localtime())
159
160 def pre_action(self):
161 # Override user.mak
162 name = self.config.base_dir + "/user.mak"
163 if os.access(name, os.F_OK):
164 f = open(name, "r")
165 self.saved_user_mak = f.read()
166 f.close()
167 if True:
168 f = open(name, "wt")
169 f.write(self.user_mak)
170 f.close()
171 # Override config_site.h
172 name = self.config.base_dir + "/pjlib/include/pj/config_site.h"
173 if os.access(name, os.F_OK):
174 f = open(name, "r")
175 self.saved_config_site= f.read()
176 f.close()
177 if True:
178 f = open(name, "wt")
179 f.write(self.config_site)
180 f.close()
181
182
183 def post_action(self):
184 # Restore user.mak
185 name = self.config.base_dir + "/user.mak"
186 if self.saved_user_mak:
187 f = open(name, "wt")
188 f.write(self.saved_user_mak)
189 f.close()
190 else:
191 os.remove(name)
192 # Restore config_site.h
193 name = self.config.base_dir + "/pjlib/include/pj/config_site.h"
194 if self.saved_config_site:
195 f = open(name, "wt")
196 f.write(self.saved_config_site)
197 f.close()
198 else:
199 os.remove(name)
200
201 def build_tests(self):
202 # This should be overridden by subclasses
203 pass
204
205 def execute(self):
206 if len(self.ccdash_args)==0:
207 self.build_tests()
208 self.pre_action()
209 counter = 0
210 for a in self.ccdash_args:
211 # Check if this test is in exclusion list
212 fullcmd = " ".join(a)
213 excluded = False
214 included = False
215 for pat in self.exclude:
Benny Prijono9be224f2008-12-29 17:57:13 +0000216 if pat and re.search(pat, fullcmd) != None:
Benny Prijono49048d92008-12-29 14:56:32 +0000217 excluded = True
218 break
219 if excluded:
220 for pat in self.not_exclude:
Benny Prijono9be224f2008-12-29 17:57:13 +0000221 if pat and re.search(pat, fullcmd) != None:
Benny Prijono49048d92008-12-29 14:56:32 +0000222 included = True
223 break
224 if excluded and not included:
225 print "Skipping test '%s'.." % (fullcmd)
226 continue
227
228 #a.extend(["-o", "/tmp/xx" + a[0] + ".xml"])
229 #print a
230 #a = ["ccdash.py"].extend(a)
231 b = ["ccdash.py"]
232 b.extend(a)
233 a = b
234 #print a
235 ccdash.main(a)
236 counter = counter + 1
237 self.post_action()
238
239
240#
241# GNU test configurator
242#
243class GNUTestBuilder(TestBuilder):
244 def __init__(self, config, build_config_name="", user_mak="", \
245 config_site="", cross_compile="", exclude=[], not_exclude=[]):
246 TestBuilder.__init__(self, config, build_config_name=build_config_name,
247 user_mak=user_mak, config_site=config_site,
248 exclude=exclude, not_exclude=not_exclude)
249 self.cross_compile = cross_compile
250 if self.cross_compile and self.cross_compile[-1] != '-':
251 self.cross_compile.append("-")
252
253 def build_tests(self):
254 if self.cross_compile:
255 suffix = self.cross_compile
256 build_name = suffix + gcc_version(self.cross_compile + "gcc")
257 else:
258 proc = subprocess.Popen(self.config.base_dir+"/config.guess",
259 stdout=subprocess.PIPE)
260 suffix = proc.stdout.readline().rstrip(" \r\n")
261 build_name = suffix+"-"+gcc_version(self.cross_compile + "gcc")
262
263 if self.build_config_name:
264 build_name = build_name + "-" + self.build_config_name
265 cmds = []
266 cmds.extend(update_ops)
267 cmds.extend(gnu_build_ops)
268 cmds.extend(std_test_ops)
269 cmds.extend(build_pjsua_test_ops())
270 self.ccdash_args = []
271 for c in cmds:
272 c.cmdline = c.cmdline.replace("$SUFFIX", suffix)
273 args = c.encode(self.config.base_dir)
274 args.extend(["-U", self.config.url,
275 "-S", self.config.site,
276 "-T", self.stamp(),
277 "-B", build_name,
278 "-G", self.config.group])
279 args.extend(self.config.options)
280 self.ccdash_args.append(args)
281
282