maposmatic/scripts/dbck.py

162 wiersze
5.9 KiB
Python
Executable File

#!/usr/bin/python
# coding: utf-8
# maposmatic, the web front-end of the MapOSMatic city map generation system
# Copyright (C) 2010 David Decotigny
# Copyright (C) 2010 Frédéric Lehobey
# Copyright (C) 2010 David Mentré
# Copyright (C) 2010 Maxime Petazzoni
# Copyright (C) 2010 Thomas Petazzoni
# Copyright (C) 2010 Gaël Utard
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or 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 Affero General Public License for more details.
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import sys
from django import db
from www.maposmatic.models import MapRenderingJob
from www.settings import RENDERING_RESULT_PATH, RENDERING_RESULT_FORMATS
class DbckHandler:
pass
class DummyDbckHandler(DbckHandler):
"""
A dummy MapOSMatic Dbck handler for the dry runs. It does nothing but
returning a detail message about the job status relevant to each check
operation.
"""
def do_obsolete(self, job):
return 'elligible for obsolete status!'
def do_admin_bbox(self, job):
return 'has both admin and bbox values!'
def do_locale(self, job):
return 'no locale information!'
class RealDbckHandler(DummyDbckHandler):
"""
The 'real' MapOSMatic Dbck handler that actually fixes jobs. See each
check operation details for more information and what's done in each case.
"""
DEFAULT_LOCALE = 'en_US.UTF-8'
def do_obsolete(self, job):
"""If the job is obsolete, but not marked as such in the database (i.e.
its status is 2 'Done', but it doesn't have all its output files
present), ask the job to remove all its files and mark itself as
obsolete."""
removed, saved = job.remove_all_files()
return 'removed %d file(s) and marked obsolete.' % removed
def do_admin_bbox(self, job):
"""If the job has both administrative boundary/osmID information and a
bounding box, always prefer the OSM ID, and purge the bounding box
information. In the daemon, the OSM ID always takes precedence
anyways."""
job.lat_upper_left = None
job.lon_upper_left = None
job.lat_bottom_right = None
job.lon_bottom_right = None
job.save()
return 'cleared bounding box, keeping osmid %d.' % \
job.administrative_osmid
def do_locale(self, job):
"""If the job has no locale defined, make sure it has one, using the
DEFAULT_LOCALE defined in RealDbckHandler."""
job.map_language = self.DEFAULT_LOCALE
job.save()
return 'missed locale information, fell back to %s.' % \
self.DEFAULT_LOCALE
class MapOSMaticDbck:
"""
A database checker/fixer for MapOSMatic. It runs a series of checks on
all jobs from the database, eventually taking action to fix things that are
wrong if a capable DbckHandler is provided.
To add checks, write a check function that makes use of the correction
operation from a handler and add it to the list of checks.
"""
def __init__(self, handler=None):
self.jobs = MapRenderingJob.objects.all().order_by('id')
self.handler = handler or DbckHandler()
self.checks = [self.__check_obsolete,
self.__check_admin_bbox,
self.__check_locale,
]
print 'Starting MapOSMatic database checker: %d job(s), ' \
'%d check(s) with %s.' % (self.jobs.count(), len(self.checks),
self.handler.__class__.__name__)
def run(self):
for job in self.jobs:
messages = []
for check in self.checks:
try:
messages.append(check(job))
except (NotImplementedError, AttributeError):
messages.append("%s not available!" % check.__name__)
messages = filter(None, messages)
if len(messages):
print ' + checking job #%d (%s): ' % (job.id, job.maptitle)
for m in messages:
print ' `', m
print 'Check/repair complete. Database queries performed: %d.' % \
len(db.connection.queries)
def __check_obsolete(self, job):
"""Checks the obsolete status of the given job. If the job is in the
done state (status=2) and does not have all its output files, it's
obselete and should be cleaned."""
if not job.is_done_ok():
return
files = job.output_files()
if (len(files['maps']) < len(RENDERING_RESULT_FORMATS)-1 or
(len(files['indeces']) > 0 and
len(files['indeces']) < len(RENDERING_RESULT_FORMATS))):
return self.handler.do_obsolete(job)
def __check_admin_bbox(self, job):
"""Make sure we don't have mutually exclusive admin/bbox data."""
if job.administrative_osmid and (job.lat_upper_left or
job.lon_upper_left or
job.lat_bottom_right or
job.lon_bottom_right):
return self.handler.do_admin_bbox(job)
def __check_locale(self, job):
"""Make sure the job declares a map language."""
if not job.map_language:
return self.handler.do_locale(job)
if __name__ == '__main__':
if len(sys.argv) == 2 and sys.argv[1] == '--dry-run':
handler = DummyDbckHandler()
else:
handler = RealDbckHandler()
MapOSMaticDbck(handler).run()