587
|
1 |
# -*- encoding: latin-1 -*-
|
|
2 |
|
|
3 |
#============================================================================
|
|
4 |
#Name : __init__.py
|
|
5 |
#Part of : Helium
|
|
6 |
|
|
7 |
#Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
|
|
8 |
#All rights reserved.
|
|
9 |
#This component and the accompanying materials are made available
|
|
10 |
#under the terms of the License "Eclipse Public License v1.0"
|
|
11 |
#which accompanies this distribution, and is available
|
|
12 |
#at the URL "http://www.eclipse.org/legal/epl-v10.html".
|
|
13 |
#
|
|
14 |
#Initial Contributors:
|
|
15 |
#Nokia Corporation - initial contribution.
|
|
16 |
#
|
|
17 |
#Contributors:
|
|
18 |
#
|
|
19 |
#Description:
|
|
20 |
#===============================================================================
|
|
21 |
|
|
22 |
"""ATS3 test drop generation."""
|
|
23 |
|
|
24 |
#W0142 => * and ** were used
|
|
25 |
#R* => will be fixed while refactoring
|
|
26 |
#F0401 => pylint didn't find "path" module
|
|
27 |
#C0302 => Too many lines
|
|
28 |
|
|
29 |
from optparse import OptionParser
|
|
30 |
import ats3.testconfigurator as acp
|
|
31 |
import ats3.dropgenerator as adg
|
|
32 |
import logging
|
|
33 |
import os
|
|
34 |
import re
|
|
35 |
|
|
36 |
import ats3.parsers as parser
|
|
37 |
|
|
38 |
from path import path # pylint: disable-msg=F0401
|
|
39 |
|
|
40 |
_logger = logging.getLogger('ats')
|
|
41 |
|
|
42 |
class Configuration(object):
|
|
43 |
"""
|
|
44 |
ATS3 drop generation configuration.
|
|
45 |
"""
|
|
46 |
def __init__(self, opts, tsrc_paths):
|
|
47 |
"""
|
|
48 |
Initialize from optparse configuration options.
|
|
49 |
"""
|
|
50 |
self._opts = opts
|
|
51 |
c_parser = parser.CppParser()
|
|
52 |
temp_dict = {}
|
|
53 |
pkg_parser = parser.PkgFileParser()
|
|
54 |
|
|
55 |
# Customize some attributes from how optparse leaves them.
|
|
56 |
self.build_drive = path(self._opts.build_drive)
|
|
57 |
self.file_store = path(self._opts.file_store)
|
|
58 |
self.flash_images = split_paths(self._opts.flash_images)
|
|
59 |
self.sis_files = split_paths(self._opts.sis_files)
|
|
60 |
self.config_file = self._opts.config
|
|
61 |
self.obey_pkgfiles = to_bool(self._opts.obey_pkgfiles)
|
|
62 |
self.hti = to_bool(self._opts.hti)
|
|
63 |
self.specific_pkg = self._opts.specific_pkg
|
|
64 |
if self.specific_pkg == '':
|
|
65 |
self.specific_pkg = None
|
|
66 |
self.tsrc_paths_dict = {}
|
|
67 |
|
|
68 |
ats_nd = self._opts.ctc_run_process_params.strip()
|
|
69 |
if ats_nd != "":
|
|
70 |
ats_nd = ats_nd.split("#")[0].strip()
|
|
71 |
if ats_nd == "":
|
|
72 |
self._opts.ctc_run_process_params = ""
|
|
73 |
_logger.warning("Property \'ats.ctc.host\' is not set. Code coverage measurement report(s) will not be created.")
|
|
74 |
|
|
75 |
main_comps = []
|
|
76 |
|
|
77 |
for tsrc in tsrc_paths:
|
|
78 |
hrh = os.path.join(self.build_drive + os.sep, 'epoc32', 'include', 'feature_settings.hrh')
|
|
79 |
if os.path.exists(hrh):
|
|
80 |
temp_dict = c_parser.get_cpp_output(path(tsrc), "d", hrh)
|
|
81 |
else:
|
|
82 |
temp_dict = c_parser.get_cpp_output(path(tsrc), "d")
|
|
83 |
for t_key, t_value in temp_dict.items():
|
|
84 |
self.tsrc_paths_dict[t_key] = t_value
|
|
85 |
|
|
86 |
#preparing a list of main components
|
|
87 |
for main_component in self.tsrc_paths_dict.keys():
|
|
88 |
if self.obey_pkgfiles == "True":
|
|
89 |
if pkg_parser.get_pkg_files(main_component) != []:
|
|
90 |
main_comps.append(main_component)
|
|
91 |
else:
|
|
92 |
main_comps.append(main_component)
|
|
93 |
|
|
94 |
|
|
95 |
self.tsrc_paths = main_comps
|
|
96 |
|
|
97 |
def __getattr__(self, attr):
|
|
98 |
return getattr(self._opts, attr)
|
|
99 |
|
|
100 |
def __str__(self):
|
|
101 |
dump = "Configuration:\n"
|
|
102 |
seen = set()
|
|
103 |
for key, value in vars(self).items():
|
|
104 |
if not key.startswith("_"):
|
|
105 |
dump += "\t%s = %s\n" % (key, value)
|
|
106 |
seen.add(key)
|
|
107 |
for key, value in vars(self._opts).items():
|
|
108 |
if key not in seen:
|
|
109 |
dump += "\t%s = %s\n" % (key, value)
|
|
110 |
seen.add(key)
|
|
111 |
return dump
|
|
112 |
|
|
113 |
|
|
114 |
class Ats3TestPlan(object):
|
|
115 |
"""
|
|
116 |
Tells ATS3 server what to test and how.
|
|
117 |
|
|
118 |
The ATS3 test plan from which the test.xml file can be written. The test
|
|
119 |
plan captures all the data related to a test run: flashing, installation
|
|
120 |
of data files and configuration files, test cases, and the notifications.
|
|
121 |
|
|
122 |
"""
|
|
123 |
EMAIL_SUBJECT = (u"ATS3 report for §RUN_NAME§ §RUN_START_DATE§ "
|
|
124 |
u"§RUN_START_TIME§")
|
|
125 |
REPORT_PATH = u"§RUN_NAME§" + os.sep + u"§RUN_START_DATE§_§RUN_START_TIME§"
|
|
126 |
|
|
127 |
def __init__(self, config):
|
|
128 |
self.diamonds_build_url = config.diamonds_build_url
|
|
129 |
self.ctc_run_process_params = config.ctc_run_process_params
|
|
130 |
self.testrun_name = config.testrun_name
|
|
131 |
self.harness = config.harness
|
|
132 |
self.device_type = config.device_type
|
|
133 |
self.device_hwid = config.device_hwid
|
|
134 |
self.plan_name = config.plan_name
|
|
135 |
self.report_email = config.report_email
|
|
136 |
self.file_store = config.file_store
|
|
137 |
self.test_timeout = config.test_timeout
|
|
138 |
self.eunitexerunner_flags = config.eunitexerunner_flags
|
|
139 |
self.sets = []
|
|
140 |
self.src_dst = []
|
|
141 |
self.pmd_files = []
|
|
142 |
self.trace_activation_files = []
|
|
143 |
self.trace_enabled = to_bool(config.trace_enabled)
|
|
144 |
self.ctc_enabled = to_bool(config.ctc_enabled)
|
|
145 |
self.multiset_enabled = to_bool(config.multiset_enabled)
|
|
146 |
self.monsym_files = config.monsym_files
|
|
147 |
self.hti = config.hti
|
|
148 |
self.component_path = ""
|
|
149 |
self.custom_dir = None
|
|
150 |
|
|
151 |
def insert_set(self, data_files=None, config_files=None,
|
|
152 |
engine_ini_file=None, image_files=None, sis_files=None,
|
|
153 |
testmodule_files=None, test_timeout=None,eunitexerunner_flags=None , test_harness=None,
|
|
154 |
src_dst=None, pmd_files=None, trace_activation_files=None, custom_dir=None, component_path=None):
|
|
155 |
"""
|
|
156 |
Insert a test set into the test plan.
|
|
157 |
"""
|
|
158 |
|
|
159 |
if not custom_dir is None:
|
|
160 |
self.custom_dir = custom_dir
|
|
161 |
if data_files is None:
|
|
162 |
data_files = []
|
|
163 |
if config_files is None:
|
|
164 |
config_files = []
|
|
165 |
if image_files is None:
|
|
166 |
image_files = []
|
|
167 |
if sis_files is None:
|
|
168 |
sis_files = []
|
|
169 |
if testmodule_files is None:
|
|
170 |
testmodule_files = []
|
|
171 |
if test_timeout is None:
|
|
172 |
test_timeout = []
|
|
173 |
if test_harness is None:
|
|
174 |
test_harness = self.harness
|
|
175 |
if src_dst is None:
|
|
176 |
src_dst = []
|
|
177 |
if pmd_files is None:
|
|
178 |
pmd_files = []
|
|
179 |
if trace_activation_files is None:
|
|
180 |
trace_activation_files = []
|
|
181 |
if component_path is None:
|
|
182 |
component_path = self.component_path
|
|
183 |
|
|
184 |
setd = dict(name="set%d" % len(self.sets),
|
|
185 |
image_files=image_files, engine_ini_file=engine_ini_file, ctc_enabled=self.ctc_enabled, component_path=component_path)
|
|
186 |
|
|
187 |
setd = dict(setd, custom_dir=custom_dir)
|
|
188 |
if sis_files:
|
|
189 |
setd = dict(setd, sis_files=sis_files, test_timeout=test_timeout, eunitexerunner_flags=eunitexerunner_flags, test_harness=test_harness, )
|
|
190 |
else:
|
|
191 |
setd = dict(setd, data_files=data_files, config_files=config_files,
|
|
192 |
testmodule_files=testmodule_files, test_timeout=test_timeout, eunitexerunner_flags=eunitexerunner_flags, test_harness=test_harness,
|
|
193 |
src_dst=src_dst)
|
|
194 |
if self.trace_enabled != "":
|
|
195 |
if self.trace_enabled.lower() == "true":
|
|
196 |
setd = dict(setd, pmd_files=pmd_files,
|
|
197 |
trace_path=self.file_store.joinpath(self.REPORT_PATH, "traces", setd["name"], "tracelog.blx"),
|
|
198 |
trace_activation_files=trace_activation_files)
|
|
199 |
else:
|
|
200 |
setd = dict(setd, pmd_files=[],
|
|
201 |
trace_path="",trace_activation_files=[])
|
|
202 |
self.sets.append(setd)
|
|
203 |
|
|
204 |
def set_plan_harness(self):
|
|
205 |
"""setting up test harness for a plan"""
|
|
206 |
eunit = False
|
|
207 |
stif = False
|
|
208 |
stifunit = False
|
|
209 |
for setd in self.sets:
|
|
210 |
if setd["test_harness"] == "STIF":
|
|
211 |
stif = True
|
|
212 |
elif setd["test_harness"] == "EUNIT":
|
|
213 |
eunit = True
|
|
214 |
elif setd["test_harness"] == "STIFUNIT":
|
|
215 |
stifunit = True
|
|
216 |
|
|
217 |
if eunit and stif:
|
|
218 |
self.harness = "MULTI_HARNESS"
|
|
219 |
elif eunit:
|
|
220 |
self.harness = "EUNIT"
|
|
221 |
elif stif:
|
|
222 |
self.harness = "STIF"
|
|
223 |
elif stifunit:
|
|
224 |
self.harness = "STIFUNIT"
|
|
225 |
else:
|
|
226 |
self.harness = "GENERIC"
|
|
227 |
|
|
228 |
@property
|
|
229 |
def post_actions(self):
|
|
230 |
"""ATS3 post actions."""
|
|
231 |
actions = []
|
|
232 |
temp_var = ""
|
|
233 |
include_ctc_runprocess = False
|
|
234 |
report_path = self.file_store.joinpath(self.REPORT_PATH)
|
|
235 |
|
|
236 |
if self.ctc_enabled and adg.CTC_PATHS_LIST != [] and self.monsym_files != "" and not "${" in self.monsym_files:
|
|
237 |
include_ctc_runprocess = True
|
|
238 |
ctc_params = "--ctcdata_files="
|
|
239 |
for cdl in adg.CTC_PATHS_LIST:
|
|
240 |
ctc_params += cdl + '\\ctcdata.txt' + ";"
|
|
241 |
temp_var = cdl
|
|
242 |
|
|
243 |
drop_count = self.ctc_run_process_params.rsplit("#", 1)[1]
|
|
244 |
temp_var = temp_var.split("ctc_helium"+os.sep)[1]
|
|
245 |
diamonds_id = temp_var.split(os.sep)[0]
|
|
246 |
drop_id = temp_var.split(os.sep)[1].split(os.sep)[0]
|
|
247 |
drop_id = re.findall(".*drop(\d*)", drop_id.lower())[0] #extracting int part of drop name
|
|
248 |
|
|
249 |
ctc_params += r" --monsym_files=" + self.monsym_files
|
|
250 |
ctc_params += r" --diamonds_build_id=" + diamonds_id
|
|
251 |
ctc_params += r" --drop_id=" + drop_id
|
|
252 |
ctc_params += r" --total_amount_of_drops=" + drop_count
|
|
253 |
|
|
254 |
runprocess_action = ("RunProcessAction",
|
|
255 |
(("file", r"catsctc2html/catsctc2html.exe"), #this line will be executing on Windows machine.
|
|
256 |
("parameters", ctc_params)))
|
|
257 |
|
|
258 |
email_url = " CTC report can be found from: " + self.diamonds_build_url
|
|
259 |
|
|
260 |
email_action = ("SendEmailAction",
|
|
261 |
(("subject", self.EMAIL_SUBJECT),
|
|
262 |
("type", "ATS3_REPORT"),
|
|
263 |
("send-files", "true"),
|
|
264 |
("additional-description", email_url),
|
|
265 |
("to", self.report_email)))
|
|
266 |
else:
|
|
267 |
email_action = ("SendEmailAction",
|
|
268 |
(("subject", self.EMAIL_SUBJECT),
|
|
269 |
("type", "ATS3_REPORT"),
|
|
270 |
("send-files", "true"),
|
|
271 |
("to", self.report_email)))
|
|
272 |
ats3_report = ("FileStoreAction",
|
|
273 |
(("to-folder", report_path.joinpath("ATS3_REPORT")),
|
|
274 |
("report-type", "ATS3_REPORT"),
|
|
275 |
("date-format", "yyyyMMdd"),
|
|
276 |
("time-format", "HHmmss")))
|
|
277 |
stif_report = ("FileStoreAction",
|
|
278 |
(("to-folder", report_path.joinpath("STIF_REPORT")),
|
|
279 |
("report-type", "STIF_COMPONENT_REPORT_ALL_CASES"),
|
|
280 |
("run-log", "true"),
|
|
281 |
("date-format", "yyyyMMdd"),
|
|
282 |
("time-format", "HHmmss")))
|
|
283 |
eunit_report = ("FileStoreAction",
|
|
284 |
(("to-folder", report_path.joinpath("EUNIT_REPORT")),
|
|
285 |
("report-type", "EUNIT_COMPONENT_REPORT_ALL_CASES"),
|
|
286 |
("run-log", "true"),
|
|
287 |
("date-format", "yyyyMMdd"),
|
|
288 |
("time-format", "HHmmss")))
|
|
289 |
diamonds_action = ("DiamondsAction", ())
|
|
290 |
|
|
291 |
|
|
292 |
if include_ctc_runprocess:
|
|
293 |
actions.append(runprocess_action)
|
|
294 |
|
|
295 |
if self.diamonds_build_url:
|
|
296 |
actions.append(diamonds_action)
|
|
297 |
if self.file_store:
|
|
298 |
actions.append(ats3_report)
|
|
299 |
if self.harness == "STIF":
|
|
300 |
actions.append(stif_report)
|
|
301 |
elif self.harness == "EUNIT":
|
|
302 |
actions.append(eunit_report)
|
|
303 |
if self.report_email:
|
|
304 |
actions.append(email_action)
|
|
305 |
return actions
|
|
306 |
|
|
307 |
def __getitem__(self, key):
|
|
308 |
return self.__dict__[key]
|
|
309 |
|
|
310 |
def encode_for_xml(unicode_data, encoding='ascii'):
|
|
311 |
"""
|
|
312 |
Encode unicode_data for use as XML or HTML, with characters outside
|
|
313 |
of the encoding converted to XML numeric character references.
|
|
314 |
"""
|
|
315 |
try:
|
|
316 |
return unicode_data.encode(encoding, 'xmlcharrefreplace')
|
|
317 |
except ValueError:
|
|
318 |
# ValueError is raised if there are unencodable chars in the
|
|
319 |
# data and the 'xmlcharrefreplace' error handler is not found.
|
|
320 |
# Pre-2.3 Python doesn't support the 'xmlcharrefreplace' error
|
|
321 |
# handler, so we'll emulate it.
|
|
322 |
return _xmlcharref_encode(unicode_data, encoding)
|
|
323 |
|
|
324 |
def _xmlcharref_encode(unicode_data, encoding):
|
|
325 |
"""Emulate Python 2.3's 'xmlcharrefreplace' encoding error handler."""
|
|
326 |
chars = []
|
|
327 |
# Step through the unicode_data string one character at a time in
|
|
328 |
# order to catch unencodable characters:
|
|
329 |
for char in unicode_data:
|
|
330 |
try:
|
|
331 |
chars.append(char.encode(encoding, 'strict'))
|
|
332 |
except UnicodeError:
|
|
333 |
chars.append('&#%i;' % ord(char))
|
|
334 |
return ''.join(chars)
|
|
335 |
|
|
336 |
|
|
337 |
def create_drop(config):
|
|
338 |
"""Create a test drop."""
|
|
339 |
_logger.debug("initialize test plan")
|
|
340 |
|
|
341 |
test_plan = Ats3TestPlan(config)
|
|
342 |
component_parser = acp.Ats3ComponentParser(config)
|
|
343 |
|
|
344 |
for tsrc in config.tsrc_paths:
|
|
345 |
lst_check_harness = []
|
|
346 |
_logger.info("inspecting tsrc path: %s" % tsrc)
|
|
347 |
#checking if there are components without harness
|
|
348 |
for sub_component in config.tsrc_paths_dict[tsrc]['content'].keys():
|
|
349 |
_harness_ = config.tsrc_paths_dict[tsrc]['content'][sub_component]['harness']
|
|
350 |
if _harness_ != "":
|
|
351 |
lst_check_harness.append(_harness_)
|
|
352 |
|
|
353 |
#if component has harness then insert to test set
|
|
354 |
if len(lst_check_harness) > 0:
|
|
355 |
component_parser.insert_test_set(test_plan, path(tsrc), config.tsrc_paths_dict)
|
|
356 |
|
|
357 |
test_plan.set_plan_harness()
|
|
358 |
|
|
359 |
|
|
360 |
#Checking if any non executable set exists
|
|
361 |
#if yes, delete the set
|
|
362 |
tesplan_counter = 0
|
|
363 |
for plan_sets in test_plan.sets:
|
|
364 |
tesplan_counter += 1
|
|
365 |
exe_flag = False
|
|
366 |
for srcanddst in plan_sets['src_dst']:
|
|
367 |
_ext = srcanddst[0].rsplit(".")[1]
|
|
368 |
#the list below are the files which are executable
|
|
369 |
#if none exists, set is not executable
|
|
370 |
for mat in ["dll", "ini", "cfg", "exe", "script"]:
|
|
371 |
if mat == _ext.lower():
|
|
372 |
exe_flag = True
|
|
373 |
break
|
|
374 |
if exe_flag:
|
|
375 |
break
|
|
376 |
|
|
377 |
if not exe_flag: #the set does not have executable, deleting the set
|
|
378 |
_logger.info(plan_sets['component_path'] + ' has no executables so not including in xml')
|
|
379 |
del test_plan.sets[tesplan_counter - 1]
|
|
380 |
|
|
381 |
if config.ats4_enabled.lower() == 'true':
|
|
382 |
generator = adg.Ats3TemplateTestDropGenerator()
|
|
383 |
else:
|
|
384 |
generator = adg.Ats3TestDropGenerator()
|
|
385 |
_logger.info("generating drop file: %s" % config.drop_file)
|
|
386 |
generator.generate(test_plan, output_file=config.drop_file, config_file=config.config_file)
|
|
387 |
|
|
388 |
def split_paths(arg, delim=","):
|
|
389 |
"""
|
|
390 |
Split the string by delim, removing extra whitespace.
|
|
391 |
"""
|
|
392 |
return [path(part.strip())
|
|
393 |
for part in arg.split(delim) if part.strip()]
|
|
394 |
|
|
395 |
def to_bool(param):
|
|
396 |
"""setting a true or false based on a param value"""
|
|
397 |
param = str(param).lower()
|
|
398 |
if "true" == param or "t" == param or "1" == param:
|
|
399 |
return "True"
|
|
400 |
else:
|
|
401 |
return "False"
|
|
402 |
|
|
403 |
def main():
|
|
404 |
"""Main entry point."""
|
|
405 |
cli = OptionParser(usage="%prog [options] TSRC1 [TSRC2 [TSRC3 ...]]")
|
|
406 |
cli.add_option("--build-drive", help="Build area root drive")
|
|
407 |
cli.add_option("--data-dir", help="Data directory name", action="append",
|
|
408 |
default=[])
|
|
409 |
cli.add_option("--device-type", help="Device type (e.g. 'PRODUCT')",
|
|
410 |
default="unknown")
|
|
411 |
cli.add_option("--device-hwid", help="Device hwid",
|
|
412 |
default="")
|
|
413 |
cli.add_option("--trace-enabled", help="Tracing enabled", default="False")
|
|
414 |
cli.add_option("--ctc-enabled", help="CTC enabled", default="False")
|
|
415 |
cli.add_option("--multiset-enabled", help="Multiset enabled", default="False")
|
|
416 |
cli.add_option("--diamonds-build-url", help="Diamonds build url")
|
|
417 |
cli.add_option("--ctc-run-process-params", help="ctc parameters include ctc host, drop id and total number of drops, separated by '#'")
|
|
418 |
cli.add_option("--drop-file", help="Name for the final drop zip file",
|
|
419 |
default="ATS3Drop.zip")
|
|
420 |
cli.add_option("--file-store", help="Destination path for reports.",
|
|
421 |
default="")
|
|
422 |
cli.add_option("--flash-images", help="Paths to the flash image files",
|
|
423 |
default="")
|
|
424 |
cli.add_option("--minimum-flash-images", help="Minimum amount of flash images",
|
|
425 |
default=2)
|
|
426 |
cli.add_option("--harness", help="Test harness (default: %default)",
|
|
427 |
default="")
|
|
428 |
cli.add_option("--report-email", help="Email notification receivers",
|
|
429 |
default="")
|
|
430 |
cli.add_option("--plan-name", help="Name of the test plan",
|
|
431 |
default="plan")
|
|
432 |
cli.add_option("--sis-files", help="Paths to the sis files",
|
|
433 |
default="")
|
|
434 |
cli.add_option("--monsym-files", help="Paths to MON.sym files, for ctc useage",
|
|
435 |
default="")
|
|
436 |
cli.add_option("--target-platform", help="Target platform (default: %default)",
|
|
437 |
default="armv5 urel")
|
|
438 |
cli.add_option("--test-timeout", help="Test execution timeout value (default: %default)",
|
|
439 |
default="60")
|
|
440 |
cli.add_option("--eunitexerunner-flags", help="Eunitexerunner flags",
|
|
441 |
default="")
|
|
442 |
cli.add_option("--testrun-name", help="Name of the test run",
|
|
443 |
default="run")
|
|
444 |
cli.add_option("--config", help="Path to the config file",
|
|
445 |
default="")
|
|
446 |
cli.add_option("--specific-pkg", help="Text in name of pkg files to use", default='')
|
|
447 |
cli.add_option("--ats4-enabled", help="ATS4 enabled", default="False")
|
|
448 |
cli.add_option("--obey-pkgfiles", help="If this option is True, then only test components having PKG file are executable and if the compnents don't have PKG files they will be ignored.", default="False")
|
|
449 |
cli.add_option("--verbose", help="Increase output verbosity", action="store_true", default=False)
|
|
450 |
cli.add_option("--hti", help="HTI enabled", default="True")
|
|
451 |
|
|
452 |
opts, tsrc_paths = cli.parse_args()
|
|
453 |
|
|
454 |
if not tsrc_paths:
|
|
455 |
cli.error("no tsrc directories given")
|
|
456 |
if not opts.build_drive:
|
|
457 |
cli.error("no build drive given")
|
|
458 |
if len(opts.flash_images.split(",")) < int(opts.minimum_flash_images):
|
|
459 |
cli.error("Not enough flash files: %i defined, %i needed" % (len(opts.flash_images.split(",")), int(opts.minimum_flash_images) ))
|
|
460 |
|
|
461 |
if opts.verbose:
|
|
462 |
_logger.setLevel(logging.DEBUG)
|
|
463 |
logging.basicConfig(level=logging.DEBUG)
|
|
464 |
|
|
465 |
config = Configuration(opts, tsrc_paths)
|
|
466 |
create_drop(config)
|
|
467 |
|
|
468 |
|
|
469 |
if __name__ == "__main__":
|
|
470 |
main()
|