Skip to content

Commit

Permalink
[Added][Ouput] Jobset, to run KiCad Jobsets
Browse files Browse the repository at this point in the history
  • Loading branch information
set-soft committed Feb 28, 2025
1 parent 8b37ffa commit a0dbe7e
Show file tree
Hide file tree
Showing 12 changed files with 490 additions and 38 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- IPC2581: Exports the PCB in IPC-2581 (IPC-DPMX) format (KiCad 9)
- export_3d: Exports the 3D model of the PCB in BREP, GLB, STL, STEP and
XAO (KiCad 9) (#783)
- jobset: Runs a KiCad jobset (KiCad 9)
- CLI:
- `--variant` to specify which variants will be generated (See #737)
- `--defs-from-project` allows using KiCad variables for the preprocessor
Expand Down
52 changes: 52 additions & 0 deletions docs/samples/generic_plot.kibot.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1934,6 +1934,58 @@ outputs:
variant: ''
# [string='C'] [B,C] Which implementation of the IPC-2581 standard will be generated
version: 'C'
# KiCad Jobset (batch execution):
# The outputs will be generated using the `dir` directory as base.
# This is provided just for convenience
- name: 'jobset_example'
comment: 'Generates outputs defined in a KiCad jobset file (.kicad_jobset).'
type: 'jobset'
dir: 'Example/jobset_dir'
options:
# [string|list(string)='_null'] Name of the filter to mark components as not fitted.
# Is a short-cut to use for simple cases where a variant is an overkill.
# Can be used to fine-tune a variant for a particular output that needs extra filtering done before the
# variant
dnf_filter: '_null'
# [boolean=true] Downloads missing 3D models from KiCad git.
# Only applies to models in KISYS3DMOD and KICAD6_3DMODEL_DIR.
# They are downloaded to a temporal directory and discarded.
# If you want to cache the downloaded files specify a directory using the
# KIBOT_3D_MODELS environment variable
download: true
# [boolean=true] In addition to try to download the 3D models from KiCad git also try to get
# them from LCSC database. In order to work you'll need to provide the LCSC
# part number. The field containing the LCSC part number is defined by the
# `field_lcsc_part` global variable
download_lcsc: true
# [string|list(string)='_null'] Name of the filter to exclude components from processing.
# Is a short-cut to use for simple cases where a variant is an overkill.
# Can be used to fine-tune a variant for a particular output that needs extra filtering done before the
# variant
exclude_filter: '_null'
# [string=''] Name of the KiCad jobset file you want to use. Should have `kicad_jobset` extension.
# Leave empty to look for a jobset with the same name as the project
jobset: ''
# [string='https://gitlab.com/kicad/libraries/kicad-packages3D/-/raw/master/'] Base URL for the KiCad 3D models
kicad_3d_url: 'https://gitlab.com/kicad/libraries/kicad-packages3D/-/raw/master/'
# [string=''] Text added to the end of the download URL.
# Can be used to pass variables to the GET request, i.e. ?VAR1=VAL1&VAR2=VAL2
kicad_3d_url_suffix: ''
# [boolean=false] Used to exclude 3D models for components with 'virtual' attribute
no_virtual: false
# [string|list(string)='_null'] Name of the filter to transform fields before applying other filters.
# Is a short-cut to use for simple cases where a variant is an overkill.
# Can be used to fine-tune a variant for a particular output that needs extra filtering done before the
# variant
pre_transform: '_null'
# [string=''] Output to be generated. When empty KiCad runs all possible outputs.
# Here the name can be obtained from the .kicad_jobset file, in JSON format.
# The `outputs` section contains all the defined outputs. Each output has an `id` use it here
run_output: ''
# [boolean=true] Stop generation when an error is detected
stop_on_error: true
# [string=''] Board variant to apply
variant: ''
# KiBoM (KiCad Bill of Materials):
# For more information: https://github.com/INTI-CMNB/KiBoM
# Note that this output is provided as a compatibility tool.
Expand Down
1 change: 1 addition & 0 deletions docs/source/Changelog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ Added
- IPC2581: Exports the PCB in IPC-2581 (IPC-DPMX) format (KiCad 9)
- export_3d: Exports the 3D model of the PCB in BREP, GLB, STL, STEP
and XAO (KiCad 9) (#783)
- jobset: Runs a KiCad jobset (KiCad 9)

- CLI:

Expand Down
42 changes: 42 additions & 0 deletions docs/source/configuration/outputs/JobSetOptions.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
.. _JobSetOptions:


JobSetOptions parameters
~~~~~~~~~~~~~~~~~~~~~~~~

- **download** :index:`: <pair: output - jobset - options; download>` [:ref:`boolean <boolean>`] (default: ``true``) Downloads missing 3D models from KiCad git.
Only applies to models in KISYS3DMOD and KICAD6_3DMODEL_DIR. |br|
They are downloaded to a temporal directory and discarded. |br|
If you want to cache the downloaded files specify a directory using the
KIBOT_3D_MODELS environment variable.
- **jobset** :index:`: <pair: output - jobset - options; jobset>` [:ref:`string <string>`] (default: ``''``) Name of the KiCad jobset file you want to use. Should have `kicad_jobset` extension.
Leave empty to look for a jobset with the same name as the project.
- **no_virtual** :index:`: <pair: output - jobset - options; no_virtual>` [:ref:`boolean <boolean>`] (default: ``false``) Used to exclude 3D models for components with 'virtual' attribute.
- **run_output** :index:`: <pair: output - jobset - options; run_output>` [:ref:`string <string>`] (default: ``''``) Output to be generated. When empty KiCad runs all possible outputs.
Here the name can be obtained from the .kicad_jobset file, in JSON format. |br|
The `outputs` section contains all the defined outputs. Each output has an `id` use it here.
- ``dnf_filter`` :index:`: <pair: output - jobset - options; dnf_filter>` [:ref:`string <string>` | :ref:`list(string) <list(string)>`] (default: ``'_null'``) Name of the filter to mark components as not fitted.
Is a short-cut to use for simple cases where a variant is an overkill. |br|
Can be used to fine-tune a variant for a particular output that needs extra filtering done before the
variant.

- ``download_lcsc`` :index:`: <pair: output - jobset - options; download_lcsc>` [:ref:`boolean <boolean>`] (default: ``true``) In addition to try to download the 3D models from KiCad git also try to get
them from LCSC database. In order to work you'll need to provide the LCSC
part number. The field containing the LCSC part number is defined by the
`field_lcsc_part` global variable.
- ``exclude_filter`` :index:`: <pair: output - jobset - options; exclude_filter>` [:ref:`string <string>` | :ref:`list(string) <list(string)>`] (default: ``'_null'``) Name of the filter to exclude components from processing.
Is a short-cut to use for simple cases where a variant is an overkill. |br|
Can be used to fine-tune a variant for a particular output that needs extra filtering done before the
variant.

- ``kicad_3d_url`` :index:`: <pair: output - jobset - options; kicad_3d_url>` [:ref:`string <string>`] (default: ``'https://gitlab.com/kicad/libraries/kicad-packages3D/-/raw/master/'``) Base URL for the KiCad 3D models.
- ``kicad_3d_url_suffix`` :index:`: <pair: output - jobset - options; kicad_3d_url_suffix>` [:ref:`string <string>`] (default: ``''``) Text added to the end of the download URL.
Can be used to pass variables to the GET request, i.e. ?VAR1=VAL1&VAR2=VAL2.
- ``pre_transform`` :index:`: <pair: output - jobset - options; pre_transform>` [:ref:`string <string>` | :ref:`list(string) <list(string)>`] (default: ``'_null'``) Name of the filter to transform fields before applying other filters.
Is a short-cut to use for simple cases where a variant is an overkill. |br|
Can be used to fine-tune a variant for a particular output that needs extra filtering done before the
variant.

- ``stop_on_error`` :index:`: <pair: output - jobset - options; stop_on_error>` [:ref:`boolean <boolean>`] (default: ``true``) Stop generation when an error is detected.
- ``variant`` :index:`: <pair: output - jobset - options; variant>` [:ref:`string <string>`] (default: ``''``) Board variant to apply.

48 changes: 48 additions & 0 deletions docs/source/configuration/outputs/jobset.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
.. Automatically generated by KiBot, please don't edit this file
.. index::
pair: KiCad Jobset (batch execution); jobset

KiCad Jobset (batch execution)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Generates outputs defined in a KiCad jobset file (.kicad_jobset).
The outputs will be generated using the `dir` directory as base. |br|
This is provided just for convenience

Type: ``jobset``


Parameters:

- **comment** :index:`: <pair: output - jobset; comment>` [:ref:`string <string>`] (default: ``''``) A comment for documentation purposes. It helps to identify the output.
- **dir** :index:`: <pair: output - jobset; dir>` [:ref:`string <string>`] (default: ``'./'``) Output directory for the generated files.
If it starts with `+` the rest is concatenated to the default dir.
- **name** :index:`: <pair: output - jobset; name>` [:ref:`string <string>`] (default: ``''``) Used to identify this particular output definition.
Avoid using `_` as first character. These names are reserved for KiBot.
- **options** :index:`: <pair: output - jobset; options>` [:ref:`JobSetOptions parameters <JobSetOptions>`] [:ref:`dict <dict>`] (default: empty dict, default values used) Options for the `jobset` output.
- **type** :index:`: <pair: output - jobset; type>` 'jobset'
- ``category`` :index:`: <pair: output - jobset; category>` [:ref:`string <string>` | :ref:`list(string) <list(string)>`] (default: ``''``) [:ref:`comma separated <comma_sep>`] The category for this output. If not specified an internally defined
category is used. |br|
Categories looks like file system paths, i.e. **PCB/fabrication/gerber**. |br|
Using '.' or './' as a category puts the file at the root. |br|
The categories are currently used for `navigate_results` and `navigate_results_rb`.

- ``disable_run_by_default`` :index:`: <pair: output - jobset; disable_run_by_default>` [:ref:`string <string>` | :ref:`boolean <boolean>`] (default: ``''``) Use it to disable the `run_by_default` status of other output.
Useful when this output extends another and you don't want to generate the original. |br|
Use the boolean true value to disable the output you are extending.
- ``extends`` :index:`: <pair: output - jobset; extends>` [:ref:`string <string>`] (default: ``''``) Copy the `options` section from the indicated output.
Used to inherit options from another output of the same type.
- ``groups`` :index:`: <pair: output - jobset; groups>` [:ref:`string <string>` | :ref:`list(string) <list(string)>`] (default: ``''``) One or more groups to add this output. In order to catch typos
we recommend to add outputs only to existing groups. You can create an empty group if
needed.

- ``output_id`` :index:`: <pair: output - jobset; output_id>` [:ref:`string <string>`] (default: ``''``) Text to use for the %I expansion content. To differentiate variations of this output.
- ``priority`` :index:`: <pair: output - jobset; priority>` [:ref:`number <number>`] (default: ``50``) (range: 0 to 100) Priority for this output. High priority outputs are created first.
Internally we use 10 for low priority, 90 for high priority and 50 for most outputs.
- ``run_by_default`` :index:`: <pair: output - jobset; run_by_default>` [:ref:`boolean <boolean>`] (default: ``true``) When enabled this output will be created when no specific outputs are requested.

.. toctree::
:caption: Used dicts

JobSetOptions
1 change: 1 addition & 0 deletions docs/source/configuration/sup_outputs.rst
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ Notes:
outputs/ibom
outputs/info
outputs/ipc2581
outputs/jobset
outputs/kibom
outputs/kicanvas
outputs/kicost
Expand Down
28 changes: 24 additions & 4 deletions kibot/out_base_3d.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,12 @@
WIDTHS_5 = [5, 10, 8.5, 10, 8.5, 10, 8.5, 10, 14.5, 10, 5]


def abs_path_model(data, replace):
""" Make sure the 3D model uses an absolute path.
Used for temporal files create at /tmp """
return os.path.abspath(replace)


def do_expand_env(fname, used_extra, extra_debug, lib_nickname):
# Is it using ALIAS:xxxxx?
force_used_extra = False
Expand All @@ -81,9 +87,13 @@ def do_expand_env(fname, used_extra, extra_debug, lib_nickname):
full_name = KiConf.expand_env(fname, used_extra, ref_dir=GS.pcb_dir)
if extra_debug:
logger.debug("- Expanded {} -> {}".format(fname, full_name))
if os.path.isfile(full_name) or ':' not in fname or GS.global_disable_3d_alias_as_env:
if os.path.isfile(full_name):
return full_name
if ':' not in fname or GS.global_disable_3d_alias_as_env:
# Try using the current working dir
full_name_cwd = KiConf.expand_env(fname, used_extra, ref_dir=os.getcwd())
if os.path.isfile(full_name_cwd):
# Was relative to cwd, not all KiCad versions supports it, patch the model
full_name = full_name_cwd
force_used_extra = True
else:
Expand Down Expand Up @@ -541,7 +551,7 @@ def list_models(self, even_missing=False):
models.add(full_name)
return list(models)

def filter_components(self, highlight=None, force_wrl=False):
def filter_components(self, highlight=None, force_wrl=False, also_sch=False):
if not self._comps:
# No filters, but we need to apply some stuff
all_comps = None
Expand All @@ -568,8 +578,18 @@ def filter_components(self, highlight=None, force_wrl=False):
return ret
return GS.pcb_file
self.filter_pcb_components(do_3D=True, do_2D=True, highlight=highlight)
self.download_models(force_wrl=force_wrl, all_comps=self._comps)
fname = self.save_tmp_board()
if also_sch:
self.download_models(force_wrl=force_wrl, all_comps=self._comps, rename_function=abs_path_model,
rename_filter='*')
fname, pcb_dir = self.save_tmp_dir_board('3D')
replaced_images = self.sch_replace_images(GS.sch)
GS.sch.save_variant(pcb_dir)
if replaced_images:
self.sch_restore_images(GS.sch)
self._files_to_remove.append(pcb_dir)
else:
self.download_models(force_wrl=force_wrl, all_comps=self._comps)
fname = self.save_tmp_board()
self.unfilter_pcb_components(do_3D=True, do_2D=True)
return fname

Expand Down
83 changes: 83 additions & 0 deletions kibot/out_jobset.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2025 Salvador E. Tropea
# Copyright (c) 2025 Instituto Nacional de Tecnología Industrial
# License: AGPL-3.0
# Project: KiBot (formerly KiPlot)
import os
import re
from .misc import MISSING_FILES, MISSING_TOOL
from .kiplot import run_command
from .gs import GS
from .out_base_3d import Base3DOptions, Base3D
from .macros import macros, document, output_class # noqa: F401
from . import log

logger = log.get_logger()


class JobSetOptions(Base3DOptions):
def __init__(self):
with document:
self.jobset = ''
""" *Name of the KiCad jobset file you want to use. Should have `kicad_jobset` extension.
Leave empty to look for a jobset with the same name as the project """
self.run_output = ''
""" *Output to be generated. When empty KiCad runs all possible outputs.
Here the name can be obtained from the .kicad_jobset file, in JSON format.
The `outputs` section contains all the defined outputs. Each output has an `id` use it here """
self.stop_on_error = True
""" Stop generation when an error is detected """
super().__init__()

def run(self, output):
if not GS.ki9:
GS.exit_with_error("`jobset` needs KiCad 9+", MISSING_TOOL)
if not GS.pro_file:
GS.exit_with_error("Missing project file, must be available in order to run a jobset", MISSING_FILES)
jobset_file = self.jobset if self.jobset else GS.pro_file.replace('.kicad_pro', '.kicad_jobset')
if not os.path.isfile(jobset_file):
GS.exit_with_error(f"Missing jobset file `{jobset_file}`", MISSING_FILES)
super().run(output)
# Base command with overwrite
cmd = ['kicad-cli', 'jobset', 'run', '--file', os.path.abspath(jobset_file)]
if self.run_output:
cmd.extend(['--output', self.run_output])
if self.stop_on_error:
cmd.append('--stop-on-error')
# The board
board_name = self.filter_components(also_sch=True)
cmd.append(board_name.replace('.kicad_pcb', '.kicad_pro'))
res = run_command(cmd, change_to=output)
for j in re.findall(r'\| Running job \d+, (.*)', res):
logger.info(' - '+j)
self.remove_temporals()


@output_class
class JobSet(Base3D):
""" KiCad Jobset (batch execution)
Generates outputs defined in a KiCad jobset file (.kicad_jobset).
The outputs will be generated using the `dir` directory as base.
This is provided just for convenience """
def __init__(self):
super().__init__()
with document:
self.options = JobSetOptions
""" *[dict={}] Options for the `jobset` output """
# We need a full project
self._both_related = True

@staticmethod
def get_conf_examples(name, layers):
if not GS.ki9:
return None
jobfile = GS.pro_file.replace('.kicad_pro', '.kicad_jobset')
if not os.path.isfile(jobfile):
return None
gb = {}
gb['name'] = 'basic_'+name
gb['comment'] = 'Run KiCad jobset'
gb['type'] = name
gb['dir'] = 'Jobset'
gb['options'] = {'jobset': jobfile}
return [gb]
5 changes: 5 additions & 0 deletions tests/GUI/cfg_out/0003.kibot.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,11 @@ outputs:
comment: Exports the PCB in the Digital Product Model Exchange IPC format
options:
output: output.ipc2581.options.dict
- name: output.jobset
type: jobset
comment: Generates outputs defined in a KiCad jobset file (.kicad_jobset)
options:
jobset: output.jobset.options.dict
- name: output.kibom
type: kibom
comment: Used to generate the BoM in HTML or CSV format using the KiBoM plug-in
Expand Down
Loading

0 comments on commit a0dbe7e

Please sign in to comment.