2144.1.1
by patrick crews
Overhaul of code. We can run rabbitmq : ) We now better encapsulate a per-executor working environment = one step closer to --parallel >: ) using subprocess goodness for server control |
1 |
#! /usr/bin/env python
|
2235.5.2
by Stewart Smith
dbqp source (and all its libs) should use emacs python mode, not emacs C mode |
2 |
# -*- mode: python; indent-tabs-mode: nil; -*-
|
2088.9.1
by patrick crews
Updated tree so that test-run.pl and test-run.py may live together in peace for a time |
3 |
# vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
|
4 |
#
|
|
2337.1.15
by patrick crews
Code cleanup / reorganization |
5 |
# Copyright (C) 2010, 2011 Patrick Crews
|
2088.9.1
by patrick crews
Updated tree so that test-run.pl and test-run.py may live together in peace for a time |
6 |
#
|
2121.3.2
by patrick crews
Updated license verbiage |
7 |
# This program is free software; you can redistribute it and/or modify
|
8 |
# it under the terms of the GNU General Public License as published by
|
|
9 |
# the Free Software Foundation; either version 2 of the License, or
|
|
10 |
# (at your option) any later version.
|
|
11 |
#
|
|
12 |
# This program is distributed in the hope that it will be useful,
|
|
13 |
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
14 |
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
15 |
# GNU General Public License for more details.
|
|
16 |
#
|
|
17 |
# You should have received a copy of the GNU General Public License
|
|
18 |
# along with this program; if not, write to the Free Software
|
|
19 |
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
2121.3.1
by patrick crews
Added licensing text to dbqp files |
20 |
|
2088.9.1
by patrick crews
Updated tree so that test-run.pl and test-run.py may live together in peace for a time |
21 |
"""codeTree
|
22 |
||
23 |
definition of what a code tree should look like
|
|
24 |
to the test-runner (which files /directories it should find where)
|
|
25 |
|
|
26 |
Files paths can be in one of several locations that we locate via
|
|
27 |
systemManager methods
|
|
28 |
||
29 |
"""
|
|
30 |
# imports
|
|
31 |
import os |
|
2337.1.17
by patrick crews
Additional work for running MySQL servers (still not ready for prime-time / working) |
32 |
import sys |
2088.9.1
by patrick crews
Updated tree so that test-run.pl and test-run.py may live together in peace for a time |
33 |
|
34 |
||
35 |
class codeTree: |
|
36 |
""" Defines what files / directories we should find and where
|
|
37 |
allows for optional / required.
|
|
38 |
||
39 |
"""
|
|
40 |
||
41 |
def __init__(self, variables, system_manager): |
|
42 |
self.debug = variables['debug'] |
|
43 |
self.system_manager = system_manager |
|
44 |
self.logging = system_manager.logging |
|
45 |
||
46 |
def debug_status(self): |
|
47 |
self.logging.debug(self) |
|
48 |
for key, item in sorted(vars(self).items()): |
|
49 |
self.logging.debug("%s: %s" %(key, item)) |
|
50 |
||
51 |
class drizzleTree(codeTree): |
|
52 |
""" What a Drizzle code tree should look like to the test-runner
|
|
53 |
|
|
54 |
"""
|
|
55 |
||
56 |
def __init__(self, variables,system_manager): |
|
57 |
self.system_manager = system_manager |
|
58 |
self.logging = self.system_manager.logging |
|
2088.9.22
by patrick crews
Updated code to set LD_LIBRARY env vars |
59 |
self.skip_keys = ['ld_lib_paths'] |
2088.9.1
by patrick crews
Updated tree so that test-run.pl and test-run.py may live together in peace for a time |
60 |
self.debug = variables['debug'] |
61 |
self.verbose = variables['verbose'] |
|
2337.1.4
by patrick crews
Tweak of logging behavior (no more 'if debug' checks...) and related code cleanup. Also groundwork for allowing multiple basedirs (server code bases) to the test runner) |
62 |
self.basedir = self.system_manager.find_path([os.path.abspath(variables['basedir'][0])]) |
2088.9.1
by patrick crews
Updated tree so that test-run.pl and test-run.py may live together in peace for a time |
63 |
self.source_dist = os.path.isdir(os.path.join(self.basedir, 'drizzled')) |
2124.2.6
by Patrick Crews
make target for dbqp! : ) |
64 |
self.builddir = self.system_manager.find_path([os.path.abspath(self.basedir)]) |
2232.1.1
by patrick crews
Added top_builddir/libdrizzle/.libs to LD_LIBRARY_PATH |
65 |
self.top_builddir = variables['topbuilddir'] |
2124.2.6
by Patrick Crews
make target for dbqp! : ) |
66 |
self.testdir = self.system_manager.find_path([os.path.abspath(variables['testdir'])]) |
2088.9.1
by patrick crews
Updated tree so that test-run.pl and test-run.py may live together in peace for a time |
67 |
self.clientbindir = self.system_manager.find_path([os.path.join(self.builddir, 'client') |
68 |
, os.path.join(self.basedir, 'client') |
|
69 |
, os.path.join(self.basedir, 'bin')]) |
|
70 |
self.srcdir = self.system_manager.find_path([self.basedir]) |
|
2337.1.12
by patrick crews
Additional work on allowing dbqp to handle multiple server types / versions (even simultaneously) |
71 |
self.suite_paths = variables['suitepaths'] |
2088.9.1
by patrick crews
Updated tree so that test-run.pl and test-run.py may live together in peace for a time |
72 |
|
73 |
||
74 |
self.drizzle_client = self.system_manager.find_path([os.path.join(self.clientbindir, |
|
75 |
'drizzle')]) |
|
76 |
||
77 |
self.drizzledump = self.system_manager.find_path([os.path.join(self.clientbindir, |
|
78 |
'drizzledump')]) |
|
79 |
||
80 |
self.drizzleimport = self.system_manager.find_path([os.path.join(self.clientbindir, |
|
81 |
'drizzleimport')]) |
|
82 |
||
83 |
self.drizzle_server = self.system_manager.find_path([os.path.join(self.basedir,'drizzled/drizzled'), |
|
84 |
os.path.join(self.clientbindir,'drizzled'), |
|
85 |
os.path.join(self.basedir,'libexec/drizzled'), |
|
86 |
os.path.join(self.basedir,'bin/drizzled'), |
|
87 |
os.path.join(self.basedir,'sbin/drizzled'), |
|
88 |
os.path.join(self.builddir,'drizzled/drizzled')]) |
|
89 |
||
90 |
||
91 |
self.drizzleslap = self.system_manager.find_path([os.path.join(self.clientbindir, |
|
92 |
'drizzleslap')]) |
|
93 |
||
94 |
self.schemawriter = self.system_manager.find_path([os.path.join(self.basedir, |
|
95 |
'drizzled/message/schema_writer'), |
|
96 |
os.path.join(self.builddir, |
|
97 |
'drizzled/message/schema_writer')]) |
|
98 |
||
99 |
self.drizzletest = self.system_manager.find_path([os.path.join(self.clientbindir, |
|
100 |
'drizzletest')]) |
|
101 |
||
2337.1.12
by patrick crews
Additional work on allowing dbqp to handle multiple server types / versions (even simultaneously) |
102 |
self.trx_reader = self.system_manager.find_path([os.path.join(self.basedir, |
2239.8.2
by David Shrewsbury
Changed name of drizzle_trx_reader to drizzletrx. |
103 |
'plugin/transaction_log/utilities/drizzletrx')]) |
2258.1.1
by patrick crews
Made the transaction_reader utility part of the codeTree. We now export the path an an env var that can be more easily called by drizzletest. Made adjustments to trx_log tests that need this |
104 |
|
2088.9.1
by patrick crews
Updated tree so that test-run.pl and test-run.py may live together in peace for a time |
105 |
self.server_version_string = None |
106 |
self.server_executable = None |
|
107 |
self.server_version = None |
|
108 |
self.server_compile_os = None |
|
109 |
self.server_platform = None |
|
110 |
self.server_compile_comment = None |
|
2337.1.14
by patrick crews
Believed to be last tweaks needed to have different code trees / basedirs in a single dbqp run. Now to code for new servers : ) |
111 |
self.type = 'drizzle' |
2088.9.1
by patrick crews
Updated tree so that test-run.pl and test-run.py may live together in peace for a time |
112 |
|
113 |
self.process_server_version() |
|
2088.9.22
by patrick crews
Updated code to set LD_LIBRARY env vars |
114 |
self.ld_lib_paths = self.get_ld_lib_paths() |
2088.9.1
by patrick crews
Updated tree so that test-run.pl and test-run.py may live together in peace for a time |
115 |
|
116 |
self.report() |
|
117 |
||
2337.1.4
by patrick crews
Tweak of logging behavior (no more 'if debug' checks...) and related code cleanup. Also groundwork for allowing multiple basedirs (server code bases) to the test runner) |
118 |
self.logging.debug_class(self) |
2088.9.1
by patrick crews
Updated tree so that test-run.pl and test-run.py may live together in peace for a time |
119 |
|
120 |
def report(self): |
|
121 |
self.logging.info("Using Drizzle source tree:") |
|
122 |
report_keys = ['basedir' |
|
123 |
,'clientbindir' |
|
124 |
,'testdir' |
|
125 |
,'server_version' |
|
126 |
,'server_compile_os' |
|
127 |
,'server_platform' |
|
128 |
,'server_comment'] |
|
129 |
for key in report_keys: |
|
130 |
self.logging.info("%s: %s" %(key, vars(self)[key])) |
|
131 |
||
132 |
||
133 |
||
134 |
def process_server_version(self): |
|
135 |
""" Get the server version number from the found server executable """
|
|
136 |
(retcode, self.server_version_string) = self.system_manager.execute_cmd(("%s --no-defaults --version" %(self.drizzle_server))) |
|
137 |
# This is a bit bobo, but we're doing it, so nyah
|
|
138 |
# TODO fix this : )
|
|
139 |
self.server_executable, data_string = [data_item.strip() for data_item in self.server_version_string.split('Ver ')] |
|
140 |
self.server_version, data_string = [data_item.strip() for data_item in data_string.split('for ')] |
|
141 |
self.server_compile_os, data_string = [data_item.strip() for data_item in data_string.split(' on')] |
|
142 |
self.server_platform = data_string.split(' ')[0].strip() |
|
143 |
self.server_comment = data_string.replace(self.server_platform,'').strip() |
|
144 |
||
2088.9.22
by patrick crews
Updated code to set LD_LIBRARY env vars |
145 |
def get_ld_lib_paths(self): |
146 |
""" Return a list of paths we want added to LD_LIB variables
|
|
2088.9.1
by patrick crews
Updated tree so that test-run.pl and test-run.py may live together in peace for a time |
147 |
|
2337.1.15
by patrick crews
Code cleanup / reorganization |
148 |
These are processed later at the server_manager level, but we want to
|
2088.9.1
by patrick crews
Updated tree so that test-run.pl and test-run.py may live together in peace for a time |
149 |
specify them here (for a drizzle source tree) and now
|
150 |
|
|
151 |
"""
|
|
2088.9.22
by patrick crews
Updated code to set LD_LIBRARY env vars |
152 |
ld_lib_paths = [] |
2088.9.1
by patrick crews
Updated tree so that test-run.pl and test-run.py may live together in peace for a time |
153 |
if self.source_dist: |
2088.9.22
by patrick crews
Updated code to set LD_LIBRARY env vars |
154 |
ld_lib_paths = [ os.path.join(self.basedir,"libdrizzleclient/.libs/") |
2337.1.12
by patrick crews
Additional work on allowing dbqp to handle multiple server types / versions (even simultaneously) |
155 |
#, os.path.join(self.basedir,"libdrizzle-2.0/libdrizzle.libs")
|
2232.1.2
by patrick crews
Updates to make this work properly on mac - tested on hades |
156 |
, os.path.join(self.basedir,"libdrizzle/.libs") |
2246.2.1
by patrick crews
Fixed ld_lib_paths in dbqp to find the new libdrizzle locations in Monty's libdrizzle2.0 tree |
157 |
, os.path.join(self.basedir,"libdrizzle-2.0/libdrizzle/.libs") |
158 |
, os.path.join(self.basedir,"libdrizzle-1.0/libdrizzle/.libs") |
|
2232.1.2
by patrick crews
Updates to make this work properly on mac - tested on hades |
159 |
, os.path.join(self.basedir,"mysys/.libs/") |
160 |
, os.path.join(self.basedir,"mystrings/.libs/") |
|
161 |
, os.path.join(self.basedir,"drizzled/.libs/") |
|
162 |
, "/usr/local/lib" |
|
163 |
]
|
|
2088.9.1
by patrick crews
Updated tree so that test-run.pl and test-run.py may live together in peace for a time |
164 |
else: |
2088.9.22
by patrick crews
Updated code to set LD_LIBRARY env vars |
165 |
ld_lib_paths = [ os.path.join(self.basedir,"lib")] |
166 |
return ld_lib_paths |
|
2088.9.1
by patrick crews
Updated tree so that test-run.pl and test-run.py may live together in peace for a time |
167 |
|
2337.1.15
by patrick crews
Code cleanup / reorganization |
168 |
class mysqlTree(codeTree): |
169 |
""" What a MySQL code tree should look like to the test-runner
|
|
170 |
|
|
171 |
"""
|
|
172 |
||
173 |
def __init__(self, variables,system_manager): |
|
174 |
self.system_manager = system_manager |
|
175 |
self.logging = self.system_manager.logging |
|
176 |
self.skip_keys = ['ld_lib_paths'] |
|
177 |
self.debug = variables['debug'] |
|
178 |
self.verbose = variables['verbose'] |
|
179 |
self.basedir = self.system_manager.find_path([os.path.abspath(variables['basedir'][0])]) |
|
180 |
self.source_dist = os.path.isdir(os.path.join(self.basedir, 'mysqld')) |
|
181 |
self.builddir = self.system_manager.find_path([os.path.abspath(self.basedir)]) |
|
182 |
self.top_builddir = variables['topbuilddir'] |
|
183 |
self.testdir = self.system_manager.find_path([os.path.abspath(variables['testdir'])]) |
|
184 |
self.clientbindir = self.system_manager.find_path([os.path.join(self.basedir, 'client_release') |
|
185 |
, os.path.join(self.basedir, 'client_debug') |
|
186 |
, os.path.join(self.basedir, 'client') |
|
187 |
, os.path.join(self.basedir, 'bin')]) |
|
188 |
self.charsetdir = self.system_manager.find_path([os.path.join(self.basedir, 'mysql/charsets') |
|
189 |
, os.path.join(self.basedir, 'sql/share/charsets') |
|
190 |
, os.path.join(self.basedir, 'share/charsets')]) |
|
2337.1.17
by patrick crews
Additional work for running MySQL servers (still not ready for prime-time / working) |
191 |
self.langdir = self.system_manager.find_path([os.path.join(self.basedir, 'share/mysql') |
192 |
, os.path.join(self.basedir, 'sql/share') |
|
193 |
, os.path.join(self.basedir, 'share')]) |
|
194 |
||
2337.1.15
by patrick crews
Code cleanup / reorganization |
195 |
|
196 |
self.srcdir = self.system_manager.find_path([self.basedir]) |
|
197 |
self.suite_paths = variables['suitepaths'] |
|
198 |
||
199 |
self.mysql_client = self.system_manager.find_path([os.path.join(self.clientbindir, |
|
200 |
'mysql')]) |
|
201 |
||
202 |
self.mysqldump = self.system_manager.find_path([os.path.join(self.clientbindir, |
|
203 |
'mysqldump')]) |
|
204 |
||
205 |
self.mysqlimport = self.system_manager.find_path([os.path.join(self.clientbindir, |
|
206 |
'mysqlimport')]) |
|
207 |
||
208 |
self.mysqladmin = self.system_manager.find_path([os.path.join(self.clientbindir, |
|
209 |
'mysqladmin')]) |
|
210 |
||
211 |
self.mysql_server = self.system_manager.find_path([ os.path.join(self.basedir, '/sql/mysqld-debug') |
|
212 |
, os.path.join(self.basedir, '/libexec/mysqld-debug') |
|
213 |
, os.path.join(self.basedir, '/sbin/mysqld-debug') |
|
214 |
, os.path.join(self.basedir, '/bin/mysqld-debug') |
|
215 |
, os.path.join(self.basedir, '/sql/mysqld') |
|
216 |
, os.path.join(self.basedir, '/libexec/mysqld') |
|
217 |
, os.path.join(self.basedir, '/sbin/mysqld') |
|
218 |
, os.path.join(self.basedir, '/bin/mysqld') |
|
219 |
, os.path.join(self.basedir, '/sql/mysqld-max-nt') |
|
220 |
, os.path.join(self.basedir, '/libexec/mysqld-max-nt') |
|
221 |
, os.path.join(self.basedir, '/sbin/mysqld-max-nt') |
|
222 |
, os.path.join(self.basedir, '/bin/mysqld-max-nt') |
|
223 |
, os.path.join(self.basedir, '/sql/mysqld-max') |
|
224 |
, os.path.join(self.basedir, '/libexec/mysqld-max') |
|
225 |
, os.path.join(self.basedir, '/sbin/mysqld-max') |
|
226 |
, os.path.join(self.basedir, '/bin/mysqld-max') |
|
227 |
, os.path.join(self.basedir, '/sql/mysqld-nt') |
|
228 |
, os.path.join(self.basedir, '/libexec/mysqld-nt') |
|
229 |
, os.path.join(self.basedir, '/sbin/mysqld-nt') |
|
230 |
, os.path.join(self.basedir, '/bin/mysqld-nt') |
|
231 |
])
|
|
232 |
||
233 |
||
234 |
||
235 |
self.mysqlslap = self.system_manager.find_path([os.path.join(self.clientbindir, |
|
236 |
'mysqlslap')]) |
|
237 |
||
238 |
self.mysqltest = self.system_manager.find_path([os.path.join(self.clientbindir, |
|
239 |
'mysqltest')]) |
|
240 |
self.server_version_string = None |
|
241 |
self.server_executable = None |
|
242 |
self.server_version = None |
|
243 |
self.server_compile_os = None |
|
244 |
self.server_platform = None |
|
245 |
self.server_compile_comment = None |
|
246 |
self.type = 'mysql' |
|
247 |
self.process_server_version() |
|
248 |
self.ld_lib_paths = self.get_ld_lib_paths() |
|
2337.1.17
by patrick crews
Additional work for running MySQL servers (still not ready for prime-time / working) |
249 |
self.bootstrap_path = os.path.join( self.system_manager.workdir |
250 |
, 'mysql_bootstrap.sql' ) |
|
251 |
self.generate_bootstrap() |
|
2337.1.15
by patrick crews
Code cleanup / reorganization |
252 |
|
253 |
self.report() |
|
254 |
||
255 |
self.logging.debug_class(self) |
|
256 |
||
257 |
def report(self): |
|
258 |
self.logging.info("Using mysql source tree:") |
|
259 |
report_keys = ['basedir' |
|
260 |
,'clientbindir' |
|
261 |
,'testdir' |
|
262 |
,'server_version' |
|
263 |
,'server_compile_os' |
|
264 |
,'server_platform' |
|
265 |
,'server_comment'] |
|
266 |
for key in report_keys: |
|
267 |
self.logging.info("%s: %s" %(key, vars(self)[key])) |
|
268 |
||
269 |
def process_server_version(self): |
|
270 |
""" Get the server version number from the found server executable """
|
|
271 |
(retcode, self.server_version_string) = self.system_manager.execute_cmd(("%s --no-defaults --version" %(self.mysql_server))) |
|
272 |
# This is a bit bobo, but we're doing it, so nyah
|
|
273 |
# TODO fix this : )
|
|
274 |
self.server_executable, data_string = [data_item.strip() for data_item in self.server_version_string.split('Ver ')] |
|
275 |
self.server_version, data_string = [data_item.strip() for data_item in data_string.split('for ')] |
|
276 |
self.server_compile_os, data_string = [data_item.strip() for data_item in data_string.split(' on')] |
|
277 |
self.server_platform = data_string.split(' ')[0].strip() |
|
278 |
self.server_comment = data_string.replace(self.server_platform,'').strip() |
|
279 |
||
280 |
def get_ld_lib_paths(self): |
|
281 |
""" Return a list of paths we want added to LD_LIB variables
|
|
282 |
||
283 |
These are processed later at the server_manager level, but we want to
|
|
284 |
specify them here (for a mysql source tree) and now
|
|
285 |
|
|
286 |
"""
|
|
287 |
ld_lib_paths = [] |
|
288 |
if self.source_dist: |
|
289 |
ld_lib_paths = [ os.path.join(self.basedir,"libmysql/.libs/") |
|
290 |
, os.path.join(self.basedir,"libmysql_r/.libs") |
|
291 |
, os.path.join(self.basedir,"zlib/.libs") |
|
292 |
]
|
|
293 |
else: |
|
294 |
ld_lib_paths = [ os.path.join(self.basedir,"lib") |
|
295 |
, os.path.join(self.basedir,"lib/mysql")] |
|
296 |
return ld_lib_paths |
|
297 |
||
2337.1.17
by patrick crews
Additional work for running MySQL servers (still not ready for prime-time / working) |
298 |
def generate_bootstrap(self): |
299 |
""" We do the voodoo that we need to in order to create the bootstrap
|
|
300 |
file needed by MySQL
|
|
301 |
||
302 |
"""
|
|
303 |
found_new_sql = False |
|
304 |
# determine if we have a proper area for our sql or if we
|
|
305 |
# use the rigged method from 5.0 / 5.1
|
|
306 |
# first we search various possible locations
|
|
307 |
test_file = "mysql_system_tables.sql" |
|
308 |
for candidate_dir in [ "mysql" |
|
309 |
, "sql/share" |
|
310 |
, "share/mysql" |
|
311 |
, "share" |
|
312 |
, "scripts"]: |
|
313 |
candidate_path = os.path.join(self.basedir, candidate_dir, test_file) |
|
314 |
if os.path.exists(candidate_path): |
|
315 |
bootstrap_file = open(self.bootstrap_path,'w') |
|
316 |
bootstrap_file.write("use mysql\n") |
|
317 |
for sql_file in [ 'mysql_system_tables.sql' #official mysql system tables |
|
318 |
, 'mysql_system_tables_data.sql' #initial data for sys tables |
|
319 |
, 'mysql_test_data_timezone.sql' # subset of full tz table data for testing |
|
320 |
, 'fill_help_tables.sql' # fill help tables populated only w/ src dist(?) |
|
321 |
]:
|
|
322 |
sql_file_path = os.path.join(self.basedir,candidate_dir,sql_file) |
|
323 |
sql_file_handle = open(sql_file_path,'r') |
|
324 |
bootstrap_file.write(sql_file_handle.readlines()) |
|
325 |
sql_file_handle.close() |
|
326 |
found_new_sql = True |
|
327 |
break
|
|
328 |
if not found_new_sql: |
|
329 |
# Install the system db's from init_db.sql
|
|
330 |
# that is in early 5.1 and 5.0 versions of MySQL
|
|
331 |
sql_file_path = os.path.join(self.basedir,'mysql-test/lib/init_db.sql') |
|
332 |
self.logging.info("Attempting to use bootstrap file - %s" %(sql_file_path)) |
|
333 |
try: |
|
334 |
in_file = open(sql_file_path,'r') |
|
335 |
bootstrap_file = open(self.bootstrap_path,'w') |
|
336 |
bootstrap_file.write(in_file.readlines()) |
|
337 |
in_file.close() |
|
338 |
except IOError: |
|
339 |
self.logging.error("Cannot find data for generating bootstrap file") |
|
340 |
self.logging.error("Cannot proceed without this, system exiting...") |
|
341 |
sys.exit(1) |
|
342 |
# Remove anonymous users
|
|
343 |
bootstrap_file.write("DELETE FROM mysql.user where user= '';\n") |
|
344 |
# Create mtr database
|
|
345 |
bootstrap_file.write("CREATE DATABASE mtr;\n") |
|
346 |
for sql_file in [ 'mtr_warnings.sql' # help tables + data for warning detection / suppression |
|
347 |
, 'mtr_check.sql' # Procs for checking proper restore post-testcase |
|
348 |
]:
|
|
349 |
sql_file_path = os.path.join(self.basedir,'mysql-test/include',sql_file) |
|
350 |
sql_file_handle = open(sql_file_path,'r') |
|
351 |
bootstrap_file.write(sql_file_handle.readlines()) |
|
352 |
sql_file_handle.close() |
|
353 |
bootstrap_file.close() |
|
354 |
return
|
|
355 |
||
356 |
||
357 |
||
358 |
||
2337.1.15
by patrick crews
Code cleanup / reorganization |
359 |
|
2088.9.1
by patrick crews
Updated tree so that test-run.pl and test-run.py may live together in peace for a time |
360 |