Commit bbe9d6d6 authored by LE GAC Renaud's avatar LE GAC Renaud
Browse files

Remove the obsolete command scripts/run.

parent 75c5739a
#!/usr/bin/env python
# -*- coding: utf-8 -*-
""" NAME
run -- run a script or python tests within the application framework
SYNOPSIS
run [options] <command> [args]
DESCRIPTION
the application framework can be located in the localhost or in
a docker container.
The user should belong to the docker group
when using the latter.
The command has to be run in the scripts directory when the
framework is in the localhost.
The command can execute the subcommands 'dump', 'loop', 'mysql',
'script' and 'pytest'.
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 ...limbra/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 limbra.
This allow to select another one.
EXAMPLE
> cd ... limbra/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
"""
import datetime
import os
import pytest
import re
import subprocess
import sys
DOCKER = "/usr/bin/docker"
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 = "web2py.py"
W2P_CNT = "/opt/web2py"
W2P_DIR = '/opt/web2py'
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 get_web2py(args):
"""Return the command to execute the web2py.py script.
The script can be located either in the localhost or within
a docker container. The preference is given to the localhost.
Args:
args (argparse.Namespace): the argument docker_container and web2py_dir
are used to localised the web2py.py script
Return
list: the command to execute the web2py.py script
"""
cmd = []
# web2py is on the local system
if os.path.exists(args.web2py_dir):
cmd.append(os.path.join(W2P_DIR, WEB2PY))
return cmd
# web2py is in a docker container
# Check if it is running
elif args.docker_container:
out = subprocess.check_output([DOCKER, "ps"])
if out:
for line in out.split("\n"):
li = line.split()
if li and args.docker_container == li[-1]:
cmd = [DOCKER,
"exec",
"-it",
args.docker_container,
os.path.join(W2P_CNT, WEB2PY)]
return cmd
print "\n\tweb2py.py is not found on the local host!"
print "\tNo directory", args.web2py_dir, "on the local host!"
print "\tDocker container", args.docker_container, "is not running!"
print "\tStart container or tune option --web2py-dir, --docker-container.\n"
sys.exit(1)
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
"""
cmd = get_web2py(ARGS)
# the script path depends on the localisation of web2py.py
# either on the localhost or within a docker container
# the length of the command allows to separate the two cases
if len(cmd) == 1:
script_path = os.path.join(os.getcwd(), script)
else:
script_path = os.path.join(W2P_CNT,
"applications",
application,
"scripts",
script)
cmd.extend(['--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 (argparse.Namespace):
"""
# 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 (argparse.Namespace):
"""
# 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 (argparse.Namespace):
"""
# 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 (argparse.Namespace):
"""
cmd = ""
skip_options = ("docker_container", "func", "path", "shell", "web2py_dir")
# collect active option
for k, v in vars(args).iteritems():
if (not v) or (k in skip_options):
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
# protection
if os.getcwd().split(os.sep)[-1] != "scripts":
print "Should be run in the scripts directory."
sys.exit(1)
# command line options
PARSER = ArgumentParser()
PARSER.add_argument("-d", "--docker-container",
default="dev",
help="docker container running web2py [%(default)s]",
metavar="<name>")
PARSER.add_argument("-w", "--web2py-dir",
default=W2P_DIR,
help="local web2py directory [%(default)s].",
metavar="<path>")
PARSER.add_argument("-S", "--shell",
default=get_application(),
help="run web2py in interactive shell "
"with specified appname [%(default)s]",
metavar="<application>")
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")
CDM1.add_argument("dburis",
help="path to the python file containing the "
"DBURIS dictionary.")
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)
# parser for the mysql subcommand
CDM3 = SUBPARSERS.add_parser("mysql",
help="run the sql script over applications.")
CDM3.add_argument("dburis",
help="path to the python file containing the "
"DBURIS dictionary.")
CDM3.add_argument("filename",
help="the name of the sql script.")
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