Source code for regolith.main

"""The main CLI for regolith"""
from __future__ import print_function

import copy
import os
from argparse import ArgumentParser, RawTextHelpFormatter, Namespace

from regolith.database import connect

from regolith import commands
from regolith import storage
from regolith.builder import BUILDERS
from regolith.commands import INGEST_COLL_LU
from regolith.helper import HELPERS
from regolith.runcontrol import DEFAULT_RC, load_rcfile, filter_databases
from regolith.schemas import SCHEMAS
from regolith.tools import update_schemas
from regolith import __version__

DISCONNECTED_COMMANDS = {
    "rc": lambda rc: print(rc._pformat()),
    "deploy": commands.deploy,
    "store": storage.main,
    "json-to-yaml": commands.json_to_yaml,
    "yaml-to-json": commands.yaml_to_json,
}

CONNECTED_COMMANDS = {
    "add": commands.add_cmd,
    "ingest": commands.ingest,
    "app": commands.app,
    "grade": commands.grade,
    "build": commands.build,
    "email": commands.email,
    "classlist": commands.classlist,
    "validate": commands.validate,
    "helper": commands.helper,
    "fs-to-mongo": commands.fs_to_mongo,
    "mongo-to-fs": commands.mongo_to_fs
}

NEED_RC = set(CONNECTED_COMMANDS.keys())
NEED_RC |= {"rc", "deploy", "store"}


