Added KiBoM and InteractiveHtmlBoM support
This commit is contained in:
parent
85acaadf26
commit
438142dabd
|
|
@ -108,7 +108,7 @@ class CfgYamlReader(CfgReader):
|
|||
if mapping['required'](cfg_options):
|
||||
|
||||
cfg_val = self._get_required(cfg_options, key)
|
||||
elif key in cfg_options:
|
||||
elif not(cfg_options is None) and key in cfg_options:
|
||||
# not required but given anyway
|
||||
cfg_val = cfg_options[key]
|
||||
else:
|
||||
|
|
@ -337,7 +337,7 @@ class CfgYamlReader(CfgReader):
|
|||
},
|
||||
{
|
||||
'key': 'format',
|
||||
'types': ['position'],
|
||||
'types': ['position','kibom'],
|
||||
'to': 'format',
|
||||
'required': lambda opts: True,
|
||||
},
|
||||
|
|
@ -358,7 +358,19 @@ class CfgYamlReader(CfgReader):
|
|||
'types': ['position'],
|
||||
'to': 'only_smd',
|
||||
'required': lambda opts: True,
|
||||
}
|
||||
},
|
||||
{
|
||||
'key': 'blacklist',
|
||||
'types': ['ibom'],
|
||||
'to': 'blacklist',
|
||||
'required': lambda opts: False,
|
||||
},
|
||||
{
|
||||
'key': 'name_format',
|
||||
'types': ['ibom'],
|
||||
'to': 'name_format',
|
||||
'required': lambda opts: False,
|
||||
},
|
||||
]
|
||||
|
||||
po = PC.OutputOptions(otype)
|
||||
|
|
@ -444,13 +456,16 @@ class CfgYamlReader(CfgReader):
|
|||
raise YamlError("Output needs a type")
|
||||
|
||||
if otype not in ['gerber', 'ps', 'hpgl', 'dxf', 'pdf', 'svg',
|
||||
'gerb_drill', 'excellon', 'position']:
|
||||
'gerb_drill', 'excellon', 'position',
|
||||
'kibom', 'ibom']:
|
||||
raise YamlError("Unknown output type: {}".format(otype))
|
||||
|
||||
try:
|
||||
options = o_obj['options']
|
||||
except KeyError:
|
||||
raise YamlError("Output need to have options specified")
|
||||
if otype != 'ibom':
|
||||
raise YamlError("Output need to have options specified")
|
||||
options = None
|
||||
|
||||
logger.debug("Parsing output options for {} ({})".format(name, otype))
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import os
|
|||
from sys import exit
|
||||
import operator
|
||||
from shutil import which
|
||||
from subprocess import call, run, PIPE
|
||||
from subprocess import call, run, PIPE, check_output, CalledProcessError, STDOUT
|
||||
import logging
|
||||
from distutils.version import StrictVersion
|
||||
import re
|
||||
|
|
@ -102,6 +102,8 @@ class Plotter(object):
|
|||
self._do_drill_plot(board, pc, op)
|
||||
elif self._output_is_position(op):
|
||||
self._do_position_plot(board, pc, op)
|
||||
elif self._output_is_bom(op):
|
||||
self._do_bom(board, pc, op, brd_file)
|
||||
else:
|
||||
raise PlotError("Don't know how to plot type {}"
|
||||
.format(op.options.type))
|
||||
|
|
@ -218,6 +220,12 @@ class Plotter(object):
|
|||
def _output_is_position(self, output):
|
||||
return output.options.type == PCfg.OutputOptions.POSITION
|
||||
|
||||
def _output_is_bom(self, output):
|
||||
return output.options.type in [
|
||||
PCfg.OutputOptions.KIBOM,
|
||||
PCfg.OutputOptions.IBOM,
|
||||
]
|
||||
|
||||
def _get_layer_plot_format(self, output):
|
||||
"""
|
||||
Gets the Pcbnew plot format for a given KiPlot output type
|
||||
|
|
@ -528,6 +536,59 @@ class Plotter(object):
|
|||
else:
|
||||
raise PlotError("Format is invalid: {}".format(to.format))
|
||||
|
||||
def _do_bom(self, board, plot_ctrl, output, brd_file):
|
||||
if output.options.type == 'kibom':
|
||||
self._do_kibom(board, plot_ctrl, output, brd_file)
|
||||
else:
|
||||
self._do_ibom(board, plot_ctrl, output, brd_file)
|
||||
|
||||
def _do_kibom(self, board, plot_ctrl, output, brd_file):
|
||||
if which('KiBOM_CLI.py') is None:
|
||||
logger.error('No `KiBOM_CLI.py` command found.\n'
|
||||
'Please install it, visit: https://github.com/INTI-CMNB/KiBoM')
|
||||
exit(misc.MISSING_TOOL)
|
||||
to = output.options.type_options
|
||||
format = to.format.lower()
|
||||
outdir = plot_ctrl.GetPlotOptions().GetOutputDirectory()
|
||||
if not os.path.exists(outdir):
|
||||
os.makedirs(outdir)
|
||||
prj = os.path.splitext(os.path.relpath(brd_file))[0]
|
||||
logger.debug('Doing BoM, format '+format+' prj: '+prj)
|
||||
cmd = [ 'KiBOM_CLI.py', prj+'.xml', os.path.join(outdir, prj)+'.'+format ]
|
||||
logger.debug('Running: '+str(cmd))
|
||||
try:
|
||||
check_output(cmd, stderr=STDOUT)
|
||||
except CalledProcessError as e:
|
||||
logger.error('Failed to create BoM, error %d', e.returncode)
|
||||
exit(misc.BOM_ERROR)
|
||||
|
||||
def _do_ibom(self, board, plot_ctrl, output, brd_file):
|
||||
if which('generate_interactive_bom.py') is None:
|
||||
logger.error('No `generate_interactive_bom.py` command found.\n'
|
||||
'Please install it, visit: https://github.com/INTI-CMNB/InteractiveHtmlBom')
|
||||
exit(misc.MISSING_TOOL)
|
||||
outdir = plot_ctrl.GetPlotOptions().GetOutputDirectory()
|
||||
if not os.path.exists(outdir):
|
||||
os.makedirs(outdir)
|
||||
prj = os.path.splitext(os.path.relpath(brd_file))[0]
|
||||
logger.debug('Doing Interactive BoM, prj: '+prj)
|
||||
cmd = [ 'generate_interactive_bom.py', brd_file,
|
||||
'--dest-dir', outdir,
|
||||
'--no-browser', ]
|
||||
to = output.options.type_options
|
||||
if to.blacklist:
|
||||
cmd.append('--blacklist')
|
||||
cmd.append(to.blacklist)
|
||||
if to.name_format:
|
||||
cmd.append('--name-format')
|
||||
cmd.append(to.name_format)
|
||||
logger.debug('Running: '+str(cmd))
|
||||
try:
|
||||
check_output(cmd, stderr=STDOUT)
|
||||
except CalledProcessError as e:
|
||||
logger.error('Failed to create BoM, error %d', e.returncode)
|
||||
exit(misc.BOM_ERROR)
|
||||
|
||||
def _configure_gerber_opts(self, po, output):
|
||||
|
||||
# true if gerber
|
||||
|
|
@ -582,6 +643,14 @@ class Plotter(object):
|
|||
|
||||
assert(output.options.type == PCfg.OutputOptions.POSITION)
|
||||
|
||||
def _configure_kibom_opts(self, po, output):
|
||||
|
||||
assert(output.options.type == PCfg.OutputOptions.KIBOM)
|
||||
|
||||
def _configure_ibom_opts(self, po, output):
|
||||
|
||||
assert(output.options.type == PCfg.OutputOptions.IBOM)
|
||||
|
||||
def _configure_output_dir(self, plot_ctrl, output):
|
||||
|
||||
po = plot_ctrl.GetPlotOptions()
|
||||
|
|
@ -637,6 +706,10 @@ class Plotter(object):
|
|||
self._configure_hpgl_opts(po, output)
|
||||
elif output.options.type == PCfg.OutputOptions.POSITION:
|
||||
self._configure_position_opts(po, output)
|
||||
elif output.options.type == PCfg.OutputOptions.KIBOM:
|
||||
self._configure_kibom_opts(po, output)
|
||||
elif output.options.type == PCfg.OutputOptions.IBOM:
|
||||
self._configure_ibom_opts(po, output)
|
||||
|
||||
po.SetDrillMarksType(opts.drill_marks)
|
||||
|
||||
|
|
|
|||
|
|
@ -377,6 +377,25 @@ class PositionOptions(TypeOptions):
|
|||
return errs
|
||||
|
||||
|
||||
class KiBoMOptions(TypeOptions):
|
||||
|
||||
def __init__(self):
|
||||
self.format = None
|
||||
|
||||
def validate(self):
|
||||
errs = []
|
||||
if self.format not in ["HTML", "CSV"]:
|
||||
errs.append("Format must be either HTML or CSV")
|
||||
return errs
|
||||
|
||||
|
||||
class IBoMOptions(TypeOptions):
|
||||
|
||||
def __init__(self):
|
||||
self.blacklist = None
|
||||
self.name_format = None
|
||||
|
||||
|
||||
class OutputOptions(object):
|
||||
|
||||
GERBER = 'gerber'
|
||||
|
|
@ -389,6 +408,8 @@ class OutputOptions(object):
|
|||
EXCELLON = 'excellon'
|
||||
GERB_DRILL = 'gerb_drill'
|
||||
POSITION = 'position'
|
||||
KIBOM = 'kibom'
|
||||
IBOM = 'ibom'
|
||||
|
||||
def __init__(self, otype):
|
||||
self.type = otype
|
||||
|
|
@ -411,12 +432,16 @@ class OutputOptions(object):
|
|||
self.type_options = GerberDrillOptions()
|
||||
elif otype == self.POSITION:
|
||||
self.type_options = PositionOptions()
|
||||
elif otype == self.KIBOM:
|
||||
self.type_options = KiBoMOptions()
|
||||
elif otype == self.IBOM:
|
||||
self.type_options = IBoMOptions()
|
||||
else:
|
||||
self.type_options = None
|
||||
|
||||
def validate(self):
|
||||
|
||||
if self.type_options is None:
|
||||
if self.type_options is None and self.type != self.IBOM:
|
||||
return ["No type specific options found"]
|
||||
|
||||
return self.type_options.validate()
|
||||
|
|
|
|||
Loading…
Reference in New Issue