#!/usr/bin/env python #-*- coding: utf-8 -*- ########################################################################### ## ## ## Copyrights Etienne Chové <chove@crans.org> 2009 ## ## ## ## This program is free software: you can redistribute it and/or modify ## ## it under the terms of the GNU General Public License as published by ## ## the Free Software Foundation, either version 3 of the License, or ## ## (at your option) any later version. ## ## ## ## This program is distributed in the hope that it will be useful, ## ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## ## GNU General Public License for more details. ## ## ## ## You should have received a copy of the GNU General Public License ## ## along with this program. If not, see <http://www.gnu.org/licenses/>. ## ## ## ########################################################################### from __future__ import print_function from modules import OsmoseLog, download from cStringIO import StringIO import sys, os, fcntl, urllib, urllib2, traceback try: import poster.encode import poster.streaminghttp poster.streaminghttp.register_openers() has_poster_lib = True except: has_poster_lib = False import psycopg2 import osmose_config as config import inspect import fileinput import shutil import datetime import dateutil.parser import socket import subprocess import time #proxy_support = urllib2.ProxyHandler() #print proxy_support.proxies #opener = urllib2.build_opener(proxy_support) #urllib2.install_opener(opener) ########################################################################### ## fonctions utiles def get_pstree(pid=os.getpid()): tree = [] while os.path.isdir("/proc/%d"%pid): tree.append((pid, open("/proc/%d/cmdline"%pid).read().replace('\x00', ' ').strip())) pid = int(open("/proc/%d/stat"%pid).read().split(" ")[3]) tree.reverse() return tree class lockfile: def __init__(self, filename): #return self.fn = filename try: olddata = open(self.fn, "r").read() except: olddata = "" try: self.fd = open(self.fn, "w") for l in get_pstree(): self.fd.write("%6d %s\n"%l) self.fd.flush() fcntl.flock(self.fd, fcntl.LOCK_NB|fcntl.LOCK_EX) except: #restore old data self.fd.close() open(self.fn, "w").write(olddata) raise self.ok = True def __del__(self): #return if "fd" in dir(self): try: fcntl.flock(self.fd, fcntl.LOCK_NB|fcntl.LOCK_UN) self.fd.close() except: pass if "fn" in dir(self) and "ok" in dir(self): try: os.remove(self.fn) except: pass class analyser_config: pass def get_version(): cmd = ["git", "describe"] try: proc = subprocess.Popen(cmd, stdout=subprocess.PIPE) version = proc.stdout.readlines()[0].strip() except: version = "(unknown)" return version def set_pgsql_schema(conf, logger, reset=False): if reset: db_schema = '"$user"' elif conf.db_schema: db_schema = conf.db_schema else: db_schema = conf.country logger.log("set pgsql schema to %s" % db_schema) cmd = ["psql"] cmd += conf.db_psql_args cmd += ["-c", "ALTER ROLE %s IN DATABASE %s SET search_path = %s,public;" % (conf.db_user, conf.db_base, db_schema)] logger.execute_out(cmd) ########################################################################### def lock_osmosis_database(logger): osmosis_lock = False for trial in xrange(60): # acquire lock try: lfil = "/tmp/osmose-osmosis_import" osmosis_lock = lockfile(lfil) break except: logger.log(logger.log_av_r + "can't lock %s" % lfil + logger.log_ap) logger.log("waiting 2 minutes") time.sleep(2*60) if not osmosis_lock: logger.log(logger.log_av_r + "definitively can't lock" + logger.log_ap) raise return osmosis_lock def check_database(conf, logger): if "osmosis" in conf.download: # check if database contains all necessary extensions logger.sub().log("check database") gisconn = psycopg2.connect(conf.db_string) giscurs = gisconn.cursor() for extension in ["hstore", "fuzzystrmatch", "unaccent"]: giscurs.execute("""SELECT installed_version FROM pg_available_extensions WHERE name = %s""", [extension]) if giscurs.rowcount != 1 or giscurs.fetchone()[0] == None: logger.log(logger.log_av_r+u"missing extension: "+extension+logger.log_ap) return False for table in ["geometry_columns", "spatial_ref_sys"]: giscurs.execute("""SELECT tablename FROM pg_tables WHERE tablename = %s""", [table]) if giscurs.rowcount != 1: # On PostGIS 2.0, geometry_columns has been moved to a view giscurs.execute("""SELECT viewname FROM pg_views WHERE viewname = %s""", [table]) if giscurs.rowcount != 1: logger.log(logger.log_av_r+u"missing table: "+table+logger.log_ap) return False else: # No need to check permissions for views continue for perm in ["select", "update", "delete"]: giscurs.execute("SELECT has_table_privilege(%s, %s)", [table, perm]) if giscurs.fetchone()[0] == False: logger.log(logger.log_av_r+u"missing permission %s on table: %s" % (perm, table)+logger.log_ap) return False giscurs.close() gisconn.close() return True def init_database(conf, logger): # import osmosis if "osmosis" in conf.download: osmosis_lock = lock_osmosis_database(logger) set_pgsql_schema(conf, logger, reset=True) # drop schema if present - might be remaining from a previous failing import logger.sub().log("DROP SCHEMA %s" % conf.download["osmosis"]) gisconn = psycopg2.connect(conf.db_string) giscurs = gisconn.cursor() sql = "DROP SCHEMA IF EXISTS %s CASCADE;" % conf.download["osmosis"] giscurs.execute(sql) gisconn.commit() giscurs.close() gisconn.close() # schema logger.log(logger.log_av_r+"import osmosis schema"+logger.log_ap) for script in conf.osmosis_pre_scripts: cmd = ["psql"] cmd += conf.db_psql_args cmd += ["-f", script] logger.execute_out(cmd) # data logger.log(logger.log_av_r+"import osmosis data"+logger.log_ap) cmd = [conf.bin_osmosis] dst_ext = os.path.splitext(conf.download["dst"])[1] dir_country_tmp = os.path.join(conf.dir_tmp, conf.download["osmosis"]) shutil.rmtree(dir_country_tmp, ignore_errors=True) os.makedirs(dir_country_tmp) if dst_ext == ".pbf": cmd += ["--read-pbf", "file=%s" % conf.download["dst"]] else: cmd += ["--read-xml", "file=%s" % conf.download["dst"]] cmd += ["-quiet"] cmd += ["--write-pgsql-dump", "directory=%s"%dir_country_tmp, "enableLinestringBuilder=yes"] logger.execute_err(cmd) for script in conf.osmosis_import_scripts: cmd = ["psql"] cmd += conf.db_psql_args cmd += ["-f", script] logger.execute_out(cmd, cwd=dir_country_tmp) shutil.rmtree(dir_country_tmp, ignore_errors=True) # post import scripts logger.log(logger.log_av_r+"import osmosis post scripts"+logger.log_ap) for script in conf.osmosis_post_scripts: cmd = ["psql"] cmd += conf.db_psql_args cmd += ["-f", script] logger.execute_out(cmd) # rename table logger.log(logger.log_av_r+"rename osmosis tables"+logger.log_ap) gisconn = psycopg2.connect(conf.db_string) giscurs = gisconn.cursor() giscurs.execute("DROP SCHEMA IF EXISTS %s CASCADE" % conf.download["osmosis"]) giscurs.execute("CREATE SCHEMA %s" % conf.download["osmosis"]) for t in ["nodes", "ways", "way_nodes", "relations", "relation_members", "users", "schema_info"]: sql = "ALTER TABLE %s SET SCHEMA %s;" % (t, conf.download["osmosis"]) giscurs.execute(sql) gisconn.commit() giscurs.close() gisconn.close() # free lock del osmosis_lock def clean_database(conf, logger, no_clean): if "osmosis" in conf.download: gisconn = psycopg2.connect(conf.db_string) giscurs = gisconn.cursor() if no_clean: # grant read-only access to everybody logger.sub().log("GRANT USAGE %s" % conf.download["osmosis"]) sql = "GRANT USAGE ON SCHEMA %s TO public" % conf.download["osmosis"] logger.sub().log(sql) giscurs.execute(sql) for t in ["nodes", "ways", "way_nodes", "relations", "relation_members", "users", "schema_info"]: sql = "GRANT SELECT ON %s.%s TO public" % (conf.download["osmosis"], t) logger.sub().log(sql) giscurs.execute(sql) else: # drop all tables logger.sub().log("DROP SCHEMA %s" % conf.download["osmosis"]) sql = "DROP SCHEMA IF EXISTS %s CASCADE;" % conf.download["osmosis"] logger.sub().log(sql) giscurs.execute(sql) gisconn.commit() giscurs.close() gisconn.close() ########################################################################### def check_osmosis_diff(conf, logger): logger.log("check osmosis replication") diff_path = conf.download["diff_path"] if not os.path.exists(diff_path): return False for f_name in ["configuration.txt", "download.lock", "state.txt"]: f = os.path.join(diff_path, f_name) if not os.path.exists(f): return False return True def init_osmosis_diff(conf, logger): logger.log(logger.log_av_r+"init osmosis replication for diff"+logger.log_ap) diff_path = conf.download["diff_path"] for f_name in ["configuration.txt", "download.lock", "state.txt"]: f = os.path.join(diff_path, f_name) if os.path.exists(f): os.remove(f) cmd = [conf.bin_osmosis] cmd += ["--read-replication-interval-init", "workingDirectory=%s" % diff_path] cmd += ["-quiet"] logger.execute_err(cmd) for line in fileinput.input(os.path.join(diff_path, "configuration.txt"), inplace=1): if line.startswith("baseUrl"): sys.stdout.write("baseUrl=" + conf.download["diff"]) elif line.startswith("maxInterval"): if "geofabrik" in conf.download["diff"]: # on daily diffs provided by Geofabrik, we should apply only one diff at a time sys.stdout.write("maxInterval=" + str(60*60*24/2)) # 1/2 day at most else: sys.stdout.write("maxInterval=" + str(7*60*60*24)) # 7 day at most else: sys.stdout.write(line) fileinput.close() if conf.download["diff"].endswith("minute/"): from modules import OsmTs OsmTs.run(conf.download["dst"], os.path.join(diff_path, "state.txt"), "minute", logger) else: download.dl(conf.download["diff"] + "state.txt", os.path.join(diff_path, "state.txt"), logger.sub(), min_file_size=10) def run_osmosis_diff(conf, logger): logger.log(logger.log_av_r+"run osmosis replication"+logger.log_ap) diff_path = conf.download["diff_path"] xml_change = os.path.join(diff_path, "change.osc.gz") tmp_pbf_file = conf.download["dst"] + ".tmp" shutil.copyfile(os.path.join(diff_path, "state.txt"), os.path.join(diff_path, "state.txt.old")) try: prev_state_ts = None is_uptodate = False nb_iter = 0 with open(os.path.join(diff_path, "state.txt"), 'r') as f: state_lines = f.readlines() for line in state_lines: print("state: ", line, end=' ') if line.startswith("timestamp="): s = line.translate(None, "\\") state_ts = dateutil.parser.parse(s[len("timestamp="):]).replace(tzinfo=None) cur_ts = datetime.datetime.today() if state_ts < (cur_ts - datetime.timedelta(days=10)): # Skip updates, and directly download .pbf file if extract is too old logger.log(logger.log_av_r + "stop updates, to download full extract" + logger.log_ap) return (False, None) while not is_uptodate and nb_iter < 30: nb_iter += 1 logger.log("iteration=%d" % nb_iter) try: cmd = [conf.bin_osmosis] cmd += ["--read-replication-interval", "workingDirectory=%s" % diff_path] cmd += ["--simplify-change", "--write-xml-change", "file=%s" % xml_change] cmd += ["-quiet"] logger.execute_err(cmd) except: logger.log("waiting 2 minutes") time.sleep(2*60) continue cmd = [conf.bin_osmosis] cmd += ["--read-xml-change", "file=%s" % xml_change] cmd += ["--read-pbf", "file=%s" % conf.download["dst"] ] cmd += ["--apply-change", "--buffer"] cmd += ["--write-pbf", "file=%s" % tmp_pbf_file] cmd += ["-quiet"] logger.execute_err(cmd) shutil.move(tmp_pbf_file, conf.download["dst"]) # find if state.txt is more recent than one day with open(os.path.join(diff_path, "state.txt"), 'r') as f: state_lines = f.readlines() for line in state_lines: print("state: ", nb_iter, " - ", line, end=' ') if line.startswith("timestamp="): s = line.translate(None, "\\") state_ts = dateutil.parser.parse(s[len("timestamp="):]).replace(tzinfo=None) cur_ts = datetime.datetime.today() if prev_state_ts != None: print(" ", prev_state_ts - state_ts) if state_ts > (cur_ts - datetime.timedelta(days=1)): is_uptodate = True elif prev_state_ts == state_ts: is_uptodate = True else: prev_state_ts = state_ts if not is_uptodate: # we didn't get the latest version of the pbf file logger.log(logger.log_av_r + "didn't get latest version of osm file" + logger.log_ap) return (False, None) elif nb_iter == 1: return (True, xml_change) else: # TODO: we should return a merge of all xml change files return (True, None) except: logger.log(logger.log_av_r+"got error, aborting"+logger.log_ap) shutil.copyfile(os.path.join(diff_path, "state.txt.old"), os.path.join(diff_path, "state.txt")) raise ########################################################################### def check_osmosis_change(conf, logger): if not check_osmosis_diff(conf, logger): return False logger.log("check osmosis replication for database") return True def init_osmosis_change(conf, logger): init_osmosis_diff(conf, logger) logger.log(logger.log_av_r+"import osmosis change post scripts"+logger.log_ap) set_pgsql_schema(conf, logger) for script in conf.osmosis_change_init_post_scripts: cmd = ["psql"] cmd += conf.db_psql_args cmd += ["-f", script] logger.execute_out(cmd) set_pgsql_schema(conf, logger, reset=True) def run_osmosis_change(conf, logger): logger.log(logger.log_av_r+"run osmosis replication"+logger.log_ap) diff_path = conf.download["diff_path"] xml_change = os.path.join(diff_path, "change.osc.gz") shutil.copyfile(os.path.join(diff_path, "state.txt"), os.path.join(diff_path, "state.txt.old")) try: osmosis_lock = lock_osmosis_database(logger) set_pgsql_schema(conf, logger) cmd = [conf.bin_osmosis] cmd += ["--read-replication-interval", "workingDirectory=%s" % diff_path] cmd += ["--simplify-change", "--write-xml-change", "file=%s" % xml_change] cmd += ["-quiet"] logger.execute_err(cmd) cmd = ["psql"] cmd += conf.db_psql_args cmd += ["-c", "TRUNCATE TABLE actions"] logger.execute_out(cmd) cmd = [conf.bin_osmosis] cmd += ["--read-xml-change", xml_change] cmd += ["--write-pgsql-change", "database=%s"%conf.db_base, "user=%s"%conf.db_user, "password=%s"%conf.db_password] cmd += ["-quiet"] logger.execute_err(cmd) logger.log(logger.log_av_r+"import osmosis change post scripts"+logger.log_ap) for script in conf.osmosis_change_post_scripts: logger.log(script) cmd = ["psql"] cmd += conf.db_psql_args cmd += ["-f", script] logger.execute_out(cmd) set_pgsql_schema(conf, logger, reset=True) del osmosis_lock return xml_change except: logger.log(logger.log_av_r+"got error, aborting"+logger.log_ap) shutil.copyfile(os.path.join(diff_path, "state.txt.old"), os.path.join(diff_path, "state.txt")) raise ########################################################################### def run(conf, logger, options): err_code = 0 country = conf.country try: version = get_version() except: version = None if not check_database(conf, logger): logger.log(logger.log_av_r+u"error in database initialisation"+logger.log_ap) return 0x10 ########################################################################## ## check for working dirs and creates when needed dirs = [conf.dir_tmp, conf.dir_cache, conf.dir_results, conf.dir_extracts, conf.dir_diffs] if "diff_path" in conf.download: dirs.append(conf.download["diff_path"]) for i in dirs: if not os.path.exists(i): try: os.makedirs(i) except OSError as e: sys.exit("%s\nCheck 'dir_work' in modules/config.py and its permissions" % str(e)) # variable used by osmosis if not "JAVACMD_OPTIONS" in os.environ: os.environ["JAVACMD_OPTIONS"] = "" os.environ["JAVACMD_OPTIONS"] += " -Djava.io.tmpdir="+conf.dir_tmp os.environ["JAVACMD_OPTIONS"] += " -Duser.timezone=GMT" ########################################################################## ## download and create database if options.skip_init: pass elif options.change and check_osmosis_change(conf, logger) and not options.change_init: xml_change = run_osmosis_change(conf, logger) elif "url" in conf.download: newer = False xml_change = None updated = False # set if extract was updated instead of fully downloaded if options.diff and check_osmosis_diff(conf, logger) and os.path.exists(conf.download["dst"]): (status, xml_change) = run_osmosis_diff(conf, logger) if status: newer = True updated = True if not newer and options.skip_download: logger.sub().log("skip download") newer = True if not newer: logger.log(logger.log_av_r+u"downloading"+logger.log_ap) newer = download.dl(conf.download["url"], conf.download["dst"], logger.sub(), min_file_size=8*1024) updated = False if not newer: return 0 init_database(conf, logger) if options.change: init_osmosis_change(conf, logger) elif options.diff and not updated: init_osmosis_diff(conf, logger) if hasattr(conf, "sql_post_scripts"): logger.log(logger.log_av_r+"import post scripts"+logger.log_ap) for script in conf.sql_post_scripts: cmd = ["psql"] cmd += conf.db_psql_args cmd += ["-f", script] logger.execute_out(cmd) ########################################################################## ## analyses country_timestamp = None for analyser, password in conf.analyser.iteritems(): logger.log(logger.log_av_r + country + " : " + analyser + logger.log_ap) if not "analyser_" + analyser in analysers: logger.sub().log("skipped") continue if password == "xxx": logger.sub().log("code is not correct - won't upload to %s" % conf.updt_url) elif not conf.results_url and not has_poster_lib: logger.sub().log("results_url is not correct - won't upload to %s" % conf.updt_url) try: analyser_conf = analyser_config() analyser_conf.dst_dir = conf.dir_results analyser_conf.db_string = conf.db_string analyser_conf.db_user = conf.db_user if conf.db_schema: analyser_conf.db_schema = conf.db_schema else: analyser_conf.db_schema = country analyser_conf.dir_scripts = conf.dir_scripts analyser_conf.options = conf.analyser_options analyser_conf.polygon_id = conf.polygon_id if options.change and xml_change: analyser_conf.src = xml_change elif "dst" in conf.download: analyser_conf.src = conf.download["dst"] lunched_analyser = [] lunched_analyser_change = [] for name, obj in inspect.getmembers(analysers["analyser_" + analyser]): if (inspect.isclass(obj) and obj.__module__ == "analyser_" + analyser and (name.startswith("Analyser") or name.startswith("analyser"))): # analyse analyser_conf.dst_file = name + "-" + country + ".xml" analyser_conf.dst_file += ".bz2" analyser_conf.dst = os.path.join(conf.dir_results, analyser_conf.dst_file) analyser_conf.version = version analyser_conf.verbose = options.verbose analyser_conf.timestamp = country_timestamp with obj(analyser_conf, logger.sub()) as analyser_obj: if not options.change or not xml_change: analyser_obj.analyser() lunched_analyser.append(analyser_obj) else: analyser_obj.analyser_change() lunched_analyser_change.append(analyser_obj) country_timestamp = analyser_obj.config.timestamp # update if (conf.results_url or has_poster_lib) and password != "xxx": logger.sub().log("update") if analyser in conf.analyser_updt_url: list_urls = conf.analyser_updt_url[analyser] else: list_urls = [conf.updt_url] for url in list_urls: update_finished = False nb_iter = 0 while not update_finished and nb_iter < 3: time.sleep(nb_iter * 15) nb_iter += 1 logger.sub().sub().log("iteration=%d" % nb_iter) try: tmp_src = "%s-%s" % (analyser, country) if has_poster_lib: (tmp_dat, tmp_headers) = poster.encode.multipart_encode( {"content": open(analyser_conf.dst, "rb"), "source": tmp_src, "code": password}) tmp_req = urllib2.Request(url, tmp_dat, tmp_headers) fd = urllib2.urlopen(tmp_req, timeout=1800) else: tmp_req = urllib2.Request(url) tmp_url = os.path.join(conf.results_url, analyser_conf.dst_file) tmp_dat = urllib.urlencode([('url', tmp_url), ('source', tmp_src), ('code', password)]) fd = urllib2.urlopen(tmp_req, tmp_dat, timeout=1800) dt = fd.read().decode("utf8").strip() if dt[-2:] != "OK": sys.stderr.write((u"UPDATE ERROR %s/%s : %s\n"%(country, analyser, dt)).encode("utf8")) err_code |= 4 else: logger.sub().sub().log(dt) update_finished = True except socket.timeout: logger.sub().sub().sub().log("got a timeout") pass except: s = StringIO() traceback.print_exc(file=s) logger.sub().log("error on update...") for l in s.getvalue().decode("utf8").split("\n"): logger.sub().sub().log(l) if not update_finished: err_code |= 1 except: s = StringIO() traceback.print_exc(file=s) logger.sub().log("error on analyse...") for l in s.getvalue().decode("utf8").split("\n"): logger.sub().sub().log(l) err_code |= 2 continue finally: if not options.no_clean: for obj in lunched_analyser: with obj as o: o.analyser_clean() for obj in lunched_analyser_change: with obj as o: o.analyser_change_clean() ########################################################################## ## vidange logger.log(logger.log_av_r + u"cleaning : " + country + logger.log_ap) if options.change: pass else: clean_database(conf, logger, options.no_clean or not conf.clean_at_end) if options.diff: # don't erase any file return err_code # remove files if "url" in conf.download and "dst" in conf.download and not options.no_clean: f = ".osm".join(conf.download["dst"].split(".osm")[:-1]) for ext in ["osm", "osm.bz2", "osm.pbf"]: try: os.remove("%s.%s"%(f, ext)) logger.sub().log("DROP FILE %s.%s"%(f, ext)) except: pass return err_code ########################################################################### if __name__ == "__main__": err_code = 0 #===================================== # analyse des arguments from optparse import OptionParser parser = OptionParser() parser.add_option("--verbose", dest="verbose", action="store_true", help="Verbose mode") parser.add_option("--list-analyser", dest="list_analyser", action="store_true", help="List all available analysers") parser.add_option("--list-country", dest="list_country", action="store_true", help="List all available countries") parser.add_option("--country", dest="country", action="append", help="Country to analyse (can be repeated)") parser.add_option("--analyser", dest="analyser", action="append", help="Analyser to run (can be repeated)") parser.add_option("--change", dest="change", action="store_true", help="Run analyser on change mode when available") parser.add_option("--change_init", dest="change_init", action="store_true", help="Initialize database for change mode") parser.add_option("--skip-download", dest="skip_download", action="store_true", help="Don't download extract") parser.add_option("--skip-init", dest="skip_init", action="store_true", help="Don't initialize database") parser.add_option("--no-clean", dest="no_clean", action="store_true", help="Don't remove extract and database after analyses") parser.add_option("--cron", dest="cron", action="store_true", help="Record output in a specific log") parser.add_option("--version", dest="version", action="store_true", help="Output version information and exit") (options, args) = parser.parse_args() analysers_path = os.path.join(os.path.dirname(__file__), "analysers") if options.list_analyser: for fn in sorted(os.listdir(analysers_path)): if fn.startswith("analyser_") and fn.endswith(".py"): print(fn[9:-3]) sys.exit(0) if options.list_country: for k in sorted(config.config.keys()): print(k) sys.exit(0) if options.cron: output = sys.stdout logger = OsmoseLog.logger(output, False) else: output = sys.stdout logger = OsmoseLog.logger(output, True) if options.change_init and not options.change: logger.log(logger.log_av_b+"--change must be specified "+fn[:-3]+logger.log_ap) sys.exit(1) if options.version: print("osmose backend version: %s" % get_version()) sys.exit(0) if not options.country: parser.print_help() sys.exit(1) #===================================== # chargement des analysers old_path = list(sys.path) sys.path.insert(0, analysers_path) logger.log(logger.log_av_v+"loading analyses "+logger.log_ap) analysers = {} for fn in os.listdir(analysers_path): if fn.startswith("analyser_") and fn.endswith(".py"): if options.analyser and fn[:-3] not in options.analyser: continue logger.log(" load "+fn[:-3]) analysers[fn[:-3]] = __import__(fn[:-3]) if options.analyser: count = 0 for k in options.analyser: if k not in analysers: logger.log(logger.log_av_b+"not found "+k+logger.log_ap) count += 1 # user is passing only non-existent analysers if len(options.analyser) == count: sys.exit("No valid analysers specified") sys.path[:] = old_path # restore previous path #===================================== # analyse for country, country_conf in config.config.iteritems(): # filter if options.country and country not in options.country: continue # acquire lock try: lfil = "/tmp/analyse-%s"%country lock = lockfile(lfil) except: logger.log(logger.log_av_r+"can't lock %s"%country+logger.log_ap) if options.cron: sys.stderr.write("can't lock %s\n"%country) for l in open(lfil).read().rstrip().split("\n"): logger.log(" "+l) if options.cron: sys.stderr.write(" "+l+"\n") if options.cron: sys.stderr.flush() err_code |= 0x80 continue country_conf.init() options.diff = not options.change and "diff" in country_conf.download # analyse err_code |= run(country_conf, logger, options) # free lock del lock logger.log(logger.log_av_v+u"end of analyses"+logger.log_ap) sys.exit(err_code)