Commit 1bb7eff3 authored by LE GAC Renaud's avatar LE GAC Renaud
Browse files

Copy the last version of the run command from track_publications.

parent fb261bd6
#!/usr/bin/env python
# -*- coding: utf-8 -*-
""" NAME
run -- run a script using the application model
run -- run a script or python tests within the application framework
SYNOPSIS
run [options] script.py
run [options] <command> [args]
DESCRIPTION
run the script in the web2py context when the
application model is instantiated.
The command has to be run in the scripts directory
It can execute the subcommands 'dump', 'loop', 'mysql', 'script'
and 'pytest'.
OPTIONS
-a, --application
Name of the application
The same software can serve several applications with only differ
by their databases. the subcommand can be applies to one of the
applications or to all of them.
The 'script' subcommand runs a python script in the application
context (model, modules and database are available). By default
the application is the current one.
> cd ... track_publications/scripts
> ./run script my_script.py
When the same software serves several applications, it is possible
to select one of the application:
> ./run -S my_application_2 script my_script.py
The `loop` subcommand allows to execute the same script on all
applicatons. It used the DBURIS dictionary located in models/_db_pro.py.
For each application a confirmation is required before executing the
python script:
> ./run loop ../models/_db_pro.py my_script.py
The 'mysql' subcommand allows to execute a sql script on all databases.
It used the DBURIS dictionary to connect to them. For each application
a confirmation is required before excetuting the sql script. The
database of one application can also be selected with the --shell
option.
> ./run mysql ../models/_db_pro.py my_script.sql
> ./run -S my_app_2 mysql ../models/_db_pro.py my_script.sql
The 'dump' subcommand dumps the content of all databases. It used the
DBURIS dictionary to connect to them and the command mysqldump. For
each application a confirmation is required before the dump. The
database of one application can also be dumped with the --shell
option.
> ./run dump ../models/_db_pro.py
> ./run -S my_app_2 dump ../models/_db_pro.py
The 'pytest' subcommand runs python tests within the pytest framework
and the application context. The python tests are located in the
directory myapplication/tests. The path of the tests is relative to
that directory.
OPTIONS
-h, --help
Display the help and exit.
-S, --shell
By default the application is track_publications.
This allow to select another one.
EXAMPLE
> cd ... myapp/scripts
> ./run myscript.py
> cd ... track_publications/scripts
> ./run -h
> ./run script -h
> ./run script my_script.py
> ./run loop -h
> ./run loop ../models/_db_pro.py my_script.py
> ./run mysql -h
> ./run mysql ../models/_db_pro.py my_script.sql
> ./run dump -h
> ./run dump ../models/_db_pro.py
> ./run pytest -h
> ./run pytest
> ./run pytest -xq test_foo/test_faa.py::test_fii
> ...
AUTHOR
R. Le Gac
"""
if __name__ == "__main__":
import datetime
import os
import pytest
import re
import subprocess
import sys
MSG_DUMP = '\nDump the database of "%s" [y/N]: '
MSG_SCRIPT = '\nExecute "%s" on "%s" [y/N]: '
MYSQL = '/usr/bin/mysql'
MYSQLDUMP = '/usr/bin/mysqldump'
PYTEST_SCRIPT = '_run_pytest.py'
REG_MYSQL = re.compile(r"mysql://(\w+):(\w+)@([\w\.]+)/(\w+)")
TEST_DIR = 'tests'
WEB2PY_DIR = '../../web2py'
WEB2PY = os.path.join(WEB2PY_DIR, 'web2py.py')
def get_application():
"""Return the name of the current application.
The following file structure is assumed:
myapplication/scripts
Returns:
string: the name of the application
"""
return os.getcwd().split(os.sep)[-2]
def mysql(dburi, script):
"""Exceute the script on the mysql database.
Args:
dburi (str): mysql database identifier used by web2py.
script (str): file name of the script
"""
match = REG_MYSQL.match(dburi)
if not match:
print "Can't decode the URIs !!!"
return
cmd = [MYSQL,
"-h", match.group(3),
"-u", match.group(1),
"-p%s" % match.group(2),
match.group(4),
"< ", script]
ret = subprocess.call(" ".join(cmd), shell=True)
if ret == 0:
print "Database modified."
def mysqldump(dburi):
"""Dump the mysql database into an sql file.
Args:
dburi (str): mysql database identifier used by web2py.
"""
match = REG_MYSQL.match(dburi)
if not match:
print "Can't decode the URIs !!!"
return
dbname = match.group(4)
now = datetime.datetime.now()
fnsql = "%s_%s.sql" % (dbname, now.strftime("%y%m%d"))
cmd = [MYSQLDUMP,
"-h", match.group(3),
"-u", match.group(1),
"-p%s" % match.group(2),
dbname,
"> ", fnsql]
ret = subprocess.call(" ".join(cmd), shell=True)
if ret == 0:
print "Database dumped in %s." % fnsql
def process(application, script, args):
"""Process the script within the framework of the application
Args:
application (str): the name of the application
script (str): filename for the script
args (str): optional argument to be passed to the script
Returns:
int: return code of the subprocess
"""
script_path = os.path.join(os.getcwd(), script)
cmd = [WEB2PY,
'--no-banner',
'--shell', application,
'--import_models',
'--run', script_path]
if args:
cmd.extend(['--args', args])
return subprocess.call(cmd)
def run_dump(args):
"""Dump the content of databases defined in the DBURIS dictionary.
It used the command mysqldump.
Args:
args
import os
import subprocess
import sys
"""
# instantiate the DBURIS dictionary
execfile(args.dburis)
# loop over databases
for app, dburi in locals()['DBURIS'].iteritems():
msg = MSG_DUMP % app
rep = raw_input(msg)
if rep != "y":
print "Skip..."
continue
mysqldump(dburi)
def run_loop(args):
"""Run the python script on several applications.
Args:
args
"""
# instantiate the DBURIS dictionary
execfile(args.dburis)
# loop over applications
for app in locals()['DBURIS']:
msg = MSG_SCRIPT % (args.filename, app)
rep = raw_input(msg)
if rep != "y":
print "Skip..."
continue
process(app, args.filename, args.args)
def run_mysql(args):
"""Run a sql script on all the databases defined in the DBURIS dictionary.
Args:
args
"""
# instantiate the DBURIS dictionary
execfile(args.dburis)
# loop over databases
for app, dburi in locals()['DBURIS'].iteritems():
msg = MSG_SCRIPT % (args.filename, app)
rep = raw_input(msg)
if rep != "y":
print "Skip..."
continue
mysql(dburi, args.filename)
def run_pytest(args):
"""Run python test.
Args:
args
"""
cmd = ""
# collect active option
for k, v in vars(args).iteritems():
if not v or k in ("func", "path", "shell"):
continue
elif k == "capture":
cmd = "%s --%s %s" % (cmd, k, v)
else:
cmd = "%s --%s" % (cmd, k)
# add the path for a given test
path = os.path.join("applications", args.shell, TEST_DIR)
if args.path:
path = os.path.join(path, args.path)
cmd = "%s %s" % (cmd, path)
# run pytest script in the application context
return_code = process(args.shell, PYTEST_SCRIPT, cmd)
sys.exit(return_code)
def run_script(args):
"""Run the given script.
Args:
args
"""
return_code = process(args.shell, args.filename, args.args)
sys.exit(return_code)
if __name__ == "__main__":
from argparse import ArgumentParser
APP = os.getcwd().split(os.sep)[-2]
WEB2PY_DIR = '../../web2py'
WEB2PY = os.path.join(WEB2PY_DIR, 'web2py.py')
# protection
if os.getcwd().split(os.sep)[-1] != "scripts":
print "Should be run in the scripts directory."
sys.exit(1)
if not os.path.exists(WEB2PY):
print "The application web2py is not located in ../../web2py."
sys.exit(1)
# command line options
PARSER = ArgumentParser()
PARSER.add_argument('-a', '--app',
default=APP,
dest='application',
help='the name of the application.')
PARSER.add_argument("-S", "--shell",
default=get_application(),
help="run web2py in interactive shell "
"with specified appname [%(default)s]")
PARSER.add_argument('script',
help='the name of the script to be run.')
SUBPARSERS = PARSER.add_subparsers(title="subcommands",
description="valid subcommands",
help="additional help")
# parser for the dump subcommand
CDM1 = SUBPARSERS.add_parser("dump",
help="dump database contents in files")
PARSER.add_argument('args',
nargs='*',
help='the arguments for the script.')
CDM1.add_argument("dburis",
help="path to the python file containing the "
"DBURIS dictionary.")
ARGS = PARSER.parse_args()
CDM1.set_defaults(func=run_dump)
# parser for the loop subcommand
CDM2 = SUBPARSERS.add_parser("loop",
help="run the python script "
"over applications.")
CDM2.add_argument("dburis",
help="path to the python file containing the "
"DBURIS dictionary.")
CDM2.add_argument("filename",
help="the name of the python script.")
CDM2.add_argument("args",
nargs="?",
help="additional arguments to be passed to the script.")
CDM2.set_defaults(func=run_loop)
# run the script in the application context
CMD = [WEB2PY,
'--no-banner',
'--shell', ARGS.application,
'--import_models',
'--run', os.path.join(os.getcwd(), ARGS.script)]
# parser for the mysql subcommand
CDM3 = SUBPARSERS.add_parser("mysql",
help="run the sql script over applications.")
if ARGS.args:
CMD.append('--ARGS')
CMD.extend(ARGS.args)
CDM3.add_argument("dburis",
help="path to the python file containing the "
"DBURIS dictionary.")
RETURN_CODE = subprocess.call(CMD)
CDM3.add_argument("filename",
help="the name of the sql script.")
# exit
sys.exit(RETURN_CODE)
CDM3.set_defaults(func=run_mysql)
# parser for the pytest subcommand
CDM4 = SUBPARSERS.add_parser("pytest",
help="run python unitary tests.")
CDM4.add_argument("-q", "--quiet",
action="store_true",
help="minimal output.")
CDM4.add_argument("--capture",
choices=["fd", "sys", "no"],
help="per-test capturing method: one of fd|sys|no.")
CDM4.add_argument("-x" , "--exitfirst",
action="store_true",
help='stop after first failure.')
CDM4.add_argument("-v", "--verbose",
action="store_true",
help="verbose mode.")
CDM4.add_argument("path",
nargs="?",
help="test path relative to the test directory.")
CDM4.set_defaults(func=run_pytest)
# parser for the script subcommand
CDM5 = SUBPARSERS.add_parser("script",
help="run dedicated python script.")
CDM5.add_argument("filename",
help="the name of the python script.")
CDM5.add_argument("args",
nargs="?",
help="additional arguments to be passed to the script.")
CDM5.set_defaults(func=run_script)
# parse the command line and run the selected command
ARGS = PARSER.parse_args()
ARGS.func(ARGS)
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment