From 0958273a71dd19c2a90471a182ccc5b90b14e5b4 Mon Sep 17 00:00:00 2001 From: Trygve Laugstøl Date: Sat, 7 Jan 2017 14:00:46 +0100 Subject: Renaming 'schematic' to 'project'. Renaming 'kicad-bom-to-ttl' to 'kicad-import-project'. Renaming 'digikey-download-for-schematic' to 'digikey-download-for-project'. Splitting out the Export xml file code into its own module. init: putting project.url and project.file in config.ini. init: putting db.update-url in config.ini if given on the command line. kicad-import-project: by default, assume that the user want to update local database, optionally write the ttl file to disk. cli.write_graph: create any missing parent directories. --- trygvis/eda/cli/kicad_import_project.py | 173 ++++++++++++++++++++++++++++++++ 1 file changed, 173 insertions(+) create mode 100755 trygvis/eda/cli/kicad_import_project.py (limited to 'trygvis/eda/cli/kicad_import_project.py') diff --git a/trygvis/eda/cli/kicad_import_project.py b/trygvis/eda/cli/kicad_import_project.py new file mode 100755 index 0000000..288b7fc --- /dev/null +++ b/trygvis/eda/cli/kicad_import_project.py @@ -0,0 +1,173 @@ +import os.path +from operator import attrgetter +import itertools + +import rdflib +from rdflib import Literal, URIRef +from rdflib.namespace import RDF, RDFS + +# from ..kicad import rdf as kicad_rdf +from . import * +from ..kicad.export import * + + +class KicadImportProjectCommand(CliCommand): + def __init__(self): + super().__init__("kicad-import-project", "Import a KiCAD project") + + def run(self, argv): + p = argparse.ArgumentParser(prog=self.key, description=self.description) + p.add_argument("-o", "--output-dir", dest="output_dir", required=False) + p.add_argument("-i", "--input", required=False) + args = p.parse_args(argv) + + run(args) + + +def run(args): + config = read_config() + + if args.input is "-": + src = sys.stdin + else: + if args.input is None: + (filename, _) = os.path.splitext(config['project']['file']) + filename += '.xml' + else: + filename = args.input + + if not isfile(filename): + raise CliException("No such file: %s. Did you export the BOM?" % filename) + + src = open(filename, 'r') + + project_url = config['project']['url'] + + with src: + project = export_to_graph(src, project_url) + + debug('Loaded %s tuples' % len(project)) + + if args.output_dir is not None: + parent = args.output_dir + if not os.path.exists(parent): + os.mkdir(parent) + output_file = os.path.join(parent, "project.ttl") + with open(output_file, 'wb') as dst: + project.serialize(destination=dst, encoding='utf-8', format='turtle') + + def import_project(g): + for idx, t in enumerate(project.triples((None, None, None))): + g.add(t) + + with_database(import_project) + + +def export_to_graph(src: object, project_url: str) -> rdflib.Graph: + export = Export.from_xml_file(src) + + # print('components:') + # for c in export.components: + # print(c) + + # for name in export.component_fields(): + # cli.info(name) + + # cli.info('components:') + # fmt = '%2s%3s' + # cli.info(fmt % ('Ref', '')) + + components = sorted(export.components, key=attrgetter('ref')) + + component_count = 0 + part_count = 0 + has_part = 0 + has_digikey = 0 + + for cls, cs in itertools.groupby(components, key=attrgetter('ref_class')): + # cli.info('--- Class: %s ---' % cls) + cs = sorted(cs, key=attrgetter('value')) + for c in cs: + component_count += 1 + + value = str(c.value) + part = c.find_field('part') + digikey = c.find_field('digikey') + footprint = c.footprint + + if c.ref_class is not None: + ref_class = c.ref_class + ref_instance = c.ref_instance + else: + ref_class = c.ref + ref_instance = '' + + # cli.info(fmt % (ref_class, ref_instance)) + # cli.info(' Value: %s' % c.value.text) + # if c.footprint: + # cli.info(' Footprint: %s' % c.footprint) + + if part is not None: + if part != 'NA': + has_part += 1 if part is not None else 0 + part_count += 1 + + if digikey is not None: + has_digikey += 1 + else: + part = None + else: + part_count += 1 + part = 'MISSING' + + # if part is not None: + # cli.info(' Part: %s' % part) + # if digikey is not None: + # cli.info(' Digikey: %s' % digikey) + + # cli.info() + # cli.info('=== Summary ===') + # cli.info('Project URL: %s' % project_url) + # cli.info('Number of components: %d' % component_count) + # cli.info('Number of parts: %d' % part_count) + # cli.info('Assigned part: %d / %2.f%%' % (has_part, (has_part / part_count) * 100)) + # cli.info('Assigned digikey: %d / %2.f%%' % (has_digikey, (has_digikey / part_count) * 100)) + + g = create_graph(kicad=True) + + project = URIRef(project_url) + g.add((project, RDF.type, kicad_rdf.KICAD_TYPE.project)) + + # The components and fields could/should have been a BNodes. Their generated names are not very nice. + # TODO: try using a hash of the current value and put that under a special generated namespace. + # 'http://example.org/my-board' + ref='C10' => 'http://example.org/my-boardC10' + # hash('http://example.org/my-boardC10') => 123456 + # add_prefix(hash) => 'https://trygvis.io/purl/kicad/generated#123456' + footprints = set() + for c in export.components: + ns = rdflib.Namespace(project_url) + node = ns[c.ref] + g.add((project, kicad_rdf.KICAD.component, node)) + + g.add((node, RDF.type, kicad_rdf.KICAD_TYPE.schematic_component)) + g.add((node, RDFS.label, Literal(c.ref))) + g.add((node, kicad_rdf.KICAD.value, Literal(c.value.text))) + + footprint_uri = URIRef(kicad_rdf.KICAD_FOOTPRINT[quote_plus(c.footprint)]) + if not footprint_uri in footprints: + g.add((footprint_uri, RDF.type, kicad_rdf.KICAD_TYPE.footprint)) + g.add((footprint_uri, RDFS.label, Literal(c.footprint))) + footprints.add(footprint_uri) + + g.add((node, kicad_rdf.KICAD.footprint, footprint_uri)) + + for name, value in c.fields.items(): + f = ns['%s-%s' % (c.ref, name)] + g.add((node, kicad_rdf.KICAD.field, f)) + g.add((f, RDF.type, kicad_rdf.KICAD_TYPE.field)) + g.add((f, kicad_rdf.KICAD.field_name, Literal(name))) + g.add((f, kicad_rdf.KICAD.field_value, Literal(value))) + + # TODO: serialize the data from too + + return g -- cgit v1.2.3