[Added] Support for internal imports

- A mechanism to implement templates
- Also fixed some groups import issues
This commit is contained in:
Salvador E. Tropea 2023-01-04 11:39:48 -03:00
parent 17aacf8daf
commit 5a5967c6b3
9 changed files with 240 additions and 146 deletions

View File

@ -6,7 +6,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [1.5.2] - Unreleased
### Added
- Support for `groups` of `outputs`
- General:
- Support for `groups` of `outputs`
- Internal templates import
- New output:
- `vrml` export the 3D model in Virtual Reality Modeling Language (#349)
- Plot related outputs and PCB_Print:

132
README.md
View File

@ -36,6 +36,7 @@
* [Installation on other targets](#installation-on-other-targets)
* [Configuration](#configuration)
* [Quick start](#quick-start)
* [Section order](#section-order)
* [The header](#the-header)
* [The *preflight* section](#the-preflight-section)
* [Supported *preflight* options](#supported-preflight-options)
@ -64,9 +65,9 @@
* [Supported outputs](#supported-outputs)
* [Consolidating BoMs](#consolidating-boms)
* [Importing outputs from another file](#importing-outputs-from-another-file)
* [Importing other stuff from another file](#importing-other-stuff-from-another-file)
* [Using other output as base for a new one](#using-other-output-as-base-for-a-new-one)
* [Grouping outputs](#grouping-outputs)
* [Importing filters and variants from another file](#importing-filters-and-variants-from-another-file)
* [Doing YAML substitution or preprocessing](#doing-yaml-substitution-or-preprocessing)
* [Usage](#usage)
* [Usage for CI/CD](#usage-for-cicd)
@ -368,7 +369,7 @@ The order in which they are declared is not relevant, they are interpreted in th
- `kiplot`/`kibot` see [The header](#the-header)
- `import` see [Importing outputs from another file](#importing-outputs-from-another-file) and
[Importing filters and variants from another file](#importing-filters-and-variants-from-another-file)
[Importing filters and variants from another file](#importing-other-stuff-from-another-file)
- `global` see [Default global options](#default-global-options)
- `filters` see [Filters and variants](#filters-and-variants)
- `variants` see [Filters and variants](#filters-and-variants)
@ -4594,6 +4595,70 @@ import:
This will import all the outputs from the listed files.
#### Importing other stuff from another file
This is a more complex case of the previous [Importing outputs from another file](#importing-outputs-from-another-file).
In this case you must use the more general syntax:
```yaml
import:
- file: FILE_CONTAINING_THE_YAML_DEFINITIONS
outputs: LIST_OF_OUTPUTS
preflights: LIST_OF_PREFLIGHTS
filters: LIST_OF_FILTERS
variants: LIST_OF_VARIANTS
global: LIST_OF_GLOBALS
groups: LIST_OF_GROUPS
```
This syntax is flexible. If you don't define which `outputs`, `preflights`, `filters`, `variants`, `global` and/or `groups` all will be imported.
So you can just omit them, like this:
```yaml
import:
- file: FILE_CONTAINING_THE_YAML_DEFINITIONS
```
The `LIST_OF_items` can be a YAML list or just one string. Here is an example:
```yaml
import:
- file: FILE_CONTAINING_THE_YAML_DEFINITIONS
outputs: one_name
filters: ['name1', 'name2']
```
This will import the `one_name` output and the `name1` and `name2` filters. As `variants` is omitted, all variants will be imported.
The same applies to other things like globals and groups.
You can also use the `all` and `none` special names, like this:
```yaml
import:
- file: FILE_CONTAINING_THE_YAML_DEFINITIONS
outputs: all
filters: all
variants: none
global: none
```
This will import all outputs and filters, but not variants or globals.
Also note that imported globals has more precedence than the ones defined in the same file.
If you want to give more priority to the local values use:
```yaml
kibot:
version: 1
imported_global_has_less_priority: true
import:
...
```
Another important detail is that global options that are lists gets the values merged.
The last set of values found is inserted at the beginning of the list.
You can collect filters for all the imported global sections.
#### Using other output as base for a new one
If you need to define an output that is similar to another, and you want to avoid copying the options from the former, you can *extend* an output.
@ -4691,69 +4756,6 @@ Groups can be imported from another YAML file.
Avoid naming groups using `_` as first character. These names are reserved for KiBot.
#### Importing filters and variants from another file
This is a more complex case of the previous [Importing outputs from another file](#importing-outputs-from-another-file).
In this case you must use the more general syntax:
```yaml
import:
- file: FILE_CONTAINING_THE_YAML_DEFINITIONS
outputs: LIST_OF_OUTPUTS
preflights: LIST_OF_PREFLIGHTS
filters: LIST_OF_FILTERS
variants: LIST_OF_VARIANTS
global: LIST_OF_GLOBALS
groups: LIST_OF_GROUPS
```
This syntax is flexible. If you don't define which `outputs`, `preflights`, `filters`, `variants`, `global` and/or `groups` all will be imported.
So you can just omit them, like this:
```yaml
import:
- file: FILE_CONTAINING_THE_YAML_DEFINITIONS
```
The `LIST_OF_items` can be a YAML list or just one string. Here is an example:
```yaml
import:
- file: FILE_CONTAINING_THE_YAML_DEFINITIONS
outputs: one_name
filters: ['name1', 'name2']
```
This will import the `one_name` output and the `name1` and `name2` filters. As `variants` is omitted, all variants will be imported.
The same applies to other things like globals and groups.
You can also use the `all` and `none` special names, like this:
```yaml
import:
- file: FILE_CONTAINING_THE_YAML_DEFINITIONS
outputs: all
filters: all
variants: none
global: none
```
This will import all outputs and filters, but not variants or globals.
Also note that imported globals has more precedence than the ones defined in the same file.
If you want to give more priority to the local values use:
```
kibot:
version: 1
imported_global_has_less_priority: true
import:
...
```
Another important detail is that global options that are lists gets the values merged.
The last set of values found is inserted at the beginning of the list.
You can collect filters for all the imported global sections.
### Doing YAML substitution or preprocessing
Sometimes you could want to change values in the YAML depending on external stuff,

View File

@ -35,6 +35,7 @@
* [Installation on other targets](#installation-on-other-targets)
* [Configuration](#configuration)
* [Quick start](#quick-start)
* [Section order](#section-order)
* [The header](#the-header)
* [The *preflight* section](#the-preflight-section)
* [Supported *preflight* options](#supported-preflight-options)
@ -63,9 +64,9 @@
* [Supported outputs](#supported-outputs)
* [Consolidating BoMs](#consolidating-boms)
* [Importing outputs from another file](#importing-outputs-from-another-file)
* [Importing other stuff from another file](#importing-other-stuff-from-another-file)
* [Using other output as base for a new one](#using-other-output-as-base-for-a-new-one)
* [Grouping outputs](#grouping-outputs)
* [Importing filters and variants from another file](#importing-filters-and-variants-from-another-file)
* [Doing YAML substitution or preprocessing](#doing-yaml-substitution-or-preprocessing)
* [Usage](#usage)
* [Usage for CI/CD](#usage-for-cicd)
@ -267,7 +268,7 @@ The order in which they are declared is not relevant, they are interpreted in th
- `kiplot`/`kibot` see [The header](#the-header)
- `import` see [Importing outputs from another file](#importing-outputs-from-another-file) and
[Importing filters and variants from another file](#importing-filters-and-variants-from-another-file)
[Importing filters and variants from another file](#importing-other-stuff-from-another-file)
- `global` see [Default global options](#default-global-options)
- `filters` see [Filters and variants](#filters-and-variants)
- `variants` see [Filters and variants](#filters-and-variants)
@ -1177,6 +1178,70 @@ import:
This will import all the outputs from the listed files.
#### Importing other stuff from another file
This is a more complex case of the previous [Importing outputs from another file](#importing-outputs-from-another-file).
In this case you must use the more general syntax:
```yaml
import:
- file: FILE_CONTAINING_THE_YAML_DEFINITIONS
outputs: LIST_OF_OUTPUTS
preflights: LIST_OF_PREFLIGHTS
filters: LIST_OF_FILTERS
variants: LIST_OF_VARIANTS
global: LIST_OF_GLOBALS
groups: LIST_OF_GROUPS
```
This syntax is flexible. If you don't define which `outputs`, `preflights`, `filters`, `variants`, `global` and/or `groups` all will be imported.
So you can just omit them, like this:
```yaml
import:
- file: FILE_CONTAINING_THE_YAML_DEFINITIONS
```
The `LIST_OF_items` can be a YAML list or just one string. Here is an example:
```yaml
import:
- file: FILE_CONTAINING_THE_YAML_DEFINITIONS
outputs: one_name
filters: ['name1', 'name2']
```
This will import the `one_name` output and the `name1` and `name2` filters. As `variants` is omitted, all variants will be imported.
The same applies to other things like globals and groups.
You can also use the `all` and `none` special names, like this:
```yaml
import:
- file: FILE_CONTAINING_THE_YAML_DEFINITIONS
outputs: all
filters: all
variants: none
global: none
```
This will import all outputs and filters, but not variants or globals.
Also note that imported globals has more precedence than the ones defined in the same file.
If you want to give more priority to the local values use:
```yaml
kibot:
version: 1
imported_global_has_less_priority: true
import:
...
```
Another important detail is that global options that are lists gets the values merged.
The last set of values found is inserted at the beginning of the list.
You can collect filters for all the imported global sections.
#### Using other output as base for a new one
If you need to define an output that is similar to another, and you want to avoid copying the options from the former, you can *extend* an output.
@ -1274,69 +1339,6 @@ Groups can be imported from another YAML file.
Avoid naming groups using `_` as first character. These names are reserved for KiBot.
#### Importing filters and variants from another file
This is a more complex case of the previous [Importing outputs from another file](#importing-outputs-from-another-file).
In this case you must use the more general syntax:
```yaml
import:
- file: FILE_CONTAINING_THE_YAML_DEFINITIONS
outputs: LIST_OF_OUTPUTS
preflights: LIST_OF_PREFLIGHTS
filters: LIST_OF_FILTERS
variants: LIST_OF_VARIANTS
global: LIST_OF_GLOBALS
groups: LIST_OF_GROUPS
```
This syntax is flexible. If you don't define which `outputs`, `preflights`, `filters`, `variants`, `global` and/or `groups` all will be imported.
So you can just omit them, like this:
```yaml
import:
- file: FILE_CONTAINING_THE_YAML_DEFINITIONS
```
The `LIST_OF_items` can be a YAML list or just one string. Here is an example:
```yaml
import:
- file: FILE_CONTAINING_THE_YAML_DEFINITIONS
outputs: one_name
filters: ['name1', 'name2']
```
This will import the `one_name` output and the `name1` and `name2` filters. As `variants` is omitted, all variants will be imported.
The same applies to other things like globals and groups.
You can also use the `all` and `none` special names, like this:
```yaml
import:
- file: FILE_CONTAINING_THE_YAML_DEFINITIONS
outputs: all
filters: all
variants: none
global: none
```
This will import all outputs and filters, but not variants or globals.
Also note that imported globals has more precedence than the ones defined in the same file.
If you want to give more priority to the local values use:
```
kibot:
version: 1
imported_global_has_less_priority: true
import:
...
```
Another important detail is that global options that are lists gets the values merged.
The last set of values found is inserted at the beginning of the list.
You can collect filters for all the imported global sections.
### Doing YAML substitution or preprocessing
Sometimes you could want to change values in the YAML depending on external stuff,

View File

@ -464,6 +464,8 @@ class CfgYamlReader(object):
dir = os.path.dirname(os.path.abspath(name))
all_collected = CollectedImports()
for entry in imp:
is_internal = False
explicit_fils = explicit_vars = explicit_globals = explicit_pres = explicit_groups = False
if isinstance(entry, str):
fn = entry
outs = None
@ -473,19 +475,18 @@ class CfgYamlReader(object):
pre = []
groups = []
explicit_outs = True
explicit_fils = False
explicit_vars = False
explicit_globals = False
explicit_pres = False
explicit_groups = False
elif isinstance(entry, dict):
fn = outs = filters = vars = globals = pre = None
explicit_outs = explicit_fils = explicit_vars = explicit_globals = explicit_pres = False
fn = outs = filters = vars = globals = pre = groups = is_internal = None
explicit_outs = False
for k, v in entry.items():
if k == 'file':
if not isinstance(v, str):
raise KiPlotConfigurationError("`import.file` must be a string ({})".format(str(v)))
fn = v
elif k == 'is_internal':
if not isinstance(v, bool):
raise KiPlotConfigurationError("`import.is_internal` must be a true/false ({})".format(str(v)))
is_internal = v
elif k == 'outputs':
outs = self._parse_import_items(k, fn, v)
explicit_outs = True
@ -502,19 +503,25 @@ class CfgYamlReader(object):
globals = self._parse_import_items(k, fn, v)
explicit_globals = True
elif k == 'groups':
vars = self._parse_import_items(k, fn, v)
groups = self._parse_import_items(k, fn, v)
explicit_groups = True
else:
self._config_error_import(fn, "unknown import entry `{}`".format(str(v)))
self._config_error_import(fn, "Unknown import entry `{}`".format(str(v)))
if fn is None:
raise KiPlotConfigurationError("`import` entry without `file` ({})".format(str(entry)))
else:
raise KiPlotConfigurationError("`import` items must be strings or dicts ({})".format(str(entry)))
fn = os.path.expandvars(os.path.expanduser(fn))
if not os.path.isabs(fn):
fn = os.path.join(dir, fn)
if not os.path.isfile(fn):
raise KiPlotConfigurationError("missing import file `{}`".format(fn))
if is_internal:
name = fn
fn = os.path.join(GS.get_resource_path('config_templates'), fn+'.kibot.yaml')
if not os.path.isfile(fn):
raise KiPlotConfigurationError("Unknown internal import file `{}` ({})".format(name, fn))
else:
fn = os.path.expandvars(os.path.expanduser(fn))
if not os.path.isabs(fn):
fn = os.path.join(dir, fn)
if not os.path.isfile(fn):
raise KiPlotConfigurationError("Missing import file `{}`".format(fn))
fn_rel = os.path.relpath(fn)
data = self.load_yaml(open(fn))
if 'import' in data:

View File

@ -169,6 +169,7 @@ class RegOutput(Optionable, Registrable):
Returns a new list.
Assumes the outputs and groups are valid. """
new_targets = []
# Avoid infinite loops
level += 1
if level > 20:
raise KiPlotConfigurationError("More than 20 levels of nested groups, possible loop")

View File

@ -0,0 +1,65 @@
# Gerber and drill files for Elecrow, without stencil
# URL: https://www.elecrow.com/
# Based on setting used by Gerber Zipper (https://github.com/g200kg/kicad-gerberzipper)
kibot:
version: 1
groups:
- name: _Elecrow
outputs:
- _Elecrow_gerbers
- _Elecrow_drill
outputs:
- name: _Elecrow_gerbers
comment: Gerbers compatible with Elecrow
type: gerber
dir: Elecrow
options: &gerber_options
exclude_edge_layer: true
exclude_pads_from_silkscreen: true
plot_sheet_reference: false
plot_footprint_refs: true
plot_footprint_values: true
force_plot_invisible_refs_vals: false
tent_vias: true
use_protel_extensions: true
create_gerber_job_file: false
output: "%f.%x"
gerber_precision: 4.6
use_gerber_x2_attributes: false
use_gerber_net_attributes: false
disable_aperture_macros: true
line_width: 0.1
uppercase_extensions: true
subtract_mask_from_silk: true
inner_extension_pattern: '.g%n'
edge_cut_extension: '.gml'
layers:
- copper
- F.SilkS
- B.SilkS
- F.Mask
- B.Mask
- Edge.Cuts
- name: _Elecrow_drill
comment: Drill files compatible with Elecrow
type: excellon
dir: Elecrow
options:
pth_and_npth_single_file: false
pth_id: ''
npth_id: '-NPTH'
output: "%f%i.TXT"
- name: _Elecrow_compress
comment: ZIP file for Elecrow
type: compress
dir: Elecrow
options:
files:
- from_output: _Elecrow_gerbers
dest: /
- from_output: _Elecrow_drill
dest: /

View File

@ -34,7 +34,7 @@ ignore = E402, E226, E126, W504
# docstrings - text style (imperative, dot)
D4
max-line-length = 127
max-complexity = 22
max-complexity = 24
exclude = experiments/kicad/v6/
experiments/JLC/
kibot/mcpyrate/

View File

@ -866,6 +866,15 @@ def test_import_8(test_dir):
ctx.clean_up(keep_project=True)
def test_import_internal_1(test_dir):
""" Import an internal file """
prj = 'light_control'
ctx = context.TestContext(test_dir, prj, 'import_test_internal_1')
ctx.run(extra=['_Elecrow_drill'])
ctx.expect_out_file('Elecrow/light_control.TXT')
ctx.clean_up(keep_project=True)
def test_disable_default_1(test_dir):
""" Disable in the same file and out-of-order """
prj = 'test_v5'

View File

@ -0,0 +1,6 @@
kibot:
version: 1
import:
- file: Elecrow
is_internal: true