Commit 249f148b authored by Reto Da Forno's avatar Reto Da Forno
Browse files

support for Intel hex format added (target images)

parent a37bbfa5
......@@ -46,7 +46,7 @@ def main(argv):
opts, args = getopt.getopt(argv, "ehdt:", ["email", "help", "debug", "testid=" ])
except getopt.GetoptError as err:
print(str(err))
logger.warn(str(err))
logger.warning(str(err))
usage()
sys.exit(errno.EINVAL)
except:
......@@ -67,15 +67,15 @@ def main(argv):
if testid <= 0:
raise
except:
logger.warn("Wrong API usage: testid has to be a positive number")
logger.warning("Wrong API usage: testid has to be a positive number")
sys.exit(errno.EINVAL)
else:
logger.warn("Wrong API usage")
logger.warning("Wrong API usage")
sys.exit(errno.EINVAL)
# Check if necessary parameters are set ---
if ((testid == -1)):
logger.warn("Wrong API usage")
logger.warning("Wrong API usage")
sys.exit(errno.EINVAL)
# Add Test ID to logger name ---
......@@ -146,10 +146,10 @@ def main(argv):
try:
nice_level = flocklab.config.getint('archiver', 'nice_level')
except:
logger.warn("Could not read nice_level from config file. Setting level to 10.")
logger.warning("Could not read nice_level from config file. Setting level to 10.")
nice_level = 10
if nice_level not in list(range(0,20)):
logger.warn("Defined nice_level %d from config file is out of bounds. Setting level to 10."%nice_level)
logger.warning("Defined nice_level %d from config file is out of bounds. Setting level to 10."%nice_level)
nice_level = 10
tarcmd = ['tar', 'cf', '-', '-C', os.path.dirname(testresultsdir)]
tarcmd.extend(resultparts)
......
......@@ -36,7 +36,7 @@ def main(argv):
opts, args = getopt.getopt(argv, "dh", ["debug", "help"])
except getopt.GetoptError as err:
print(str(err))
logger.warn(str(err))
logger.warning(str(err))
usage()
sys.exit(errno.EINVAL)
except:
......@@ -50,7 +50,7 @@ def main(argv):
usage()
sys.exit(flocklab.SUCCESS)
else:
logger.warn("Wrong API usage")
logger.warning("Wrong API usage")
sys.exit(errno.EINVAL)
# Allow only x instances ---
......@@ -204,7 +204,7 @@ def main(argv):
command = line[6:106].strip()
runtime = line[106:].strip()
except:
logger.warn("Failed to parse output of 'ps'. Line was: '%s'" % line)
logger.warning("Failed to parse output of 'ps'. Line was: '%s'" % line)
break
if "testid=" in command:
testid = int(command.split('testid=', 1)[1].split()[0])
......
......@@ -289,31 +289,38 @@ def start_test(testid, cur, cn, obsdict_key, obsdict_id):
# Prepare image ---
(fd, imagepath) = tempfile.mkstemp()
binpath = "%s.ihex" % (os.path.splitext(imagepath)[0])
imagefile = os.fdopen(fd, 'w+b')
imagefile.write(binary)
imagefile.close()
logger.debug("Got target image ID %s for observer ID %s with node ID %s from database and wrote it to temp file %s (hash %s)" % (str(tgimage_key), str(obs_id), str(node_id), imagepath, hashlib.sha1(binary).hexdigest()))
logger.debug("Found %s target architecture on platform %s for observer ID %s (node ID to be used: %s)." % (arch, platname, str(obs_id), str(node_id)))
# binary patching
if (node_id != None):
# set node ID
if flocklab.patch_binary("FLOCKLAB_NODE_ID", node_id, imagepath, arch) != flocklab.SUCCESS:
msg = "Failed to patch symbol FLOCKLAB_NODE_ID in binary file %s." % (imagepath)
errors.append(msg)
logger.error(msg)
if flocklab.patch_binary("TOS_NODE_ID", node_id, imagepath, arch) != flocklab.SUCCESS:
msg = "Failed to patch symbol TOS_NODE_ID in binary file %s." % (imagepath)
# First, check if image is already in hex format ---
if flocklab.is_hex_file(data=binary):
f = open(binpath, "wb")
f.write(binary)
f.close()
else:
imagefile = os.fdopen(fd, 'w+b')
imagefile.write(binary)
imagefile.close()
logger.debug("Got target image ID %s for observer ID %s with node ID %s from database and wrote it to temp file %s (hash %s)" % (str(tgimage_key), str(obs_id), str(node_id), imagepath, hashlib.sha1(binary).hexdigest()))
logger.debug("Found %s target architecture on platform %s for observer ID %s (node ID to be used: %s)." % (arch, platname, str(obs_id), str(node_id)))
# binary patching
if (node_id != None):
# set node ID
if flocklab.patch_binary("FLOCKLAB_NODE_ID", node_id, imagepath, arch) != flocklab.SUCCESS:
msg = "Failed to patch symbol FLOCKLAB_NODE_ID in binary file %s." % (imagepath)
errors.append(msg)
logger.error(msg)
if flocklab.patch_binary("TOS_NODE_ID", node_id, imagepath, arch) != flocklab.SUCCESS:
msg = "Failed to patch symbol TOS_NODE_ID in binary file %s." % (imagepath)
errors.append(msg)
logger.error(msg)
# convert elf to intel hex
if flocklab.bin_to_hex(imagepath, arch, binpath) != flocklab.SUCCESS:
msg = "Failed to convert image file %s to Intel hex format." % (imagepath)
errors.append(msg)
logger.error(msg)
# convert elf to intel hex
if flocklab.bin_to_hex(imagepath, arch, binpath) != flocklab.SUCCESS:
msg = "Failed to convert image file %s to Intel hex format." % (imagepath)
errors.append(msg)
logger.error(msg)
shutil.move(imagepath, binpath)
logger.debug("Copied binary file without modification.")
shutil.move(imagepath, binpath)
logger.debug("Copied binary file without modification.")
# Remove the original file which is not used anymore:
if os.path.exists(imagepath):
......@@ -328,15 +335,15 @@ def start_test(testid, cur, cn, obsdict_key, obsdict_id):
logger.debug("Found adapter for %s on observer ID %s in slot %d" % (platname, obs_id, slot))
elif ret == 0:
slot = None
msg = "Could not find an adapter for %s on observer ID %s" %(platname, obs_id)
msg = "Could not find an adapter for %s on observer ID %s" % (platname, obs_id)
errors.append(msg)
logger.error(msg)
else:
slot = None
msg = "Error when detecting adapter for %s on observer ID %s: function returned %d" %(platname, obs_id, ret)
msg = "Error when detecting adapter for %s on observer ID %s: function returned %d" % (platname, obs_id, ret)
errors.append(msg)
logger.error(msg)
# Write the dictionary for the image:
if not obs_fk in imagedict_key:
imagedict_key[obs_fk] = []
......@@ -346,7 +353,7 @@ def start_test(testid, cur, cn, obsdict_key, obsdict_id):
# XML processing ---
# Get the XML config from the database and generate a separate file for every observer used:
cur.execute("SELECT `testconfig_xml` FROM `tbl_serv_tests` WHERE (`serv_tests_key` = %s)" %testid)
cur.execute("SELECT `testconfig_xml` FROM `tbl_serv_tests` WHERE (`serv_tests_key` = %s)" % testid)
ret = cur.fetchone()
if not ret:
msg = "No XML found in database for testid %d." %testid
......@@ -735,7 +742,7 @@ def stop_test(testid, cur, cn, obsdict_key, obsdict_id, abort=False):
# Stop test on observers ---
if not db_register_activity(testid, cur, cn, 'stop', iter(obsdict_key.keys())):
msg = "Some observers were occupied while stopping test."
logger.warn(msg)
logger.warning(msg)
warnings.append(msg)
# Start a thread for each observer which calls the test stop script on the observer
logger.info("Stopping test on observers...")
......@@ -854,7 +861,7 @@ def prepare_testresults(testid, cur):
et.write("%s/testconfig.xml" % testresultsdir, pretty_print=True)
logger.debug("XML config copied to results folder.")
else:
logger.warn("Could not copy XML config to test results directory.")
logger.warning("Could not copy XML config to test results directory.")
# Generate plot ---
if flocklab.config.getint('viz', 'generate_plots'):
......@@ -1084,7 +1091,7 @@ def main(argv):
opts, args = getopt.getopt(argv, "adht:", ["abort", "debug", "help", "testid="])
except getopt.GetoptError as err:
print(str(err))
logger.warn(str(err))
logger.warning(str(err))
usage()
sys.exit(errno.EINVAL)
except:
......@@ -1106,15 +1113,15 @@ def main(argv):
except:
testid = 0
if testid <= 0:
logger.warn("Wrong API usage: testid has to be a positive number")
logger.warning("Wrong API usage: testid has to be a positive number")
sys.exit(errno.EINVAL)
else:
logger.warn("Wrong API usage")
logger.warning("Wrong API usage")
sys.exit(errno.EINVAL)
# Check if the necessary parameters are set: testid and either start, stop or abort has to be specified but not all.
if not testid:
logger.warn("Wrong API usage")
logger.warning("Wrong API usage")
sys.exit(errno.EINVAL)
# Add testid to logger name
......@@ -1184,7 +1191,7 @@ def main(argv):
cn.commit()
if len(errors) != 0:
# Test start failed. Make it abort:
logger.warn("Going to abort test because of errors when trying to start it.")
logger.warning("Going to abort test because of errors when trying to start it.")
abort = True
# Inform user:
ret = inform_user(testid, cur, action, errors, warnings)
......@@ -1240,7 +1247,7 @@ def main(argv):
SET `cleanuptime` = %d
WHERE `serv_tests_key` = %d;
"""
cur.execute(sql%(int(time_needed), testid))
cur.execute(sql % (int(time_needed), testid))
cn.commit()
# Inform user:
......
......@@ -94,7 +94,7 @@ def sigterm_handler(signum, frame):
try:
thread.join(shutdown_timeout)
except:
logger.warn("Fetcher thread did not stop within %d seconds." % shutdown_timeout)
logger.warning("Fetcher thread did not stop within %d seconds." % shutdown_timeout)
# Set DB status:
logger.debug("Setting test status in DB to 'syncing'...")
try:
......@@ -103,7 +103,7 @@ def sigterm_handler(signum, frame):
cur.close()
cn.close()
except:
logger.warn("Could not connect to database.")
logger.warning("Could not connect to database.")
# Tell the main loop to stop:
mainloop_stop = True
......@@ -494,7 +494,7 @@ class FetchObsThread(threading.Thread):
# Make sure the file is downloaded again at a later point:
copyfilelist.remove(f)
os.unlink("%s/%s" % (self._obsfiledir, fname))
self._logger.warn(self._loggerprefix + "FetchObsThread queue is full. Cannot put %s/%s on it." % (self._obsfiledir, fname))
self._logger.warning(self._loggerprefix + "FetchObsThread queue is full. Cannot put %s/%s on it." % (self._obsfiledir, fname))
# Remove remote files if any are left:
if (len(copyfilelist) > 0):
cmd = ['ssh' ,'%s'%(self._obsethernet), "cd %s;"%self._obstestresfolder, "rm"]
......@@ -562,7 +562,7 @@ def start_fetcher():
msg = str(err)
flocklab.error_logandexit(msg, errno.EIO)
except:
logger.warn("Error %s: %s" %(str(sys.exc_info()[0]), str(sys.exc_info()[1])))
logger.warning("Error %s: %s" %(str(sys.exc_info()[0]), str(sys.exc_info()[1])))
rs = cur.fetchall()
cur.close()
cn.close()
......@@ -599,7 +599,7 @@ def start_fetcher():
thread.start()
logger.debug("Started fetcher thread for observer %d" % (obsid))
except:
logger.warn("Error when starting fetcher thread for observer %d: %s, %s" % (obsid, str(sys.exc_info()[0]), str(sys.exc_info()[1])))
logger.warning("Error when starting fetcher thread for observer %d: %s, %s" % (obsid, str(sys.exc_info()[0]), str(sys.exc_info()[1])))
continue
return flocklab.SUCCESS
......@@ -636,7 +636,7 @@ def stop_fetcher():
# check if there is a remaining fetcher process
pid = flocklab.get_fetcher_pid(testid)
if pid > 0 and pid != os.getpid():
logger.warn("Found a remaining fetcher thread with PID %d, killing it now..." % (pid))
logger.warning("Found a remaining fetcher thread with PID %d, killing it now..." % (pid))
os.kill(pid, signal.SIGKILL)
raise ValueError
else:
......@@ -650,7 +650,7 @@ def stop_fetcher():
cur.close()
cn.close()
except:
logger.warn("Could not connect to database.")
logger.warning("Could not connect to database.")
return errno.ENOPKG
return flocklab.SUCCESS
......@@ -756,7 +756,7 @@ def main(argv):
opts, args = getopt.getopt(argv, "hedt:", ["help", "stop", "debug", "testid="])
except getopt.GetoptError as err:
print(str(err))
logger.warn(str(err))
logger.warning(str(err))
usage()
sys.exit(errno.EINVAL)
except:
......@@ -775,20 +775,20 @@ def main(argv):
except ValueError:
err = "Wrong API usage: testid has to be integer"
print(str(err))
logger.warn(str(err))
logger.warning(str(err))
usage()
sys.exit(errno.EINVAL)
elif opt in ("-e", "--stop"):
stop = True
else:
print("Wrong API usage")
logger.warn("Wrong API usage")
logger.warning("Wrong API usage")
sys.exit(errno.EINVAL)
# Check if the necessary parameters are set ---
if not testid:
print("Wrong API usage")
logger.warn("Wrong API usage")
logger.warning("Wrong API usage")
sys.exit(errno.EINVAL)
# Check if the Test ID exists in the database ---
......@@ -940,7 +940,7 @@ def main(argv):
thread = LogQueueThread(logqueue, logger, LogQueueThread_stopEvent)
thread.start()
except:
logger.warn("Error when starting log queue thread: %s: %s" %(str(sys.exc_info()[0]), str(sys.exc_info()[1])))
logger.warning("Error when starting log queue thread: %s: %s" %(str(sys.exc_info()[0]), str(sys.exc_info()[1])))
# Determine the number of CPU's to be used for each aggregating process. If a service is not used, its CPUs are assigned to other services
cpus_free = 0
......@@ -983,7 +983,7 @@ def main(argv):
service_pools_dict = { 'logs': cpus_logs, 'serial': cpus_serial, 'gpiotracing': cpus_gpiomonitoring, 'powerprofiling': cpus_powerprofiling }
if (cpus_total > multiprocessing.cpu_count()):
logger.warn("Number of requested CPUs for all aggregating processes (%d) is higher than number of available CPUs (%d) on system." % (cpus_total, multiprocessing.cpu_count()))
logger.warning("Number of requested CPUs for all aggregating processes (%d) is higher than number of available CPUs (%d) on system." % (cpus_total, multiprocessing.cpu_count()))
# Start a worker process pool for every service:
for service, cpus in service_pools_dict.items():
......@@ -1057,7 +1057,7 @@ def main(argv):
worker_args = [nextitem, nodeid, testresultsfile_dict['timesynclog'][0], logqueue, None]
worker_f = worker_logs
else:
logger.warn(loggerprefix + "Results file %s/%s from observer %s did not match any of the known patterns" % (fdir, f, obsid))
logger.warning(loggerprefix + "Results file %s/%s from observer %s did not match any of the known patterns" % (fdir, f, obsid))
continue
# Schedule worker function from the service's pool. The result will be reported to the callback function.
pool.apply_async(func=worker_f, args=tuple(worker_args), callback=callback_f)
......@@ -1085,7 +1085,7 @@ def main(argv):
cur.close()
cn.close()
except:
logger.warn("Could not connect to database.")
logger.warning("Could not connect to database.")
# Delete the obsfile directories as they are not needed anymore:
if ((obsfiledir != None) and (os.path.exists(obsfiledir))):
......
......@@ -41,7 +41,7 @@ def main(argv):
opts, args = getopt.getopt(argv, "dh", ["debug", "help"])
except getopt.GetoptError as err:
print(str(err))
logger.warn(str(err))
logger.warning(str(err))
usage()
sys.exit(errno.EINVAL)
except:
......@@ -55,7 +55,7 @@ def main(argv):
usage()
sys.exit(flocklab.SUCCESS)
else:
logger.warn("Wrong API usage")
logger.warning("Wrong API usage")
sys.exit(errno.EINVAL)
# Allow only x instances ---
......
......@@ -111,7 +111,7 @@ def main(argv):
opts, args = getopt.getopt(argv, "dh", ["debug", "help"])
except getopt.GetoptError as err:
print(str(err))
logger.warn(str(err))
logger.warning(str(err))
usage()
sys.exit(errno.EINVAL)
except:
......@@ -125,7 +125,7 @@ def main(argv):
usage()
sys.exit(flocklab.SUCCESS)
else:
logger.warn("Wrong API usage")
logger.warning("Wrong API usage")
sys.exit(errno.EINVAL)
# Connect to the database ---
......
......@@ -155,7 +155,7 @@ def update_configuration_from_db():
logger.error(msg)
flocklab.error_logandexit(msg, errno.EIO)
except:
logger.warn("Error %s: %s" %(str(sys.exc_info()[0]), str(sys.exc_info()[1])))
logger.warning("Error %s: %s" %(str(sys.exc_info()[0]), str(sys.exc_info()[1])))
raise
### END update_configuration_from_db
......@@ -418,7 +418,7 @@ def sig_proxy(signum):
if (pid == os.getpid()):
return errno.ENOPKG
else:
logger.warn("Command failed: %s" % (str(cmd)))
logger.warning("Command failed: %s" % (str(cmd)))
return errno.ENOPKG
# Signal the process to stop:
if (pid > 0):
......@@ -434,10 +434,10 @@ def sig_proxy(signum):
time.sleep(1)
shutdown_timeout = shutdown_timeout - 1
if os.path.exists(pidpath):
logger.warn("Serial proxy is still running, sending it the SIGKILL signal...")
logger.warning("Serial proxy is still running, sending it the SIGKILL signal...")
os.kill(pid, signal.SIGKILL)
except:
logger.warn("Failed to send SIGKILL: %s: %s" % (str(sys.exc_info()[0]), str(sys.exc_info()[1])))
logger.warning("Failed to send SIGKILL: %s: %s" % (str(sys.exc_info()[0]), str(sys.exc_info()[1])))
return flocklab.SUCCESS
### END sig_proxy
......@@ -485,7 +485,7 @@ def main(argv):
opts, args = getopt.getopt(argv, "hnsed", ["help", "notify", "start", "stop", "debug"])
except getopt.GetoptError as err:
print(str(err))
logger.warn(str(err))
logger.warning(str(err))
usage()
sys.exit(errno.EINVAL)
except:
......@@ -506,7 +506,7 @@ def main(argv):
notify = True
else:
print("Wrong API usage")
logger.warn("Wrong API usage")
logger.warning("Wrong API usage")
sys.exit(errno.EINVAL)
# Start / stop the proxy ---
......
......@@ -135,10 +135,10 @@ class UpdateSlotAssignThread(threading.Thread):
self.Queue.put(msg)
except MySQLdb.Error as err:
self.Logger.warn(str(err))
self.Logger.warning(str(err))
sys.exit(errno.EIO)
except:
self.Logger.warn("Error updating serial ID: %s: %s" % (str(sys.exc_info()[0]), str(sys.exc_info()[1])))
self.Logger.warning("Error updating serial ID: %s: %s" % (str(sys.exc_info()[0]), str(sys.exc_info()[1])))
finally:
cur.close()
cn.close()
......@@ -179,11 +179,11 @@ def main(argv):
opts, args = getopt.getopt(argv, "hds:m:fo:de", ["help", "debug", "searchtime", "maxretries", "force", "observer", "develop", "email"])
except getopt.GetoptError as err:
print((str(err)))
logger.warn(str(err))
logger.warning(str(err))
usage()
sys.exit(errno.EINVAL)
except:
logger.warn("Error %s: %s" % (str(sys.exc_info()[0]), str(sys.exc_info()[1])))
logger.warning("Error %s: %s" % (str(sys.exc_info()[0]), str(sys.exc_info()[1])))
sys.exit(errno.EINVAL)
for opt, arg in opts:
if opt in ("-h", "--help"):
......@@ -198,7 +198,7 @@ def main(argv):
if (searchtime <= 0.0):
raise ValueError
except:
logger.warn("Wrong API usage: %s" %str(arg))
logger.warning("Wrong API usage: %s" %str(arg))
usage()
sys.exit(errno.EINVAL)
elif opt in ("-f", "--force"):
......@@ -219,14 +219,14 @@ def main(argv):
if (maxretries < 0):
raise ValueError
except:
logger.warn("Wrong API usage: %s" %str(arg))
logger.warning("Wrong API usage: %s" %str(arg))
usage()
sys.exit(errno.EINVAL)
elif opt in ("-e", "--email"):
email = True
else:
print("Wrong API usage")
logger.warn("Wrong API usage")
logger.warning("Wrong API usage")
usage()
sys.exit(errno.EINVAL)
......@@ -263,10 +263,10 @@ def main(argv):
""" % (status, observer)
cur.execute(sql)
except MySQLdb.Error as err:
logger.warn(str(err))
logger.warning(str(err))
sys.exit(errno.EIO)
except:
logger.warn("Error %s: %s" % (str(sys.exc_info()[0]), str(sys.exc_info()[1])))
logger.warning("Error %s: %s" % (str(sys.exc_info()[0]), str(sys.exc_info()[1])))
rs = cur.fetchall()
cur.close()
cn.close()
......@@ -280,7 +280,7 @@ def main(argv):
threadlist.append(t)
t.start()
except:
logger.warn("Error when starting thread for observer %s: %s: %s" % (observerdata[1], str(sys.exc_info()[0]), str(sys.exc_info()[1])))
logger.warning("Error when starting thread for observer %s: %s: %s" % (observerdata[1], str(sys.exc_info()[0]), str(sys.exc_info()[1])))
continue
# Wait for threads to finish:
logger.debug("Joining threads")
......@@ -292,9 +292,9 @@ def main(argv):
thread_timeoutadd = 0
t.join(timeout=(10 + thread_timeoutadd))
if t.isAlive():
logger.warn("Timeout when joining thread - is still alive...")
logger.warning("Timeout when joining thread - is still alive...")
except:
logger.warn("Error when joining threads...")
logger.warning("Error when joining threads...")
continue
# Get all messages from the threads which are now in the queue and send them to the admin:
try:
......@@ -315,7 +315,7 @@ def main(argv):
else:
print(msg)
except:
logger.warn("Error when sending change notifications to admin. %s: %s" % (str(sys.exc_info()[0]), str(sys.exc_info()[1])))
logger.warning("Error when sending change notifications to admin. %s: %s" % (str(sys.exc_info()[0]), str(sys.exc_info()[1])))
logger.debug("Slot assignment updater finished.")
......
......@@ -48,7 +48,7 @@ def load_config():
global config
if config:
if logger:
logger.warn("Config already loaded")
logger.warning("Config already loaded")
return SUCCESS
config = get_config()
if not config:
......@@ -85,7 +85,7 @@ def get_config():
def init_logger(loggername=scriptname):
global logger
if logger:
logger.warn("Logger already initialized.")
logger.warning("Logger already initialized.")
return SUCCESS # already initialized
logger = get_logger(loggername)
if not logger:
......@@ -137,7 +137,7 @@ def log_error(msg=""):
def log_warning(msg=""):
global logger
logger.warn(msg)
logger.warning(msg)
### END log_warning()
def log_debug(msg=""):
......@@ -1118,7 +1118,7 @@ def parse_int(s):
res = int(float(s.strip())) # higher success rate if first parsed to float
except ValueError:
if logger:
logger.warn("Could not parse %s to int." % (str(s)))
logger.warning("Could not parse %s to int." % (str(s)))
return res
### END parse_int()
......@@ -1187,6 +1187,7 @@ def patch_binary(symbol=None, value=None, binaryfile=None, arch=None):
##############################################################################
#
# bin_to_hex() converts a binary (ELF) file to Intel hex format
# -> as alternative, use intelhex python module
#
##############################################################################
def bin_to_hex(binaryfile=None, arch=None, outputfile=None):
......@@ -1225,3 +1226,34 @@ def bin_to_hex(binaryfile=None, arch=None, outputfile=None):
return SUCCESS
### END bin_to_hex()
##############################################################################
#
# is_hex_file() checks whether the file is an intel hex file (basic checks only!)
#
##############################################################################
def is_hex_file(filename=None, data=None):
if filename == None and data == None:
return FAILED
if (filename != None and not os.path.isfile(filename)):
return FAILED
try:
if filename != None:
f = open(filename, 'rb')
data = f.read()
f.close()
# try to decode as ASCII, if it fails then this is not a hex file
decoded_data = data.decode('ascii')
lines = decoded_data.split('\n')
for line in lines:
line = line.strip()
if line == "":
continue