[docs]def create_parser(): p = ArgumentParser() subp = p.add_subparsers(title="cmd", dest="cmd") p.add_argument( "--version", action="store_true" ) # helper subparser subp.add_parser( "helper", help="runs an available helper target", formatter_class=RawTextHelpFormatter, ) # rc subparser subp.add_parser("rc", help="prints run control") # add subparser addp = subp.add_parser( "add", help="adds a record to a database and collection" ) addp.add_argument("db", help="database name") addp.add_argument("coll", help="collection name") addp.add_argument( "documents", nargs="+", help="documents, in JSON / mongodb format" ) # ingest subparser ingp = subp.add_parser( "ingest", help="ingest many records from a foreign " "resource into a database", ) ingp.add_argument("db", help="database name") ingp.add_argument( "filename", help="file to ingest. Currently valid formats are: \n{}" "".format([k for k in INGEST_COLL_LU]), ) ingp.add_argument( "--coll", dest="coll", default=None, help="collection name, if this is not given it is infered from the " "file type or file name.", ) # store subparser strp = subp.add_parser( "store", help="stores a file into the appropriate " "storage location." ) strp.add_argument("storename", help="storage name") strp.add_argument( "documents", nargs="+", help="paths to documents, i.e. " "PDFs, images, etc.", ) strp.add_argument( "-f", "--force", dest="force", default=False, action="store_true", help="forces copy of file if one of the same name " "already exists", ) # app subparser appp = subp.add_parser( "app", help="starts up a flask app for inspecting and " "modifying regolith data.", ) appp.add_argument( "--debug", dest="debug", action="store_true", default=False, help="starts server in debug mode", ) # grade subparser grdp = subp.add_parser( "grade", help="starts up a flask app for adding " "grades to the database.", ) grdp.add_argument( "--debug", dest="debug", action="store_true", default=False, help="starts server in debug mode", ) # builder subparser bldp = subp.add_parser( "build", help="builds various available targets", formatter_class=RawTextHelpFormatter, ) bldp.add_argument( "build_targets", nargs="+", help="targets to build. Currently valid targets are: \n{}".format( [k for k in BUILDERS] ), ) bldp.add_argument( "--no-pdf", dest="pdf", help="don't produce PDFs during the build " "(for builds which produce PDFs)", action="store_false", default=True, ) bldp.add_argument( "--from", dest="from_date", help="date in form YYYY-MM-DD. Items will only be built" " if their date or end_date is equal or after this date", default=None, ) bldp.add_argument( "--to", dest="to_date", help="date in form YYYY-MM-DD. Items will only be built" " if their date or begin_date is equal or before this date", default=None, ) bldp.add_argument( "--grants", nargs='+', dest="grants", help="specify a grant or a space-separated list of grants so items are " "built only if associated with this(these) grant(s)", default=None, ) bldp.add_argument( "--people", nargs='+', dest="people", help="specify a person or a space-separated list of people such that " "the build will be for only those people", default=None, ) # deploy subparser depp = subp.add_parser( "deploy", help="deploys what was built by regolith") # email subparser emlp = subp.add_parser("email", help="automates emailing") emlp.add_argument( "email_target", help='targets to email, eg "test" or ' '"grades".' ) emlp.add_argument( "--to", default=None, dest="to", help="receiver of email" ) emlp.add_argument( "--subject", dest="subject", help="email subject line", default="" ) emlp.add_argument( "--body", dest="body", help="email body, as restructured text", default="", ) emlp.add_argument( "--attach", nargs="+", dest="attachments", default=(), help="attachments to send along as well.", ) emlp.add_argument( "-c", "--course-id", dest="course_ids", default=(), nargs="+", help="course identifier that should be emailed.", ) emlp.add_argument("--db", help="database name", dest="db", default=None) # classlist subparser clp = subp.add_parser( "classlist", help="updates classlist information from file" ) clp.add_argument( "op", help='operatation to perform, such as "add" or "replace".' ) clp.add_argument("filename", help="file to read class information from.") clp.add_argument( "course_id", help="course identifier whose registry should be updated" ) clp.add_argument( "-f", "--format", dest="format", default=None, help="file / school format to read information from. Current values are " '"json" and "usc". Determined from extension if not available.', ) clp.add_argument( "-d", "--dry-run", dest="dry_run", action="store_true", default=False, help="only does a dry run and reports results", ) clp.add_argument("--db", help="database name", dest="db", default=None) # JSON-to-YAML subparser jty = subp.add_parser( "json-to-yaml", help="Converts files from JSON to YAML" ) jty.add_argument("files", nargs="+", help="file names to convert") # YAML-to-JSON subparser ytj = subp.add_parser( "yaml-to-json", help="Converts files from YAML to JSON" ) ytj.add_argument("files", nargs="+", help="file names to convert") # mongo-to-fs subparser mtf = subp.add_parser( "mongo-to-fs", help="Backup database from mongodb to filesystem as json. The database will be imported to the destination " "specified by the 'database':'dst_url' key. For this to work, ensure that the database is included in the " "dst_url, and that local is set to true." ) mtf.add_argument("--host", help="Specifies a resolvable hostname for the mongod to which to connect. By " "default, the mongoexport attempts to connect to a MongoDB instance running " "on the localhost on port number 27017.", dest="host", default=None) # fs-to-mongo subparser ftm = subp.add_parser( "fs-to-mongo", help="Import database from filesystem to mongodb. By default, the database will be import to the local " "mongodb. The database can also be imported to the destination specified by the 'database':'dst_url' key." " For this to work, ensure that the database is included in the dst_url, and that local is set to true." ) ftm.add_argument("--host", help="Specifies a resolvable hostname for the mongod to which to connect. By " "default, the mongoimport attempts to connect to a MongoDB instance running " "on the localhost on port number 27017.", dest="host", default=None) # Validator val = subp.add_parser("validate", help="Validates db") val.add_argument( "--collection", dest="collection", default=None, help="If provided only validate that collection", ) return p
[docs]def main(args=None): rc = copy.copy(DEFAULT_RC) parser = create_parser() args0 = Namespace() args1, rest = parser.parse_known_args(args, namespace=args0) if args1.version: print(__version__) return rc if args1.cmd == 'helper': p = ArgumentParser(prog='regolith helper') p.add_argument( "helper_target", help="helper target to run. Currently valid targets are: \n{}".format( [k for k in HELPERS] ), ) if len(rest) == 0: p.print_help() args2, rest2 = p.parse_known_args(rest, namespace=args0) # it is not apparent from this but the following line calls the suparser in # in the helper module to get the rest of the args. HELPERS[args2.helper_target][1](p) if len(rest2) == 0: p.print_help() args3, rest3 = p.parse_known_args(rest, namespace=args0) ns = args3 else: ns = args1 if ns.cmd in NEED_RC: if os.path.exists(rc.user_config): rc._update(load_rcfile(rc.user_config)) rc._update(load_rcfile("regolithrc.json")) rc._update(ns.__dict__) if "schemas" in rc._dict: user_schema = copy.deepcopy(rc.schemas) default_schema = copy.deepcopy(SCHEMAS) rc.schemas = update_schemas(default_schema, user_schema) else: rc.schemas = SCHEMAS if ns.cmd in NEED_RC: filter_databases(rc) if rc.cmd in DISCONNECTED_COMMANDS: DISCONNECTED_COMMANDS[rc.cmd](rc) else: dbs = None if rc.cmd == 'build': dbs = commands.build_db_check(rc) elif rc.cmd == 'helper': dbs = commands.helper_db_check(rc) with connect(rc, dbs=dbs) as rc.client: CONNECTED_COMMANDS[rc.cmd](rc) return rc
if __name__ == "__main__": main()