onescad 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- onescad-0.1.0/.github/ISSUE_TEMPLATE/bug_report.yml +32 -0
- onescad-0.1.0/.github/ISSUE_TEMPLATE/config.yml +1 -0
- onescad-0.1.0/.github/ISSUE_TEMPLATE/feature_request.yml +18 -0
- onescad-0.1.0/.github/PULL_REQUEST_TEMPLATE.md +6 -0
- onescad-0.1.0/.github/dependabot.yml +16 -0
- onescad-0.1.0/.github/workflows/check.yml +62 -0
- onescad-0.1.0/.github/workflows/publish.yml +31 -0
- onescad-0.1.0/.gitignore +10 -0
- onescad-0.1.0/.gitmodules +3 -0
- onescad-0.1.0/CHANGELOG.md +7 -0
- onescad-0.1.0/CONTRIBUTING.md +54 -0
- onescad-0.1.0/LICENSE +21 -0
- onescad-0.1.0/PKG-INFO +113 -0
- onescad-0.1.0/README.md +104 -0
- onescad-0.1.0/SECURITY.md +14 -0
- onescad-0.1.0/pyproject.toml +46 -0
- onescad-0.1.0/scripts/check-release.sh +82 -0
- onescad-0.1.0/scripts/release.sh +290 -0
- onescad-0.1.0/src/onescad/__init__.py +1 -0
- onescad-0.1.0/src/onescad/cli.py +133 -0
- onescad-0.1.0/src/onescad/customizer.py +249 -0
- onescad-0.1.0/src/onescad/emit.py +293 -0
- onescad-0.1.0/src/onescad/errors.py +5 -0
- onescad-0.1.0/src/onescad/flatten.py +164 -0
- onescad-0.1.0/src/onescad/header.py +109 -0
- onescad-0.1.0/src/onescad/lexer.py +102 -0
- onescad-0.1.0/src/onescad/licenses.py +50 -0
- onescad-0.1.0/src/onescad/loader.py +168 -0
- onescad-0.1.0/src/onescad/parser.py +409 -0
- onescad-0.1.0/src/onescad/paths.py +28 -0
- onescad-0.1.0/src/onescad/presets.py +38 -0
- onescad-0.1.0/src/onescad/rename.py +174 -0
- onescad-0.1.0/src/onescad/resolver.py +366 -0
- onescad-0.1.0/src/onescad/shake.py +59 -0
- onescad-0.1.0/src/onescad/syntax.py +225 -0
- onescad-0.1.0/src/onescad/verify.py +105 -0
- onescad-0.1.0/tests/fixtures/bosl2_std/expected.scad +19013 -0
- onescad-0.1.0/tests/fixtures/bosl2_std/libs +1 -0
- onescad-0.1.0/tests/fixtures/bosl2_std/main.scad +4 -0
- onescad-0.1.0/tests/fixtures/call_capture/expected.scad +16 -0
- onescad-0.1.0/tests/fixtures/call_capture/main.scad +6 -0
- onescad-0.1.0/tests/fixtures/customizer_edges/expected.scad +40 -0
- onescad-0.1.0/tests/fixtures/customizer_edges/main.scad +27 -0
- onescad-0.1.0/tests/fixtures/customizer_reassign_after_cutoff/expected.scad +10 -0
- onescad-0.1.0/tests/fixtures/customizer_reassign_after_cutoff/main.scad +4 -0
- onescad-0.1.0/tests/fixtures/cycle/a.scad +1 -0
- onescad-0.1.0/tests/fixtures/cycle/error.txt +1 -0
- onescad-0.1.0/tests/fixtures/cycle/main.scad +1 -0
- onescad-0.1.0/tests/fixtures/default_args/expected.scad +21 -0
- onescad-0.1.0/tests/fixtures/default_args/lib.scad +2 -0
- onescad-0.1.0/tests/fixtures/default_args/main.scad +6 -0
- onescad-0.1.0/tests/fixtures/dollar_in_used/error.txt +1 -0
- onescad-0.1.0/tests/fixtures/dollar_in_used/lib.scad +2 -0
- onescad-0.1.0/tests/fixtures/dollar_in_used/main.scad +2 -0
- onescad-0.1.0/tests/fixtures/echo_function_literal/a.scad +1 -0
- onescad-0.1.0/tests/fixtures/echo_function_literal/b.scad +2 -0
- onescad-0.1.0/tests/fixtures/echo_function_literal/expected.scad +16 -0
- onescad-0.1.0/tests/fixtures/echo_function_literal/main.scad +3 -0
- onescad-0.1.0/tests/fixtures/external_import/expected.scad +8 -0
- onescad-0.1.0/tests/fixtures/external_import/main.scad +1 -0
- onescad-0.1.0/tests/fixtures/external_import/noverify +1 -0
- onescad-0.1.0/tests/fixtures/external_import/warning.txt +1 -0
- onescad-0.1.0/tests/fixtures/header_blank_line/expected.scad +12 -0
- onescad-0.1.0/tests/fixtures/header_blank_line/main.scad +3 -0
- onescad-0.1.0/tests/fixtures/hoist_conflict/error.txt +1 -0
- onescad-0.1.0/tests/fixtures/hoist_conflict/main.scad +3 -0
- onescad-0.1.0/tests/fixtures/include_in_module/body.scad +2 -0
- onescad-0.1.0/tests/fixtures/include_in_module/expected.scad +13 -0
- onescad-0.1.0/tests/fixtures/include_in_module/main.scad +5 -0
- onescad-0.1.0/tests/fixtures/include_repeat/defs.scad +3 -0
- onescad-0.1.0/tests/fixtures/include_repeat/expected.scad +16 -0
- onescad-0.1.0/tests/fixtures/include_repeat/main.scad +3 -0
- onescad-0.1.0/tests/fixtures/license/expected.scad +18 -0
- onescad-0.1.0/tests/fixtures/license/main.scad +3 -0
- onescad-0.1.0/tests/fixtures/license/vendor/LICENSE +3 -0
- onescad-0.1.0/tests/fixtures/license/vendor/lib.scad +2 -0
- onescad-0.1.0/tests/fixtures/local_lookup/expected.scad +30 -0
- onescad-0.1.0/tests/fixtures/local_lookup/main.scad +18 -0
- onescad-0.1.0/tests/fixtures/missing_file/error.txt +1 -0
- onescad-0.1.0/tests/fixtures/missing_file/main.scad +1 -0
- onescad-0.1.0/tests/fixtures/presets/expected.scad +11 -0
- onescad-0.1.0/tests/fixtures/presets/main.json +1 -0
- onescad-0.1.0/tests/fixtures/presets/main.scad +2 -0
- onescad-0.1.0/tests/fixtures/reassign/expected.scad +20 -0
- onescad-0.1.0/tests/fixtures/reassign/main.scad +11 -0
- onescad-0.1.0/tests/fixtures/shadow_builtin/a.scad +1 -0
- onescad-0.1.0/tests/fixtures/shadow_builtin/b.scad +4 -0
- onescad-0.1.0/tests/fixtures/shadow_builtin/expected.scad +18 -0
- onescad-0.1.0/tests/fixtures/shadow_builtin/main.scad +3 -0
- onescad-0.1.0/tests/fixtures/shake/expected.scad +12 -0
- onescad-0.1.0/tests/fixtures/shake/lib.scad +5 -0
- onescad-0.1.0/tests/fixtures/shake/main.scad +2 -0
- onescad-0.1.0/tests/fixtures/use_basic/expected.scad +21 -0
- onescad-0.1.0/tests/fixtures/use_basic/lib.scad +3 -0
- onescad-0.1.0/tests/fixtures/use_basic/main.scad +7 -0
- onescad-0.1.0/tests/fixtures/use_basic/mid.scad +2 -0
- onescad-0.1.0/tests/fixtures/use_in_module/error.txt +1 -0
- onescad-0.1.0/tests/fixtures/use_in_module/main.scad +1 -0
- onescad-0.1.0/tests/fixtures/use_last_wins/a.scad +2 -0
- onescad-0.1.0/tests/fixtures/use_last_wins/b.scad +1 -0
- onescad-0.1.0/tests/fixtures/use_last_wins/expected.scad +12 -0
- onescad-0.1.0/tests/fixtures/use_last_wins/main.scad +4 -0
- onescad-0.1.0/tests/fixtures/use_placement/a.scad +2 -0
- onescad-0.1.0/tests/fixtures/use_placement/b.scad +1 -0
- onescad-0.1.0/tests/fixtures/use_placement/expected.scad +16 -0
- onescad-0.1.0/tests/fixtures/use_placement/main.scad +6 -0
- onescad-0.1.0/tests/helpers.py +59 -0
- onescad-0.1.0/tests/test_cli.py +178 -0
- onescad-0.1.0/tests/test_customizer.py +588 -0
- onescad-0.1.0/tests/test_emit.py +198 -0
- onescad-0.1.0/tests/test_flatten.py +106 -0
- onescad-0.1.0/tests/test_header.py +145 -0
- onescad-0.1.0/tests/test_lexer.py +111 -0
- onescad-0.1.0/tests/test_loader.py +240 -0
- onescad-0.1.0/tests/test_oracle.py +105 -0
- onescad-0.1.0/tests/test_parser.py +247 -0
- onescad-0.1.0/tests/test_presets.py +52 -0
- onescad-0.1.0/tests/test_rename.py +95 -0
- onescad-0.1.0/tests/test_resolver.py +268 -0
- onescad-0.1.0/tests/test_shake.py +87 -0
- onescad-0.1.0/tests/test_verify.py +60 -0
- onescad-0.1.0/tests/test_version.py +9 -0
- onescad-0.1.0/uv.lock +570 -0
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
name: Bug report
|
|
2
|
+
description: onescad fails on a model or produces a bundle that renders differently.
|
|
3
|
+
labels: [bug]
|
|
4
|
+
body:
|
|
5
|
+
- type: textarea
|
|
6
|
+
id: what-happened
|
|
7
|
+
attributes:
|
|
8
|
+
label: What happened
|
|
9
|
+
description: The command you ran, what you expected, and what you got instead.
|
|
10
|
+
validations:
|
|
11
|
+
required: true
|
|
12
|
+
- type: input
|
|
13
|
+
id: version
|
|
14
|
+
attributes:
|
|
15
|
+
label: onescad version
|
|
16
|
+
description: Output of `onescad --version`.
|
|
17
|
+
validations:
|
|
18
|
+
required: true
|
|
19
|
+
- type: input
|
|
20
|
+
id: openscad
|
|
21
|
+
attributes:
|
|
22
|
+
label: OpenSCAD version
|
|
23
|
+
description: Output of `openscad --version`, if the bug involves rendering or `--verify`.
|
|
24
|
+
validations:
|
|
25
|
+
required: false
|
|
26
|
+
- type: textarea
|
|
27
|
+
id: repro
|
|
28
|
+
attributes:
|
|
29
|
+
label: Minimal reproduction
|
|
30
|
+
description: A small .scad model that triggers the bug, if you can share one.
|
|
31
|
+
validations:
|
|
32
|
+
required: false
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
blank_issues_enabled: false
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
name: Feature request
|
|
2
|
+
description: Propose a change to onescad's behavior or CLI.
|
|
3
|
+
labels: [enhancement]
|
|
4
|
+
body:
|
|
5
|
+
- type: textarea
|
|
6
|
+
id: problem
|
|
7
|
+
attributes:
|
|
8
|
+
label: Problem
|
|
9
|
+
description: What you are trying to do that onescad does not support today.
|
|
10
|
+
validations:
|
|
11
|
+
required: true
|
|
12
|
+
- type: textarea
|
|
13
|
+
id: proposal
|
|
14
|
+
attributes:
|
|
15
|
+
label: Proposed change
|
|
16
|
+
description: What you would like to see, and why it fits bundling one model into one file.
|
|
17
|
+
validations:
|
|
18
|
+
required: true
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
## Checklist
|
|
2
|
+
|
|
3
|
+
- [ ] `uv run ruff check` and `uv run ruff format --check` pass
|
|
4
|
+
- [ ] `uv run mypy` and `uv run pytest` pass
|
|
5
|
+
- [ ] A fixture or test covers the behavior this PR changes
|
|
6
|
+
- [ ] `uv run pytest -m oracle --no-cov` passes if the bundle's output could change
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
version: 2
|
|
2
|
+
updates:
|
|
3
|
+
- package-ecosystem: github-actions
|
|
4
|
+
directory: /
|
|
5
|
+
schedule:
|
|
6
|
+
interval: weekly
|
|
7
|
+
|
|
8
|
+
- package-ecosystem: uv
|
|
9
|
+
directory: /
|
|
10
|
+
schedule:
|
|
11
|
+
interval: weekly
|
|
12
|
+
|
|
13
|
+
- package-ecosystem: gitsubmodule
|
|
14
|
+
directory: /
|
|
15
|
+
schedule:
|
|
16
|
+
interval: weekly
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
name: check
|
|
2
|
+
on:
|
|
3
|
+
push:
|
|
4
|
+
pull_request:
|
|
5
|
+
permissions:
|
|
6
|
+
contents: read
|
|
7
|
+
jobs:
|
|
8
|
+
check:
|
|
9
|
+
strategy:
|
|
10
|
+
matrix:
|
|
11
|
+
os: [ubuntu-latest, macos-latest]
|
|
12
|
+
python-version: ['3.11', '3.14']
|
|
13
|
+
runs-on: ${{ matrix.os }}
|
|
14
|
+
steps:
|
|
15
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
16
|
+
with:
|
|
17
|
+
persist-credentials: false
|
|
18
|
+
submodules: true
|
|
19
|
+
- uses: astral-sh/setup-uv@c18668ad3cf93ea998bef934396af7bb5c839dc7 # v10.2.0
|
|
20
|
+
- run: uv sync --locked --python ${{ matrix.python-version }}
|
|
21
|
+
- run: uv run ruff check
|
|
22
|
+
- run: uv run ruff format --check
|
|
23
|
+
- run: uv run mypy
|
|
24
|
+
- run: uv run pytest
|
|
25
|
+
|
|
26
|
+
oracle:
|
|
27
|
+
runs-on: ubuntu-latest
|
|
28
|
+
env:
|
|
29
|
+
OPENSCAD_VERSION: '2026.09.23'
|
|
30
|
+
OPENSCAD_SHA256: 033762f4e0b0de7a2c6cf2b5a12febb29d60ba62ede227d57b1c8b675a94710a
|
|
31
|
+
APPIMAGE_EXTRACT_AND_RUN: '1'
|
|
32
|
+
QT_QPA_PLATFORM: offscreen
|
|
33
|
+
steps:
|
|
34
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
35
|
+
with:
|
|
36
|
+
persist-credentials: false
|
|
37
|
+
submodules: true
|
|
38
|
+
- uses: astral-sh/setup-uv@c18668ad3cf93ea998bef934396af7bb5c839dc7 # v10.2.0
|
|
39
|
+
- name: Install OpenSCAD
|
|
40
|
+
run: |
|
|
41
|
+
sudo apt-get update
|
|
42
|
+
sudo apt-get install -y --no-install-recommends libegl1 libopengl0 libgl1 libglu1-mesa libxkbcommon0 libfontconfig1 libdbus-1-3
|
|
43
|
+
curl -fsSL -o openscad "https://files.openscad.org/snapshots/OpenSCAD-${OPENSCAD_VERSION}-x86_64.AppImage"
|
|
44
|
+
echo "${OPENSCAD_SHA256} openscad" | sha256sum -c -
|
|
45
|
+
chmod +x openscad
|
|
46
|
+
mkdir -p "$HOME/.local/bin"
|
|
47
|
+
mv openscad "$HOME/.local/bin/openscad"
|
|
48
|
+
echo "$HOME/.local/bin" >> "$GITHUB_PATH"
|
|
49
|
+
- run: openscad --version
|
|
50
|
+
- run: uv sync --locked
|
|
51
|
+
- run: uv run pytest -m oracle --no-cov
|
|
52
|
+
|
|
53
|
+
release-check:
|
|
54
|
+
runs-on: ubuntu-latest
|
|
55
|
+
steps:
|
|
56
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
57
|
+
with:
|
|
58
|
+
persist-credentials: false
|
|
59
|
+
- uses: astral-sh/setup-uv@c18668ad3cf93ea998bef934396af7bb5c839dc7 # v10.2.0
|
|
60
|
+
- run: uv build
|
|
61
|
+
- run: uvx twine check dist/*
|
|
62
|
+
- run: uvx zizmor==1.30.1 .github/workflows
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
name: publish
|
|
2
|
+
on:
|
|
3
|
+
release:
|
|
4
|
+
types: [published]
|
|
5
|
+
permissions:
|
|
6
|
+
contents: read
|
|
7
|
+
jobs:
|
|
8
|
+
verify:
|
|
9
|
+
runs-on: ubuntu-latest
|
|
10
|
+
env:
|
|
11
|
+
RELEASE_TAG: ${{ github.event.release.tag_name }}
|
|
12
|
+
RELEASE_NAME: ${{ github.event.release.name }}
|
|
13
|
+
steps:
|
|
14
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
15
|
+
with:
|
|
16
|
+
persist-credentials: false
|
|
17
|
+
- run: sh scripts/check-release.sh "$RELEASE_TAG" "$RELEASE_NAME"
|
|
18
|
+
publish:
|
|
19
|
+
needs: verify
|
|
20
|
+
runs-on: ubuntu-latest
|
|
21
|
+
permissions:
|
|
22
|
+
id-token: write
|
|
23
|
+
steps:
|
|
24
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
25
|
+
with:
|
|
26
|
+
persist-credentials: false
|
|
27
|
+
- uses: astral-sh/setup-uv@c18668ad3cf93ea998bef934396af7bb5c839dc7 # v10.2.0
|
|
28
|
+
with:
|
|
29
|
+
enable-cache: false
|
|
30
|
+
- run: uv build
|
|
31
|
+
- uses: pypa/gh-action-pypi-publish@dc37677b2e1c63e2034f94d8a5b11f265b73ba33 # v1.14.2
|
onescad-0.1.0/.gitignore
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 0.1.0
|
|
4
|
+
|
|
5
|
+
First release. `onescad INPUT -o OUTPUT [-L DIR]... [--verify]` bundles an OpenSCAD model and
|
|
6
|
+
everything it includes or uses into one `.scad` file that keeps the Customizer working, copies a
|
|
7
|
+
neighboring presets file, and embeds each contributing license.
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# Contributing
|
|
2
|
+
|
|
3
|
+
## Setup and checks
|
|
4
|
+
|
|
5
|
+
```sh
|
|
6
|
+
git submodule update --init
|
|
7
|
+
uv sync --locked
|
|
8
|
+
uv run ruff check
|
|
9
|
+
uv run ruff format --check
|
|
10
|
+
uv run mypy
|
|
11
|
+
uv run pytest
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
`tests/corpus/BOSL2` is a submodule pinned to the BOSL2 revision the parser tests run against.
|
|
15
|
+
`pytest` fails under 90% coverage.
|
|
16
|
+
|
|
17
|
+
The oracle tests render the source and the bundle with a real `openscad` and skip without one.
|
|
18
|
+
CI runs them against a pinned OpenSCAD 2026.09.23 AppImage. Locally:
|
|
19
|
+
|
|
20
|
+
```sh
|
|
21
|
+
uv run pytest -m oracle --no-cov
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Each fixture under `tests/fixtures/<case>/` holds a `main.scad` and a golden `expected.scad`,
|
|
25
|
+
or an `error.txt` for a case that must fail. Regenerate goldens with
|
|
26
|
+
`ONESCAD_UPDATE_GOLDEN=1`. A defect found in review is fixed with a fixture or test for its
|
|
27
|
+
class, not only its instance.
|
|
28
|
+
|
|
29
|
+
CI also runs `uv build`, `twine check`, and `zizmor` over the workflows.
|
|
30
|
+
|
|
31
|
+
## Releasing
|
|
32
|
+
|
|
33
|
+
```sh
|
|
34
|
+
sh scripts/release.sh [--dry-run] <version>
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
`<version>` is bare (`0.1.0`, not `v0.1.0`). Run it on a clean, synced `main` with `gh` and `uv`
|
|
38
|
+
installed. The script runs the same checks CI runs, opens a `release-<version>` PR that sets the
|
|
39
|
+
version in `pyproject.toml`, `src/onescad/__init__.py`, and `uv.lock`, waits for its checks, and
|
|
40
|
+
squash-merges it. GitHub signs the squash commit, so the release shows as Verified. It then
|
|
41
|
+
tags the merged commit and creates the GitHub release from the matching `CHANGELOG.md` section;
|
|
42
|
+
add a `## <version>` heading there first. If the bump is already on `main`, it skips the PR and
|
|
43
|
+
only tags and releases, so a run that stopped after the merge can be repeated. `--dry-run` runs
|
|
44
|
+
every check and prints each mutating command instead of running it.
|
|
45
|
+
|
|
46
|
+
The release event triggers `publish.yml`, which re-runs `scripts/check-release.sh` (the tag, its
|
|
47
|
+
title, and the `CHANGELOG.md` heading must all agree) before building and publishing to PyPI
|
|
48
|
+
through a trusted publisher.
|
|
49
|
+
|
|
50
|
+
## Scope
|
|
51
|
+
|
|
52
|
+
onescad is a single-maintainer project with no runtime dependencies. It bundles one model into
|
|
53
|
+
one file and checks the result. PRs that add a runtime dependency or reach past that are
|
|
54
|
+
declined. Bug reports and fixes are welcome.
|
onescad-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Kamil Jiwa
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
onescad-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: onescad
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Bundle an OpenSCAD model into one customizer-ready file
|
|
5
|
+
License-Expression: MIT
|
|
6
|
+
License-File: LICENSE
|
|
7
|
+
Requires-Python: >=3.11
|
|
8
|
+
Description-Content-Type: text/markdown
|
|
9
|
+
|
|
10
|
+
# onescad
|
|
11
|
+
|
|
12
|
+
Bundle an OpenSCAD model into one self-contained, Customizer-ready `.scad` file.
|
|
13
|
+
|
|
14
|
+
```sh
|
|
15
|
+
uvx onescad model.scad -o dist/model.scad
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
The bundle renders identically to the source, keeps the Customizer's parameters, groups, and
|
|
19
|
+
widgets, and carries the license text of every file it takes code from. Python 3.11 or newer;
|
|
20
|
+
no runtime dependencies.
|
|
21
|
+
|
|
22
|
+
## Usage
|
|
23
|
+
|
|
24
|
+
```
|
|
25
|
+
onescad INPUT -o OUTPUT [-L DIR]... [--verify] [--version]
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
| Option | Meaning |
|
|
29
|
+
| --- | --- |
|
|
30
|
+
| `INPUT` | The model's `.scad` file. |
|
|
31
|
+
| `-o`, `--output` | The bundle to write. Parent directories are created. |
|
|
32
|
+
| `-L`, `--library DIR` | A directory to search for `include` and `use`; repeatable. |
|
|
33
|
+
| `--verify` | Render the source and the bundle with `openscad` and compare them. |
|
|
34
|
+
| `--version` | Print the version. |
|
|
35
|
+
|
|
36
|
+
Warnings print to stderr as `onescad: warning: <message>`. Errors print as `onescad: <message>`.
|
|
37
|
+
|
|
38
|
+
| Exit code | Meaning |
|
|
39
|
+
| --- | --- |
|
|
40
|
+
| 0 | The bundle was written (and verified, with `--verify`). |
|
|
41
|
+
| 1 | The bundle could not be built or verified. |
|
|
42
|
+
| 2 | Usage error. |
|
|
43
|
+
|
|
44
|
+
## Search path
|
|
45
|
+
|
|
46
|
+
`include` and `use` are resolved in this order: the including file's directory, each `-L`
|
|
47
|
+
directory, then each `OPENSCADPATH` entry. OpenSCAD also searches the user and built-in library
|
|
48
|
+
directories; onescad does not, so a bundle is the same on every machine. Put those libraries on
|
|
49
|
+
`-L` or `OPENSCADPATH`. A missing file is an error that lists the directories searched.
|
|
50
|
+
|
|
51
|
+
## What gets bundled
|
|
52
|
+
|
|
53
|
+
The output has these parts, in order:
|
|
54
|
+
|
|
55
|
+
1. A header of `//` comments:
|
|
56
|
+
- the onescad version, marked as generated;
|
|
57
|
+
- the source path relative to its git root, the remote as an https URL, and the commit, with
|
|
58
|
+
`+dirty` when tracked files have uncommitted changes (omitted outside a git work tree with a
|
|
59
|
+
commit);
|
|
60
|
+
- the main file's leading comment;
|
|
61
|
+
- the fonts named by `font=` strings, the files read by `import()` or `surface()`, and a note
|
|
62
|
+
naming the presets file, when they apply;
|
|
63
|
+
- for each license file covering code that was kept, its directory and its text verbatim. The
|
|
64
|
+
license file is the nearest `LICENSE*`, `LICENCE*`, or `COPYING*` in an ancestor directory of
|
|
65
|
+
each source file.
|
|
66
|
+
2. The Customizer parameters, hoisted to the top.
|
|
67
|
+
3. A `/* [Hidden] */` marker, so nothing after it appears in the Customizer.
|
|
68
|
+
4. Each used file's definitions, dependencies first, each preceded by a `// onescad: <path>` marker
|
|
69
|
+
and the file's leading comment.
|
|
70
|
+
5. The main file, with its included files spliced in.
|
|
71
|
+
|
|
72
|
+
The output has no timestamps, so the same input gives byte-identical output.
|
|
73
|
+
|
|
74
|
+
Definitions that the model never reaches are dropped. A definition is renamed (`name__1`) when
|
|
75
|
+
keeping its name would capture a different reference, as when a library wraps a builtin it later
|
|
76
|
+
overrides.
|
|
77
|
+
|
|
78
|
+
## Presets
|
|
79
|
+
|
|
80
|
+
If `model.json` sits next to `model.scad`, onescad copies it verbatim to the output's name with a
|
|
81
|
+
`.json` extension (`dist/model.json` for `-o dist/model.scad`). OpenSCAD loads presets only from a
|
|
82
|
+
`.json` beside the `.scad`, so keep the two together. A warning names each preset key that is not a
|
|
83
|
+
Customizer parameter of the bundle.
|
|
84
|
+
|
|
85
|
+
## Verification
|
|
86
|
+
|
|
87
|
+
`--verify` needs `openscad` on `PATH`. It compares the source with the bundle on:
|
|
88
|
+
|
|
89
|
+
- the CSG of the default parameters and of every preset;
|
|
90
|
+
- the `ECHO` lines, after undoing renames;
|
|
91
|
+
- the Customizer parameter set (`-o x.param`, ignoring `title`).
|
|
92
|
+
|
|
93
|
+
The bundle renders with `OPENSCADPATH` unset and an empty `HOME`, which proves it is
|
|
94
|
+
self-contained. `text()` fonts are not compared. Verifying needs an OpenSCAD that can export
|
|
95
|
+
`param` (the 2026.09 snapshots do; 2021.01 is untested).
|
|
96
|
+
|
|
97
|
+
## Limitations
|
|
98
|
+
|
|
99
|
+
- The Customizer is emulated, not run. A model whose parameter assignment reads a name before
|
|
100
|
+
that name's first assignment cannot be hoisted; onescad stops with an error.
|
|
101
|
+
- A top-level `$` variable in a used file, conflicting definitions that cannot be renamed, and a
|
|
102
|
+
rename that would split a call's possible targets are errors.
|
|
103
|
+
- A top-level variable in a used file is evaluated once in the bundle, not on every call as
|
|
104
|
+
OpenSCAD does; onescad warns.
|
|
105
|
+
- `import()` and `surface()` still read their files at render time; onescad warns and lists them
|
|
106
|
+
in the header. Relative paths then resolve against wherever the bundle is rendered.
|
|
107
|
+
- Fonts are not embedded; the header lists those that `font=` names.
|
|
108
|
+
- A model's license text appears in the header only when a license file covers its source.
|
|
109
|
+
onescad warns about each source file with none.
|
|
110
|
+
|
|
111
|
+
## License
|
|
112
|
+
|
|
113
|
+
MIT. See `LICENSE`. Bundles carry the licenses of their inputs; check them before redistributing.
|
onescad-0.1.0/README.md
ADDED
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
# onescad
|
|
2
|
+
|
|
3
|
+
Bundle an OpenSCAD model into one self-contained, Customizer-ready `.scad` file.
|
|
4
|
+
|
|
5
|
+
```sh
|
|
6
|
+
uvx onescad model.scad -o dist/model.scad
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
The bundle renders identically to the source, keeps the Customizer's parameters, groups, and
|
|
10
|
+
widgets, and carries the license text of every file it takes code from. Python 3.11 or newer;
|
|
11
|
+
no runtime dependencies.
|
|
12
|
+
|
|
13
|
+
## Usage
|
|
14
|
+
|
|
15
|
+
```
|
|
16
|
+
onescad INPUT -o OUTPUT [-L DIR]... [--verify] [--version]
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
| Option | Meaning |
|
|
20
|
+
| --- | --- |
|
|
21
|
+
| `INPUT` | The model's `.scad` file. |
|
|
22
|
+
| `-o`, `--output` | The bundle to write. Parent directories are created. |
|
|
23
|
+
| `-L`, `--library DIR` | A directory to search for `include` and `use`; repeatable. |
|
|
24
|
+
| `--verify` | Render the source and the bundle with `openscad` and compare them. |
|
|
25
|
+
| `--version` | Print the version. |
|
|
26
|
+
|
|
27
|
+
Warnings print to stderr as `onescad: warning: <message>`. Errors print as `onescad: <message>`.
|
|
28
|
+
|
|
29
|
+
| Exit code | Meaning |
|
|
30
|
+
| --- | --- |
|
|
31
|
+
| 0 | The bundle was written (and verified, with `--verify`). |
|
|
32
|
+
| 1 | The bundle could not be built or verified. |
|
|
33
|
+
| 2 | Usage error. |
|
|
34
|
+
|
|
35
|
+
## Search path
|
|
36
|
+
|
|
37
|
+
`include` and `use` are resolved in this order: the including file's directory, each `-L`
|
|
38
|
+
directory, then each `OPENSCADPATH` entry. OpenSCAD also searches the user and built-in library
|
|
39
|
+
directories; onescad does not, so a bundle is the same on every machine. Put those libraries on
|
|
40
|
+
`-L` or `OPENSCADPATH`. A missing file is an error that lists the directories searched.
|
|
41
|
+
|
|
42
|
+
## What gets bundled
|
|
43
|
+
|
|
44
|
+
The output has these parts, in order:
|
|
45
|
+
|
|
46
|
+
1. A header of `//` comments:
|
|
47
|
+
- the onescad version, marked as generated;
|
|
48
|
+
- the source path relative to its git root, the remote as an https URL, and the commit, with
|
|
49
|
+
`+dirty` when tracked files have uncommitted changes (omitted outside a git work tree with a
|
|
50
|
+
commit);
|
|
51
|
+
- the main file's leading comment;
|
|
52
|
+
- the fonts named by `font=` strings, the files read by `import()` or `surface()`, and a note
|
|
53
|
+
naming the presets file, when they apply;
|
|
54
|
+
- for each license file covering code that was kept, its directory and its text verbatim. The
|
|
55
|
+
license file is the nearest `LICENSE*`, `LICENCE*`, or `COPYING*` in an ancestor directory of
|
|
56
|
+
each source file.
|
|
57
|
+
2. The Customizer parameters, hoisted to the top.
|
|
58
|
+
3. A `/* [Hidden] */` marker, so nothing after it appears in the Customizer.
|
|
59
|
+
4. Each used file's definitions, dependencies first, each preceded by a `// onescad: <path>` marker
|
|
60
|
+
and the file's leading comment.
|
|
61
|
+
5. The main file, with its included files spliced in.
|
|
62
|
+
|
|
63
|
+
The output has no timestamps, so the same input gives byte-identical output.
|
|
64
|
+
|
|
65
|
+
Definitions that the model never reaches are dropped. A definition is renamed (`name__1`) when
|
|
66
|
+
keeping its name would capture a different reference, as when a library wraps a builtin it later
|
|
67
|
+
overrides.
|
|
68
|
+
|
|
69
|
+
## Presets
|
|
70
|
+
|
|
71
|
+
If `model.json` sits next to `model.scad`, onescad copies it verbatim to the output's name with a
|
|
72
|
+
`.json` extension (`dist/model.json` for `-o dist/model.scad`). OpenSCAD loads presets only from a
|
|
73
|
+
`.json` beside the `.scad`, so keep the two together. A warning names each preset key that is not a
|
|
74
|
+
Customizer parameter of the bundle.
|
|
75
|
+
|
|
76
|
+
## Verification
|
|
77
|
+
|
|
78
|
+
`--verify` needs `openscad` on `PATH`. It compares the source with the bundle on:
|
|
79
|
+
|
|
80
|
+
- the CSG of the default parameters and of every preset;
|
|
81
|
+
- the `ECHO` lines, after undoing renames;
|
|
82
|
+
- the Customizer parameter set (`-o x.param`, ignoring `title`).
|
|
83
|
+
|
|
84
|
+
The bundle renders with `OPENSCADPATH` unset and an empty `HOME`, which proves it is
|
|
85
|
+
self-contained. `text()` fonts are not compared. Verifying needs an OpenSCAD that can export
|
|
86
|
+
`param` (the 2026.09 snapshots do; 2021.01 is untested).
|
|
87
|
+
|
|
88
|
+
## Limitations
|
|
89
|
+
|
|
90
|
+
- The Customizer is emulated, not run. A model whose parameter assignment reads a name before
|
|
91
|
+
that name's first assignment cannot be hoisted; onescad stops with an error.
|
|
92
|
+
- A top-level `$` variable in a used file, conflicting definitions that cannot be renamed, and a
|
|
93
|
+
rename that would split a call's possible targets are errors.
|
|
94
|
+
- A top-level variable in a used file is evaluated once in the bundle, not on every call as
|
|
95
|
+
OpenSCAD does; onescad warns.
|
|
96
|
+
- `import()` and `surface()` still read their files at render time; onescad warns and lists them
|
|
97
|
+
in the header. Relative paths then resolve against wherever the bundle is rendered.
|
|
98
|
+
- Fonts are not embedded; the header lists those that `font=` names.
|
|
99
|
+
- A model's license text appears in the header only when a license file covers its source.
|
|
100
|
+
onescad warns about each source file with none.
|
|
101
|
+
|
|
102
|
+
## License
|
|
103
|
+
|
|
104
|
+
MIT. See `LICENSE`. Bundles carry the licenses of their inputs; check them before redistributing.
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# Security
|
|
2
|
+
|
|
3
|
+
onescad reads the `.scad` files that a model includes or uses, the license files beside them,
|
|
4
|
+
and a neighboring presets `.json`. It runs `git` to read the source's remote and commit, and,
|
|
5
|
+
with `--verify`, `openscad`. It writes the bundle and a copy of the presets file. It makes no
|
|
6
|
+
network requests and sends no telemetry. A bundle embeds the remote URL of the repository it
|
|
7
|
+
was built from.
|
|
8
|
+
|
|
9
|
+
## Reporting a vulnerability
|
|
10
|
+
|
|
11
|
+
Please use
|
|
12
|
+
[GitHub's private vulnerability reporting](https://github.com/kjiwa/onescad/security/advisories/new)
|
|
13
|
+
for this repository rather than opening a public issue. If that option isn't available yet,
|
|
14
|
+
email kamil.jiwa@gmail.com instead.
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "onescad"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "Bundle an OpenSCAD model into one customizer-ready file"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
license = "MIT"
|
|
11
|
+
license-files = ["LICENSE"]
|
|
12
|
+
requires-python = ">=3.11"
|
|
13
|
+
dependencies = []
|
|
14
|
+
|
|
15
|
+
[project.scripts]
|
|
16
|
+
onescad = "onescad.cli:main"
|
|
17
|
+
|
|
18
|
+
[dependency-groups]
|
|
19
|
+
dev = ["pytest", "pytest-cov", "mypy", "ruff"]
|
|
20
|
+
|
|
21
|
+
[tool.hatch.build.targets.wheel]
|
|
22
|
+
packages = ["src/onescad"]
|
|
23
|
+
|
|
24
|
+
[tool.ruff]
|
|
25
|
+
line-length = 100
|
|
26
|
+
src = ["src", "tests"]
|
|
27
|
+
extend-exclude = ["tests/corpus"]
|
|
28
|
+
|
|
29
|
+
[tool.ruff.lint]
|
|
30
|
+
select = ["E", "F", "I", "UP", "B", "S", "SIM", "RUF"]
|
|
31
|
+
|
|
32
|
+
[tool.ruff.lint.per-file-ignores]
|
|
33
|
+
"tests/**" = ["S101"]
|
|
34
|
+
|
|
35
|
+
[tool.mypy]
|
|
36
|
+
strict = true
|
|
37
|
+
files = ["src", "tests"]
|
|
38
|
+
exclude = ["tests/corpus/"]
|
|
39
|
+
|
|
40
|
+
[tool.pytest.ini_options]
|
|
41
|
+
testpaths = ["tests"]
|
|
42
|
+
addopts = "--cov=onescad --cov-report=term-missing"
|
|
43
|
+
markers = ["oracle: compares against a real openscad run"]
|
|
44
|
+
|
|
45
|
+
[tool.coverage.report]
|
|
46
|
+
fail_under = 90
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
#!/bin/sh
|
|
2
|
+
# Check that a release's tag and title match the version in pyproject.toml
|
|
3
|
+
# and that CHANGELOG.md has a matching heading, so a hand-cut release
|
|
4
|
+
# cannot drift the way v0.1.7 did.
|
|
5
|
+
#
|
|
6
|
+
# Usage: sh scripts/check-release.sh <tag> <title>
|
|
7
|
+
# sh scripts/check-release.sh --changelog <tag>
|
|
8
|
+
#
|
|
9
|
+
# --changelog checks only the CHANGELOG heading, for use before the version
|
|
10
|
+
# bump has landed in pyproject.toml.
|
|
11
|
+
set -eu
|
|
12
|
+
|
|
13
|
+
_check_tag_shape() {
|
|
14
|
+
_check_tag_shape_tag=$1
|
|
15
|
+
if ! echo "$_check_tag_shape_tag" | grep -Eq '^v[0-9]+\.[0-9]+\.[0-9]+$'; then
|
|
16
|
+
echo "check-release: tag '$_check_tag_shape_tag' does not match vX.Y.Z" >&2
|
|
17
|
+
return 1
|
|
18
|
+
fi
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
_check_tag_matches_version() {
|
|
22
|
+
_check_tag_matches_version_tag=$1
|
|
23
|
+
_check_tag_matches_version_version=$(sed -n 's/^version = "\(.*\)"$/\1/p' "$PYPROJECT" | head -n1)
|
|
24
|
+
if [ -z "$_check_tag_matches_version_version" ]; then
|
|
25
|
+
echo "check-release: could not read version from $PYPROJECT" >&2
|
|
26
|
+
return 1
|
|
27
|
+
fi
|
|
28
|
+
if [ "$_check_tag_matches_version_tag" != "v$_check_tag_matches_version_version" ]; then
|
|
29
|
+
echo "check-release: tag '$_check_tag_matches_version_tag' does not match pyproject.toml version '$_check_tag_matches_version_version'" >&2
|
|
30
|
+
return 1
|
|
31
|
+
fi
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
_check_title_matches_tag() {
|
|
35
|
+
_check_title_matches_tag_tag=$1
|
|
36
|
+
_check_title_matches_tag_title=$2
|
|
37
|
+
if [ "$_check_title_matches_tag_title" != "$_check_title_matches_tag_tag" ]; then
|
|
38
|
+
echo "check-release: title '$_check_title_matches_tag_title' does not match tag '$_check_title_matches_tag_tag'" >&2
|
|
39
|
+
return 1
|
|
40
|
+
fi
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
_check_changelog_heading() {
|
|
44
|
+
_check_changelog_heading_tag=$1
|
|
45
|
+
_check_changelog_heading_version=${_check_changelog_heading_tag#v}
|
|
46
|
+
if ! grep -Fxq "## $_check_changelog_heading_version" "$CHANGELOG"; then
|
|
47
|
+
echo "check-release: CHANGELOG.md has no '## $_check_changelog_heading_version' heading" >&2
|
|
48
|
+
return 1
|
|
49
|
+
fi
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
main() {
|
|
53
|
+
REPO_ROOT=$(CDPATH='' cd -- "$(dirname -- "$0")/.." && pwd)
|
|
54
|
+
readonly REPO_ROOT
|
|
55
|
+
readonly PYPROJECT="$REPO_ROOT/pyproject.toml"
|
|
56
|
+
readonly CHANGELOG="$REPO_ROOT/CHANGELOG.md"
|
|
57
|
+
|
|
58
|
+
if [ $# -eq 2 ] && [ "$1" = "--changelog" ]; then
|
|
59
|
+
_check_changelog_heading "$2"
|
|
60
|
+
exit $?
|
|
61
|
+
fi
|
|
62
|
+
if [ $# -ne 2 ]; then
|
|
63
|
+
echo "usage: sh scripts/check-release.sh <tag> <title>" >&2
|
|
64
|
+
echo " sh scripts/check-release.sh --changelog <tag>" >&2
|
|
65
|
+
exit 2
|
|
66
|
+
fi
|
|
67
|
+
|
|
68
|
+
_main_tag=$1
|
|
69
|
+
_main_title=$2
|
|
70
|
+
_main_status=0
|
|
71
|
+
|
|
72
|
+
_check_tag_shape "$_main_tag" || _main_status=1
|
|
73
|
+
if [ "$_main_status" -eq 0 ]; then
|
|
74
|
+
_check_tag_matches_version "$_main_tag" || _main_status=1
|
|
75
|
+
fi
|
|
76
|
+
_check_title_matches_tag "$_main_tag" "$_main_title" || _main_status=1
|
|
77
|
+
_check_changelog_heading "$_main_tag" || _main_status=1
|
|
78
|
+
|
|
79
|
+
exit "$_main_status"
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
main "$@"
|