Skip to content
Snippets Groups Projects
Commit 7f5627e5 authored by Yohan Jarosz's avatar Yohan Jarosz
Browse files

Simpler and more efficient CL wrapper

parent e32c2716
No related branches found
No related tags found
No related merge requests found
......@@ -3,6 +3,8 @@ from lib.docopt import docopt
from lib.path import Path
import subprocess
import os
import json
import shlex
__doc__ = """Integrated Metaomic Pipeline.
____ __ __ ____
......@@ -11,88 +13,20 @@ __doc__ = """Integrated Metaomic Pipeline.
(____)(_/\/\_)(__)
Usage:
IMP init <data> <output> [<name>]
IMP run [VAR ...]
IMP -h | --help
IMP -d DATA -o OUTPUT [--enter] [-n CONTAINER] [-e ENV] ... [COMMANDS ...]
IMP (-h | --help)
IMP --version
Options:
-h --help Show this help and exit
-d DATA Path to the data
-e ENV Environment variable to pass to the container
--enter Enter the container
-h --help Show this help and exit
-n CONTAINER Name of the container. Useful when you want to run a previous version of IMP.
-o OUTPUT Path to the output directory
Parameters:
** INIT **
<data>: the path where your data is stored
<output>: the path where IMP will write result files
<name>: the name of the configuration file [default:IMP]
** RUN **
VAR: any command or flag will be forwarded to the underlying Snakemake.
Try '-l' to have a list of all commands available.
"""
DOCKER_COMPOSE_TMPL = """imp:
image: imp
env_file: {output}/.env
volumes:
- {data}:/data
- {code}:/home/imp/integrated-metaomic-pipeline
- {output}:/output
environment:
- IMP_NAME={name}
"""
IMP_CACHE = Path('.imp')
IMP_CACHE.makedirs_p()
IMP_CONFIG_CACHE = IMP_CACHE / 'configs'
IMP_CONFIG_CACHE.touch()
def get_config_cache():
cache = None
with open(IMP_CONFIG_CACHE, 'r') as rhandle:
cache = rhandle.read()
return cache
def add_to_cache(pth):
with open(IMP_CONFIG_CACHE, 'a') as whandle:
whandle.write(pth + os.linesep)
def write_to_cache(pth):
with open(IMP_CONFIG_CACHE, 'w') as whandle:
whandle.write(pth + os.linesep)
def yes_or_no(question):
reply = str(input(question + ' (y/n): ')).lower().strip()
if reply[0] == 'y':
return True
if reply[0] == 'n':
return False
else:
return yes_or_no("Please enter ")
def select(title, questions):
s = os.linesep + title
for idx, q in enumerate(questions):
s += os.linesep + '%s) %s.' % (idx + 1, q)
s += os.linesep + 'Choice: '
try:
reply = int(input(s))
except ValueError:
return select("Please type a number: ", questions)
except KeyboardInterrupt:
print(os.linesep, "Exiting ...")
exit(0)
if abs(reply) > len(questions) or reply <= 0:
return select("Please select one of the following: ", questions)
return questions[reply - 1]
CURRENT_PATH = Path('.').abspath()
def get_version():
return subprocess.check_output(
......@@ -102,46 +36,30 @@ def get_version():
if __name__ == '__main__':
args = docopt(__doc__, version=get_version(), options_first=True)
# get config file from cache
config_files = get_config_cache().split()
# delete if some config files are removed
cfs = []
for cf in config_files:
if Path(cf).exists():
cfs.append(cf)
write_to_cache(os.linesep.join(cfs))
config_files = cfs
# init config
if args['init']:
data = Path(args['<data>']).abspath()
output = Path(args['<output>']).abspath()
name = args['<name>']
if name is None:
name = 'IMP'
if not output.exists():
output.makedirs()
docker_compose_path = Path(output / '%s.yml' % name)
env_file = Path(output / '.env').touch()
compose = DOCKER_COMPOSE_TMPL.format(data=data, output=output, code=CURRENT_PATH, name=name)
if docker_compose_path.exists() and not yes_or_no("Configuration already exist. Overwrite ''%s'?" % docker_compose_path):
print("Exiting ... ")
exit(0)
if docker_compose_path not in config_files:
add_to_cache(docker_compose_path)
docker_compose_path.parent.makedirs_p()
with open(docker_compose_path, 'w') as whandle:
whandle.write(compose)
print("Configuration written at {}".format(docker_compose_path))
# run IMP with docker compose
elif args['run']:
if not config_files:
print("You must init IMP first.")
print("Exiting ... ")
exit(0)
elif len(config_files) > 1:
cf = select("Multiple config file found", config_files)
else:
cf = config_files[0]
cmd = ['docker-compose', '-f', cf, 'run', 'imp'] + args['VAR']
subprocess.call(cmd)
CURRENT_PATH = Path(__file__).parent.abspath()
print(args)
data = Path(args['-d']).abspath()
output = Path(args['-o']).abspath()
container_name = args['-n'] is not None and args['-n'] or 'imp:latest'
# configure IMP mount point to the docker container
mount_points = [
'-v %s:/data' % data,
'-v %s:/home/imp/integrated-metaomic-pipeline' % CURRENT_PATH,
'-v %s:/output' % output
]
# environement variables
envs = ['-e {}="{}"'.format(*e.split('=')) for e in args['-e']]
# CL
cmd = ['docker', 'run'] + mount_points + envs
# reconfigure entrypoint if --enter flag is specified
if args['--enter']:
cmd += ['--entrypoint /bin/bash -it']
# add container name and commands to pass to snakemake
cmd += [container_name] + args['COMMANDS']
# parse CL correctly
cmd = shlex.split(' '.join(cmd))
print("Executing", '"', ' '.join(cmd), '"')
subprocess.call(cmd)
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment