157 lines
5.9 KiB
Python
157 lines
5.9 KiB
Python
|
#!/usr/bin/env python
|
||
|
# -*- coding: utf-8 mode: python -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
|
||
|
|
||
|
"""Interroger la base deploydb
|
||
|
"""
|
||
|
|
||
|
import logging; log = logging.getLogger(__name__)
|
||
|
import sys
|
||
|
from os import path
|
||
|
from argparse import ArgumentParser
|
||
|
|
||
|
from .utils import *
|
||
|
from .parser import Parser
|
||
|
from .objects import catalog
|
||
|
|
||
|
DEFAULT_CONFIG = 'deploydb.conf'
|
||
|
USER_CONFDIR = path.expanduser('~/etc/deploy')
|
||
|
SYSTEM_CONFDIR = '/var/local/deploy'
|
||
|
|
||
|
DEFAULT_MODULES = ['base']
|
||
|
DEFAULT_FUNC = 'base.query'
|
||
|
DEFAULT_ACTION = 'run'
|
||
|
|
||
|
SCRIPTDIR = path.dirname(path.dirname(path.dirname(__file__)))
|
||
|
|
||
|
################################################################################
|
||
|
# Programme principal
|
||
|
|
||
|
logging.basicConfig()
|
||
|
|
||
|
from argparse import ArgumentParser, HelpFormatter
|
||
|
if sys.argv[1:2] == ['--compat']:
|
||
|
# Avec l'argument --compat, désactiver la classe FancyHelpFormatter qui
|
||
|
# se base sur une API non documentée
|
||
|
sys.argv = sys.argv[0:1] + sys.argv[2:]
|
||
|
FancyHelpFormatter = HelpFormatter
|
||
|
else:
|
||
|
class FancyHelpFormatter(HelpFormatter):
|
||
|
"""Comme HelpFormatter, mais ne touche pas aux lignes qui commencent par les
|
||
|
caractères '>>>'. Cela permet de mixer du texte formaté et du texte non
|
||
|
formaté.
|
||
|
"""
|
||
|
def _fill_text(self, text, width, indent):
|
||
|
return ''.join([indent + line for line in text.splitlines(True)])
|
||
|
def _split_lines(self, text, width):
|
||
|
lines = ['']
|
||
|
for line in text.splitlines():
|
||
|
if line.startswith('>>>'):
|
||
|
lines.append(line)
|
||
|
lines.append('')
|
||
|
else:
|
||
|
lines[-1] += '\n' + line
|
||
|
lines = filter(None, lines)
|
||
|
texts = []
|
||
|
for line in lines:
|
||
|
if line.startswith('>>>'):
|
||
|
line = line[3:]
|
||
|
if line: texts.append(line)
|
||
|
else:
|
||
|
texts.extend(super(FancyHelpFormatter, self)._split_lines(line, width))
|
||
|
return texts
|
||
|
AP = ArgumentParser(
|
||
|
usage=u"deploydb args...",
|
||
|
description=__doc__,
|
||
|
formatter_class=FancyHelpFormatter,
|
||
|
)
|
||
|
AP.set_defaults(
|
||
|
missing_ok=False,
|
||
|
modules=DEFAULT_MODULES,
|
||
|
func=DEFAULT_FUNC,
|
||
|
resolve=True,
|
||
|
action=DEFAULT_ACTION,
|
||
|
)
|
||
|
AP.add_argument('-c', '--config', dest='config',
|
||
|
help=u"Spécifier le fichier de configuration à utiliser. S'il s'agit d'un nom sans chemin, il est recherché dans les répertoires par défaut.")
|
||
|
AP.add_argument('--missing-ok', action='store_true', dest='missing_ok',
|
||
|
help=u"Sortir sans erreur si le fichier de configuration n'est pas trouvé")
|
||
|
AP.add_argument('-m', '--module', action='append', dest='modules', metavar='MODULE',
|
||
|
help=u"Spécifier un module à charger. Cette option peut être spécifiée autant de fois que nécessaire. Par défaut, seul le module 'base' est chargé.")
|
||
|
AP.add_argument('-r', '--func', dest='func',
|
||
|
help=u"Spécifier la fonction à lancer après le chargement de la base de données. La valeur par défaut est %s" % DEFAULT_FUNC)
|
||
|
AP.add_argument('--no-resolve', action='store_false', dest='resolve',
|
||
|
help=u"Ne pas résoudre les objets avant de lancer la fonction. Cette option avancée ne devrait pas avoir besoin d'être utilisée.")
|
||
|
AP.add_argument('--run', action='store_const', dest='action', const='run',
|
||
|
help=u"Lancer la fonction spécifiée avec l'option --func")
|
||
|
AP.add_argument('--dump', action='store_const', dest='action', const='dump',
|
||
|
help=u"Afficher le contenu de la base de données")
|
||
|
AP.add_argument('args', nargs='*')
|
||
|
o = AP.parse_args()
|
||
|
|
||
|
# charger les modules
|
||
|
MODULES = {}
|
||
|
for module in o.modules:
|
||
|
MODULES[module] = __import__('%s_module' % module, globals())
|
||
|
|
||
|
# charger la configuration
|
||
|
config = o.config
|
||
|
if config is not None and ('/' in config or path.isfile(config)):
|
||
|
deploydb_path = [path.abspath(path.dirname(config))]
|
||
|
else:
|
||
|
deploydb_path = [USER_CONFDIR, SYSTEM_CONFDIR, SCRIPTDIR]
|
||
|
cname = config if config is not None else DEFAULT_CONFIG
|
||
|
config = find_in_path(cname, deploydb_path)
|
||
|
if config is None and not o.missing_ok:
|
||
|
raise ValueError("Impossible de trouver le fichier de configuration %s" % cname)
|
||
|
|
||
|
catalog.create_object('deploydb', 'path', dir=deploydb_path)
|
||
|
Parser(config)
|
||
|
|
||
|
dd_path = catalog.get('deploydb', 'path')
|
||
|
dd_include = catalog.get('deploydb', 'include', None, create=False)
|
||
|
if dd_include is not None:
|
||
|
included = set([config])
|
||
|
while True:
|
||
|
done = True
|
||
|
for file in dd_include.get('file', ()):
|
||
|
# cette valeur peut changer au fur et à mesure que les fichiers sont
|
||
|
# inclus. la recharger systématiquement
|
||
|
deploydb_path = dd_path.get('dir', ())
|
||
|
pf = find_in_path(file, deploydb_path)
|
||
|
if pf in included: continue
|
||
|
included.add(pf)
|
||
|
if pf is not None:
|
||
|
Parser(pf)
|
||
|
# il y a peut-être de nouveaux fichiers à inclure. configurer
|
||
|
# une nouvelle itération
|
||
|
done = False
|
||
|
else:
|
||
|
log.warning("deploydb:include: %s: Fichier introuvable", file)
|
||
|
if done: break
|
||
|
|
||
|
deploydb_path = dd_path.get('dir', ())
|
||
|
dd_loadcsv = catalog.get('deploydb', 'loadcsv', None, create=False)
|
||
|
if dd_loadcsv is not None:
|
||
|
otype = dd_loadcsv.first('otype', None)
|
||
|
otype_col = dd_loadcsv.first('otype_col', 'otype')
|
||
|
oid_col = dd_loadcsv.first('oid_col', 'oid')
|
||
|
for file in dd_loadcsv.get('file', ()):
|
||
|
pf = find_in_path(file, deploydb_path)
|
||
|
if pf is not None:
|
||
|
catalog.load_csv(pf, otype, otype_col, oid_col)
|
||
|
else:
|
||
|
log.warning("deploydb:loadcsv: %s: Fichier introuvable", file)
|
||
|
|
||
|
# actions
|
||
|
if o.resolve: catalog.resolve()
|
||
|
|
||
|
if o.action == 'run':
|
||
|
names = o.func.split('.')
|
||
|
func = MODULES[names[0]]
|
||
|
for name in names[1:]:
|
||
|
func = getattr(func, name)
|
||
|
func(*o.args)
|
||
|
|
||
|
elif o.action == 'dump':
|
||
|
catalog.dump()
|