From de8665b0b05db10c3257f9c645a09638a4732256 Mon Sep 17 00:00:00 2001 From: Trygve Laugstøl Date: Wed, 28 Dec 2016 00:37:54 +0100 Subject: o Improving CLI output and setup. o Adding 'init' command similar to git's init command. Only configurable item is the database to query. Removing the -d/--db argument to all commands as it's read from the configuration instead. o Adding support for querying a remove SPARQL endpoint. --- .gitignore | 1 + requirement.txt | 1 + trygvis/eda/cli/__init__.py | 53 ++++++-- trygvis/eda/cli/add_to_db.py | 4 +- trygvis/eda/cli/db_stats.py | 4 +- trygvis/eda/cli/digikey_download_for_schematic.py | 9 +- trygvis/eda/cli/eda_rdf.py | 157 ++++++++++++++++------ trygvis/eda/cli/init.py | 29 ++++ trygvis/eda/cli/make_bom.py | 4 +- 9 files changed, 196 insertions(+), 66 deletions(-) create mode 100755 trygvis/eda/cli/init.py diff --git a/.gitignore b/.gitignore index 70e9a43..a4f7607 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ env *.db +.eda-rdf *.pyc digikey_cache diff --git a/requirement.txt b/requirement.txt index 2567238..7afb6ca 100644 --- a/requirement.txt +++ b/requirement.txt @@ -1,5 +1,6 @@ bsddb3==6.2.1 CacheControl==0.11.7 +configparser==3.5.0 html5lib==0.999999999 isodate==0.5.4 lockfile==0.12.2 diff --git a/trygvis/eda/cli/__init__.py b/trygvis/eda/cli/__init__.py index 8a4ce6f..f300f86 100644 --- a/trygvis/eda/cli/__init__.py +++ b/trygvis/eda/cli/__init__.py @@ -1,8 +1,9 @@ import sys import logging - from rdflib import store, ConjunctiveGraph, Graph, RDF, RDFS from rdflib.plugins.sparql import prepareQuery +import rdflib.plugins.stores.sparqlstore as sparqlstore +import configparser from ..digikey import rdf as digikey_rdf from ..kicad import rdf as kicad_rdf @@ -12,7 +13,7 @@ class CliException(Exception): pass -def init(): +def initialize(): logging.basicConfig(level=logging.DEBUG) pass @@ -27,16 +28,27 @@ def do_exit(msg=None): sys.exit(msg) -def with_database(path, tx): - g = ConjunctiveGraph('Sleepycat') - rt = g.open(path, create=False) - if rt == store.NO_STORE: - info("Creating store in %s" % path) - g.open(path, create=True) - elif rt != store.VALID_STORE: - raise CliException("The database is corrupt: %s" % path) +def with_database(tx): + config = read_config() + + db_type = config['db']['type'] + if db_type is None or db_type == 'local': + path = ".eda-rdf/db" + g = ConjunctiveGraph('Sleepycat') + rt = g.open(path, create=False) + if rt == store.NO_STORE: + info("Creating store in %s" % path) + g.open(path, create=True) + elif rt != store.VALID_STORE: + raise CliException("The database is corrupt: %s" % path) + elif db_type == 'sparql': + g = sparqlstore.SPARQLStore() + g.open(config["db"]["url"]) + else: + raise CliException("Unknown db.type: %s" % db_type) try: + print("g=%s" % g) tx(g) finally: g.close() @@ -70,7 +82,22 @@ _initNs = { "kicad-type": kicad_rdf.KICAD_TYPE} -def sparql(g, query, init_bindings=None): - q = prepareQuery(query, initNs=_initNs) +def sparql(g: Graph, query: str, init_bindings=None): + + if isinstance(g, sparqlstore.SPARQLStore): + return g.query(query, initNs=_initNs, initBindings=init_bindings) + else: + q = prepareQuery(query, initNs=_initNs) + return g.query(q, initBindings=init_bindings) + + +def write_config(config: configparser.ConfigParser): + with open('.eda-rdf/config.ini', 'w') as configfile: + config.write(configfile) + - return g.query(q, initBindings=init_bindings) +def read_config(): + with open('.eda-rdf/config.ini', 'r') as f: + config = configparser.ConfigParser() + config.read_file(f) + return config diff --git a/trygvis/eda/cli/add_to_db.py b/trygvis/eda/cli/add_to_db.py index e3b07c1..84f8d74 100644 --- a/trygvis/eda/cli/add_to_db.py +++ b/trygvis/eda/cli/add_to_db.py @@ -1,7 +1,7 @@ import trygvis.eda.cli as cli -def run(files, path, args): +def run(files, args): def load(g): s = 0 for f in files: @@ -15,4 +15,4 @@ def run(files, path, args): cli.info("Done. Loaded %d tuples" % s) - cli.with_database(path, load) + cli.with_database(load) diff --git a/trygvis/eda/cli/db_stats.py b/trygvis/eda/cli/db_stats.py index 5ee99ac..5261ed1 100755 --- a/trygvis/eda/cli/db_stats.py +++ b/trygvis/eda/cli/db_stats.py @@ -1,7 +1,7 @@ from trygvis.eda import cli -def run(db_path): +def run(): def db_stats(g): res = cli.sparql(g, """ SELECT ?schematic ?label @@ -37,4 +37,4 @@ ORDER BY ?dk_part_number for row in res: cli.info(" %-30s: %s" % (row.dk_part_number, row.label)) - cli.with_database(db_path, db_stats) + cli.with_database(db_stats) diff --git a/trygvis/eda/cli/digikey_download_for_schematic.py b/trygvis/eda/cli/digikey_download_for_schematic.py index ecfbc9e..0c21b3a 100755 --- a/trygvis/eda/cli/digikey_download_for_schematic.py +++ b/trygvis/eda/cli/digikey_download_for_schematic.py @@ -1,4 +1,5 @@ from rdflib.plugins.sparql import prepareQuery +import rdflib import rdflib.term from trygvis.eda import cli, write_graph @@ -7,8 +8,8 @@ from trygvis.eda.digikey import rdf as digikey_rdf from trygvis.eda.kicad import rdf as kicad_rdf initNs = { - "rdf": RDF, - "rdfs": RDFS, + "rdf": rdflib.RDF, + "rdfs": rdflib.RDFS, "dk": digikey_rdf.DIGIKEY, "dk-attr-type": digikey_rdf.DIGIKEY_ATTRIBUTE_TYPE, "dk-attr-value": digikey_rdf.DIGIKEY_ATTRIBUTE_VALUE, @@ -128,6 +129,6 @@ ORDER BY ?digikey_pn # writeGraph(tmpG, 'ttl/' + filename) -def run(schematic_url, db_path, args): +def run(schematic_url, args): cli.info("Schematic: %s" % schematic_url) - cli.with_database(db_path, lambda g: work(schematic_url, g)) + cli.with_database(lambda g: work(schematic_url, g)) diff --git a/trygvis/eda/cli/eda_rdf.py b/trygvis/eda/cli/eda_rdf.py index 7bf0934..33018ec 100644 --- a/trygvis/eda/cli/eda_rdf.py +++ b/trygvis/eda/cli/eda_rdf.py @@ -3,44 +3,47 @@ import sys import trygvis.eda.cli as cli -def main(): - parser = argparse.ArgumentParser() +class CliCommand(object): + def __init__(self, key, description): + self.key = key + self.description = description + + +class AddToDb(CliCommand): + def __init__(self): + super().__init__("add-to-db", "Import RDF triplet file to the database") - subparsers = parser.add_subparsers(dest="cmd") + def run(self, argv): + p = argparse.ArgumentParser(prog=self.key, description=self.description) + p.add_argument("files", nargs='*') + args = p.parse_args(argv) - # kicad-* - p = subparsers.add_parser("kicad-bom-to-ttl") - p.add_argument("-o", "--output", required=False) - p.add_argument("-i", "--input", required=False) + from trygvis.eda.cli import add_to_db + add_to_db.run(args.files, args) - # db-* - p = subparsers.add_parser("add-to-db") - p.add_argument("-d", "--db", required=True) - p.add_argument("files", nargs='*') - p = subparsers.add_parser("db-stats") - p.add_argument("-d", "--db", required=True) +class DbStats(CliCommand): + def __init__(self): + super().__init__("db-stats", "Show some statistics about the data in the database") - # digikey-* - p = subparsers.add_parser("digikey-download-for-schematic") - p.add_argument("-d", "--db", required=True) - p.add_argument("--schematic", required=True) + def run(self, argv): + p = argparse.ArgumentParser(prog=self.key, description=self.description) + args = p.parse_args(argv) - p = subparsers.add_parser("digikey-download-attribute-types-for-category") - p.add_argument("-c", "--category", required=True) - p.add_argument("-s", "--sub-category", required=True) - p.add_argument("-o", "--output", required=False) + from trygvis.eda.cli import db_stats + db_stats.run() - # Other - p = subparsers.add_parser("make-bom") - p.add_argument("-d", "--db", required=True) - p.add_argument("--schematic", required=True) - args = parser.parse_args() +class KicadBomToTtl(CliCommand): + def __init__(self): + super().__init__("kicad-bom-to-ttl", "Create RDF triples from a KiCAD BOM.xml file") - cli.init() + def run(self, argv): + p = argparse.ArgumentParser(prog=self.key, description=self.description) + p.add_argument("-o", "--output", required=False) + p.add_argument("-i", "--input", required=False) + args = p.parse_args(argv) - if args.cmd == "kicad-bom-to-ttl": from trygvis.eda.cli import kicad_bom_to_ttl if args.input is not None: @@ -56,24 +59,92 @@ def main(): with src, dst: kicad_bom_to_ttl.run(src, dst, args) - elif args.cmd == "add-to-db": - from trygvis.eda.cli import add_to_db - - add_to_db.run(args.files, args.db, args) - elif args.cmd == "db-stats": - from trygvis.eda.cli import db_stats - db_stats.run(args.db) +class DigikeyDownloadForSchematic(CliCommand): + def __init__(self): + super().__init__("digikey-download-for-schematic", "Download missing data from digikey.com") - elif args.cmd == "make-bom": - from trygvis.eda.cli import make_bom - make_bom.run(args.schematic, args.db) + def run(self, argv): + p = argparse.ArgumentParser(prog=self.key, description=self.description) + p.add_argument("--schematic", required=True) + args = p.parse_args(argv) - elif args.cmd == "digikey-download-for-schematic": from trygvis.eda.cli import digikey_download_for_schematic - digikey_download_for_schematic.run(args.schematic, args.db, args) - elif args.cmd == "digikey-download-attribute-types-for-category": + digikey_download_for_schematic.run(args.schematic, args) + + +class DigikeyDownloadAttributeTypesForCategory(CliCommand): + def __init__(self): + super().__init__("digikey-download-attribute-types-for-category", "Download the attribute types for a category from digikey.com") + + def run(self, argv): + p = argparse.ArgumentParser(prog=self.key, description=self.description) + p.add_argument("-c", "--category", required=True) + p.add_argument("-s", "--sub-category", required=True) + p.add_argument("-o", "--output", required=False) + args = p.parse_args(argv) + from trygvis.eda.cli import digikey_download_attribute_types_for_category digikey_download_attribute_types_for_category.run(args.category, args.sub_category, args.output, args) - else: - sys.exit("Unknown command: %s" % args.cmd) + +class MakeBom(CliCommand): + def __init__(self): + super().__init__("make-bom", "Create a BOM for a project with all info for each part.") + + def run(self, argv): + p = argparse.ArgumentParser(prog=self.key, description=self.description) + p.add_argument("--schematic", required=True) + args = p.parse_args(argv) + + from trygvis.eda.cli import make_bom + make_bom.run(args.schematic) + + +class Init(CliCommand): + def __init__(self): + super().__init__("init", "Initialize a EDA-RFD database") + + def run(self, argv): + p = argparse.ArgumentParser(prog=self.key, description=self.description) + p.add_argument("--database-url", dest="database_url") + args = p.parse_args(argv) + + from trygvis.eda.cli import init + init.run(args) + + +def main(): + cli.initialize() + + commands = [ + AddToDb(), + Init(), + DbStats(), + MakeBom(), + KicadBomToTtl(), + DigikeyDownloadForSchematic(), + DigikeyDownloadAttributeTypesForCategory(), + ] + + parser = argparse.ArgumentParser( + description='EDA RFD tools', + usage="""eda-rdf [] + +Available commands + +""" + "\n".join([" %-50s %s" % (cmd.key, cmd.description) for cmd in commands])) + parser.add_argument('command', help='Subcommand to run', nargs='?') + args = parser.parse_args(sys.argv[1:2]) + cmd_args = sys.argv[2:] + + if args.command is None: + print(parser.usage) + print() + sys.exit(1) + + for cmd in commands: + if cmd.key == args.command: + cmd.run(cmd_args) + return + + print("Unknown command: %s" % args.command) diff --git a/trygvis/eda/cli/init.py b/trygvis/eda/cli/init.py new file mode 100755 index 0000000..1ea9079 --- /dev/null +++ b/trygvis/eda/cli/init.py @@ -0,0 +1,29 @@ +from os.path import isfile, exists, isdir + +from trygvis.eda import cli +import configparser + +import os +import sys + + +def run(args): + try: + os.mkdir('.eda-rdf') + except FileExistsError: + if isdir('.eda-rdf'): + cli.info('Already initialized') + else: + cli.info('.eda-rdf exists, but is not a directory') + sys.exit(1) + + config = configparser.ConfigParser() + config['db'] = { + "type": "local" + } + + if args.database_url is not None: + config["db"]["type"] = "sparql" + config["db"]["url"] = args.database_url + + cli.write_config(config) diff --git a/trygvis/eda/cli/make_bom.py b/trygvis/eda/cli/make_bom.py index eae7043..fcdbe99 100755 --- a/trygvis/eda/cli/make_bom.py +++ b/trygvis/eda/cli/make_bom.py @@ -21,8 +21,8 @@ class Component(object): self.fields[field_name] = field_value -def run(schematic_url, db_path): - cli.with_database(db_path, lambda g: work(schematic_url, g)) +def run(schematic_url): + cli.with_database(lambda g: work(schematic_url, g)) def work(schematic_url, g): -- cgit v1.2.3