casperbox 0.2.1__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.
- casperbox-0.2.1/.gitignore +10 -0
- casperbox-0.2.1/PKG-INFO +190 -0
- casperbox-0.2.1/README.md +182 -0
- casperbox-0.2.1/pyproject.toml +27 -0
- casperbox-0.2.1/src/casperbox/__init__.py +8 -0
- casperbox-0.2.1/src/casperbox/assets/common/packages/software.list +70 -0
- casperbox-0.2.1/src/casperbox/assets/common/rootfs/etc/profile.d/casper.sh +48 -0
- casperbox-0.2.1/src/casperbox/assets/common/rootfs/etc/ssh/sshd_config.d/casper.conf +8 -0
- casperbox-0.2.1/src/casperbox/assets/common/rootfs/usr/local/bin/entrypoint.sh +82 -0
- casperbox-0.2.1/src/casperbox/assets/common/scripts/config_mlib_devel.sh +54 -0
- casperbox-0.2.1/src/casperbox/assets/common/scripts/create_user.sh +39 -0
- casperbox-0.2.1/src/casperbox/assets/common/scripts/install_base.sh +27 -0
- casperbox-0.2.1/src/casperbox/assets/common/scripts/install_miniconda.sh +27 -0
- casperbox-0.2.1/src/casperbox/assets/common/scripts/install_scilab.sh +45 -0
- casperbox-0.2.1/src/casperbox/assets/common/scripts/setup_conda_env.sh +16 -0
- casperbox-0.2.1/src/casperbox/assets/common/vnc/xstartup +9 -0
- casperbox-0.2.1/src/casperbox/assets/versions/m2021a/Dockerfile +85 -0
- casperbox-0.2.1/src/casperbox/assets/versions/m2021a/toolflow.toml +32 -0
- casperbox-0.2.1/src/casperbox/cli.py +318 -0
- casperbox-0.2.1/src/casperbox/config.py +362 -0
- casperbox-0.2.1/src/casperbox/errors.py +2 -0
- casperbox-0.2.1/src/casperbox/podman.py +262 -0
- casperbox-0.2.1/src/casperbox/templates/casperbox.toml +46 -0
- casperbox-0.2.1/src/casperbox/versions.py +85 -0
- casperbox-0.2.1/tests/test_config.py +172 -0
- casperbox-0.2.1/uv.lock +150 -0
casperbox-0.2.1/PKG-INFO
ADDED
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: casperbox
|
|
3
|
+
Version: 0.2.1
|
|
4
|
+
Summary: Build and run CASPER toolflow development containers with rootless podman
|
|
5
|
+
Requires-Python: >=3.11
|
|
6
|
+
Requires-Dist: typer>=0.12
|
|
7
|
+
Description-Content-Type: text/markdown
|
|
8
|
+
|
|
9
|
+
# casperbox
|
|
10
|
+
|
|
11
|
+
`casperbox` builds and runs CASPER toolflow development containers with rootless podman.
|
|
12
|
+
|
|
13
|
+
The image includes openssh-server, TigerVNC (XFCE desktop), Firefox, Miniconda (conda env),
|
|
14
|
+
mlib_devel, device-tree-xlnx and Scilab. Vivado and the license are mounted from the host.
|
|
15
|
+
|
|
16
|
+
## Supported versions
|
|
17
|
+
|
|
18
|
+
| Version | Base image | Vivado | Python | mlib_devel | device-tree-xlnx | Scilab |
|
|
19
|
+
|---|---|---|---|---|---|---|
|
|
20
|
+
| m2021a | Ubuntu 20.04 | 2021.1 | 3.14 | [liuweiseu/mlib_devel](https://github.com/liuweiseu/mlib_devel) `scilab-dev-ai` | xlnx_rel_v2021.1 | 2024.1.0 |
|
|
21
|
+
|
|
22
|
+
## Host requirements
|
|
23
|
+
|
|
24
|
+
- [uv](https://docs.astral.sh/uv/) (installs without sudo)
|
|
25
|
+
- rootless podman >= 4.4 (run as a regular user) and the passt package (provides pasta)
|
|
26
|
+
- An installed Vivado (version in the table above) and a Xilinx license
|
|
27
|
+
|
|
28
|
+
## Host setup
|
|
29
|
+
|
|
30
|
+
Log in directly (SSH or desktop) as the user that runs podman (do not switch with `su`), then run:
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
loginctl enable-linger "$(id -un)" # keep the user's systemd running, also after logout
|
|
34
|
+
grep "^$(id -un):" /etc/subuid /etc/subgid # should print one line each; otherwise ask an admin
|
|
35
|
+
podman system migrate
|
|
36
|
+
ls /run/user/$(id -u)/bus # the user's systemd bus must exist
|
|
37
|
+
podman run --rm docker.io/library/ubuntu:20.04 true # must succeed with no WARN/ERROR
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
If the last command fails with `sd-bus call: Access denied` (no user systemd session, e.g. after `su`),
|
|
41
|
+
either point the shell at the user's bus:
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
export XDG_RUNTIME_DIR=/run/user/$(id -u)
|
|
45
|
+
export DBUS_SESSION_BUS_ADDRESS=unix:path=$XDG_RUNTIME_DIR/bus
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
or stop podman from using systemd for cgroups:
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
mkdir -p ~/.config/containers
|
|
52
|
+
printf '[engine]\ncgroup_manager = "cgroupfs"\nevents_logger = "file"\n' >> ~/.config/containers/containers.conf
|
|
53
|
+
podman system migrate
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Install
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
uv tool install git+https://github.com/<owner>/casperbox
|
|
60
|
+
# or from a local clone
|
|
61
|
+
uv tool install ./casperbox
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
Upgrade with `uv tool upgrade casperbox`.
|
|
65
|
+
|
|
66
|
+
## Quick start
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
mkdir ~/casper-a && cd ~/casper-a
|
|
70
|
+
casperbox init # creates casperbox.toml
|
|
71
|
+
vi casperbox.toml # set vivado.dir / paths.license_dir / ports
|
|
72
|
+
casperbox up # builds the image on first use, then starts the container
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
Connect:
|
|
76
|
+
|
|
77
|
+
- SSH: `ssh -p <ports.ssh> casper@<host>`, password `container.password` (default `casper`)
|
|
78
|
+
- VNC: `<host>:<ports.vnc>`, password `container.vnc_password` (default `casper`)
|
|
79
|
+
- Local: `casperbox shell`
|
|
80
|
+
|
|
81
|
+
## Configuration
|
|
82
|
+
|
|
83
|
+
`casperbox init` writes a commented `casperbox.toml` (permissions 600, it holds passwords).
|
|
84
|
+
Relative paths in it are relative to the file's directory.
|
|
85
|
+
|
|
86
|
+
| Key | Default | Description |
|
|
87
|
+
|---|---|---|
|
|
88
|
+
| `version` | | Toolflow version (`casperbox list`) |
|
|
89
|
+
| `container.name` | `casper-<version>` | Container name and hostname |
|
|
90
|
+
| `container.user` | `casper` | Container user |
|
|
91
|
+
| `container.password` / `vnc_password` | `casper` | SSH/sudo and VNC (6-8 chars) passwords |
|
|
92
|
+
| `container.mac` | random | MAC of `eth0` |
|
|
93
|
+
| `container.shm_size` / `tz` | `2g` / `UTC` | |
|
|
94
|
+
| `vivado.dir` / `vivado.mount` | / `ro` | Vivado install, mounted at the same path |
|
|
95
|
+
| `paths.license_dir` | `~/.Xilinx` | Mounted at `~/.Xilinx` |
|
|
96
|
+
| `paths.work_dir` | `./work` | Mounted at `~/work` (created if missing) |
|
|
97
|
+
| `ports.bind_address` | `0.0.0.0` | |
|
|
98
|
+
| `ports.ssh` / `ports.vnc` | `2222` / `5901` | Host ports for container 22 / 5901 |
|
|
99
|
+
| `vnc.geometry` | `1920x1080` | |
|
|
100
|
+
| `[[mounts]]` | | Extra mounts: `host`, `container` (`~/` = home), `mode` |
|
|
101
|
+
| `[[extra_ports]]` | | Extra ports: `host`, `container`, `protocol` |
|
|
102
|
+
|
|
103
|
+
Unknown keys and wrong types (e.g. a port written as a string) are reported as errors.
|
|
104
|
+
|
|
105
|
+
### Several containers
|
|
106
|
+
|
|
107
|
+
Each config file is one container. Use another directory or file, and give it its own
|
|
108
|
+
`container.name` and ports:
|
|
109
|
+
|
|
110
|
+
```bash
|
|
111
|
+
casperbox init lab.toml # edit container.name, ports.ssh, ports.vnc
|
|
112
|
+
casperbox -c lab.toml up
|
|
113
|
+
casperbox ps # all casperbox containers, from any directory
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
`casperbox` refuses to recreate or remove a container that was created from a different config file.
|
|
117
|
+
|
|
118
|
+
## Commands
|
|
119
|
+
|
|
120
|
+
| Command | Description |
|
|
121
|
+
|---|---|
|
|
122
|
+
| `casperbox list` | List supported toolflow versions |
|
|
123
|
+
| `casperbox init [FILE] [--toolflow VER] [--force]` | Create a config file (default `casperbox.toml`) |
|
|
124
|
+
| `casperbox build [--no-cache]` | Build the image |
|
|
125
|
+
| `casperbox up` | Start (recreate) the container; builds the image if missing |
|
|
126
|
+
| `casperbox down` | Stop and remove the container |
|
|
127
|
+
| `casperbox restart` | `down` + `up` |
|
|
128
|
+
| `casperbox shell` | Open a login shell as the container user |
|
|
129
|
+
| `casperbox status` | Container status and ports |
|
|
130
|
+
| `casperbox logs [-f]` | Container logs |
|
|
131
|
+
| `casperbox config` | Resolved config and podman commands (passwords masked) |
|
|
132
|
+
| `casperbox ps` | List all casperbox containers |
|
|
133
|
+
|
|
134
|
+
`-c FILE` selects the config file (before or after the command); the default is `./casperbox.toml`.
|
|
135
|
+
|
|
136
|
+
## Inside the container
|
|
137
|
+
|
|
138
|
+
```
|
|
139
|
+
~/toolflow/
|
|
140
|
+
├── mlib_devel/ # includes the generated startsg.local
|
|
141
|
+
├── device-tree-xlnx/
|
|
142
|
+
└── src/ # -e dependencies from requirements.txt
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
Shells automatically load Vivado `settings64.sh` and the variables in `startsg.local`, and activate the conda env `casper`.
|
|
146
|
+
Scilab is in `/opt/scilab`; run `scilab` (linked in `~/.local/bin`).
|
|
147
|
+
|
|
148
|
+
> `~/toolflow` is part of the image, not a mount. `down`/`up` recreate the container and
|
|
149
|
+
> discard changes made there; keep your projects under `~/work`.
|
|
150
|
+
|
|
151
|
+
## Networking (pasta)
|
|
152
|
+
|
|
153
|
+
The container uses pasta networking (no bridge network). Ports are forwarded with `-p`,
|
|
154
|
+
the interface is named `eth0`, and the container sees the same IP as the host.
|
|
155
|
+
`container.mac` is applied with pasta's `--ns-mac-addr` (e.g. for a MAC-locked node-locked license);
|
|
156
|
+
the interface exists only in the container's network namespace, so reusing the host NIC's MAC is safe.
|
|
157
|
+
|
|
158
|
+
## After changing the config
|
|
159
|
+
|
|
160
|
+
| Change | Action |
|
|
161
|
+
|---|---|
|
|
162
|
+
| Directories, ports, passwords, MAC, mounts | `casperbox up` |
|
|
163
|
+
| `container.user`, or a different host user (UID/GID changed) | `casperbox build`, then `casperbox up` |
|
|
164
|
+
|
|
165
|
+
## Development
|
|
166
|
+
|
|
167
|
+
```
|
|
168
|
+
src/casperbox/
|
|
169
|
+
├── cli.py Typer commands
|
|
170
|
+
├── config.py casperbox.toml parsing and validation
|
|
171
|
+
├── podman.py podman build/run arguments and container queries
|
|
172
|
+
├── versions.py toolflow versions in assets/versions
|
|
173
|
+
├── templates/ casperbox.toml template
|
|
174
|
+
└── assets/ build context: Dockerfiles, build scripts, rootfs, software.list
|
|
175
|
+
tests/ pytest tests
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
```bash
|
|
179
|
+
uv sync
|
|
180
|
+
uv run pytest
|
|
181
|
+
uv run casperbox --help
|
|
182
|
+
uv tool install -e . # installed casperbox uses this source tree
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
Adding apt packages: add one per line to `assets/common/packages/software.list`, then `casperbox build`.
|
|
186
|
+
|
|
187
|
+
Adding a toolflow version: copy `assets/versions/m2021a` to `assets/versions/<new>`, edit
|
|
188
|
+
`toolflow.toml` (`TOOLFLOW_VERSION` must match the directory name) and the Dockerfile as needed.
|
|
189
|
+
|
|
190
|
+
The shell-based tool (`casper.sh`) is available at tag `v0.1.0`.
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
# casperbox
|
|
2
|
+
|
|
3
|
+
`casperbox` builds and runs CASPER toolflow development containers with rootless podman.
|
|
4
|
+
|
|
5
|
+
The image includes openssh-server, TigerVNC (XFCE desktop), Firefox, Miniconda (conda env),
|
|
6
|
+
mlib_devel, device-tree-xlnx and Scilab. Vivado and the license are mounted from the host.
|
|
7
|
+
|
|
8
|
+
## Supported versions
|
|
9
|
+
|
|
10
|
+
| Version | Base image | Vivado | Python | mlib_devel | device-tree-xlnx | Scilab |
|
|
11
|
+
|---|---|---|---|---|---|---|
|
|
12
|
+
| m2021a | Ubuntu 20.04 | 2021.1 | 3.14 | [liuweiseu/mlib_devel](https://github.com/liuweiseu/mlib_devel) `scilab-dev-ai` | xlnx_rel_v2021.1 | 2024.1.0 |
|
|
13
|
+
|
|
14
|
+
## Host requirements
|
|
15
|
+
|
|
16
|
+
- [uv](https://docs.astral.sh/uv/) (installs without sudo)
|
|
17
|
+
- rootless podman >= 4.4 (run as a regular user) and the passt package (provides pasta)
|
|
18
|
+
- An installed Vivado (version in the table above) and a Xilinx license
|
|
19
|
+
|
|
20
|
+
## Host setup
|
|
21
|
+
|
|
22
|
+
Log in directly (SSH or desktop) as the user that runs podman (do not switch with `su`), then run:
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
loginctl enable-linger "$(id -un)" # keep the user's systemd running, also after logout
|
|
26
|
+
grep "^$(id -un):" /etc/subuid /etc/subgid # should print one line each; otherwise ask an admin
|
|
27
|
+
podman system migrate
|
|
28
|
+
ls /run/user/$(id -u)/bus # the user's systemd bus must exist
|
|
29
|
+
podman run --rm docker.io/library/ubuntu:20.04 true # must succeed with no WARN/ERROR
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
If the last command fails with `sd-bus call: Access denied` (no user systemd session, e.g. after `su`),
|
|
33
|
+
either point the shell at the user's bus:
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
export XDG_RUNTIME_DIR=/run/user/$(id -u)
|
|
37
|
+
export DBUS_SESSION_BUS_ADDRESS=unix:path=$XDG_RUNTIME_DIR/bus
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
or stop podman from using systemd for cgroups:
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
mkdir -p ~/.config/containers
|
|
44
|
+
printf '[engine]\ncgroup_manager = "cgroupfs"\nevents_logger = "file"\n' >> ~/.config/containers/containers.conf
|
|
45
|
+
podman system migrate
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## Install
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
uv tool install git+https://github.com/<owner>/casperbox
|
|
52
|
+
# or from a local clone
|
|
53
|
+
uv tool install ./casperbox
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Upgrade with `uv tool upgrade casperbox`.
|
|
57
|
+
|
|
58
|
+
## Quick start
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
mkdir ~/casper-a && cd ~/casper-a
|
|
62
|
+
casperbox init # creates casperbox.toml
|
|
63
|
+
vi casperbox.toml # set vivado.dir / paths.license_dir / ports
|
|
64
|
+
casperbox up # builds the image on first use, then starts the container
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
Connect:
|
|
68
|
+
|
|
69
|
+
- SSH: `ssh -p <ports.ssh> casper@<host>`, password `container.password` (default `casper`)
|
|
70
|
+
- VNC: `<host>:<ports.vnc>`, password `container.vnc_password` (default `casper`)
|
|
71
|
+
- Local: `casperbox shell`
|
|
72
|
+
|
|
73
|
+
## Configuration
|
|
74
|
+
|
|
75
|
+
`casperbox init` writes a commented `casperbox.toml` (permissions 600, it holds passwords).
|
|
76
|
+
Relative paths in it are relative to the file's directory.
|
|
77
|
+
|
|
78
|
+
| Key | Default | Description |
|
|
79
|
+
|---|---|---|
|
|
80
|
+
| `version` | | Toolflow version (`casperbox list`) |
|
|
81
|
+
| `container.name` | `casper-<version>` | Container name and hostname |
|
|
82
|
+
| `container.user` | `casper` | Container user |
|
|
83
|
+
| `container.password` / `vnc_password` | `casper` | SSH/sudo and VNC (6-8 chars) passwords |
|
|
84
|
+
| `container.mac` | random | MAC of `eth0` |
|
|
85
|
+
| `container.shm_size` / `tz` | `2g` / `UTC` | |
|
|
86
|
+
| `vivado.dir` / `vivado.mount` | / `ro` | Vivado install, mounted at the same path |
|
|
87
|
+
| `paths.license_dir` | `~/.Xilinx` | Mounted at `~/.Xilinx` |
|
|
88
|
+
| `paths.work_dir` | `./work` | Mounted at `~/work` (created if missing) |
|
|
89
|
+
| `ports.bind_address` | `0.0.0.0` | |
|
|
90
|
+
| `ports.ssh` / `ports.vnc` | `2222` / `5901` | Host ports for container 22 / 5901 |
|
|
91
|
+
| `vnc.geometry` | `1920x1080` | |
|
|
92
|
+
| `[[mounts]]` | | Extra mounts: `host`, `container` (`~/` = home), `mode` |
|
|
93
|
+
| `[[extra_ports]]` | | Extra ports: `host`, `container`, `protocol` |
|
|
94
|
+
|
|
95
|
+
Unknown keys and wrong types (e.g. a port written as a string) are reported as errors.
|
|
96
|
+
|
|
97
|
+
### Several containers
|
|
98
|
+
|
|
99
|
+
Each config file is one container. Use another directory or file, and give it its own
|
|
100
|
+
`container.name` and ports:
|
|
101
|
+
|
|
102
|
+
```bash
|
|
103
|
+
casperbox init lab.toml # edit container.name, ports.ssh, ports.vnc
|
|
104
|
+
casperbox -c lab.toml up
|
|
105
|
+
casperbox ps # all casperbox containers, from any directory
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
`casperbox` refuses to recreate or remove a container that was created from a different config file.
|
|
109
|
+
|
|
110
|
+
## Commands
|
|
111
|
+
|
|
112
|
+
| Command | Description |
|
|
113
|
+
|---|---|
|
|
114
|
+
| `casperbox list` | List supported toolflow versions |
|
|
115
|
+
| `casperbox init [FILE] [--toolflow VER] [--force]` | Create a config file (default `casperbox.toml`) |
|
|
116
|
+
| `casperbox build [--no-cache]` | Build the image |
|
|
117
|
+
| `casperbox up` | Start (recreate) the container; builds the image if missing |
|
|
118
|
+
| `casperbox down` | Stop and remove the container |
|
|
119
|
+
| `casperbox restart` | `down` + `up` |
|
|
120
|
+
| `casperbox shell` | Open a login shell as the container user |
|
|
121
|
+
| `casperbox status` | Container status and ports |
|
|
122
|
+
| `casperbox logs [-f]` | Container logs |
|
|
123
|
+
| `casperbox config` | Resolved config and podman commands (passwords masked) |
|
|
124
|
+
| `casperbox ps` | List all casperbox containers |
|
|
125
|
+
|
|
126
|
+
`-c FILE` selects the config file (before or after the command); the default is `./casperbox.toml`.
|
|
127
|
+
|
|
128
|
+
## Inside the container
|
|
129
|
+
|
|
130
|
+
```
|
|
131
|
+
~/toolflow/
|
|
132
|
+
├── mlib_devel/ # includes the generated startsg.local
|
|
133
|
+
├── device-tree-xlnx/
|
|
134
|
+
└── src/ # -e dependencies from requirements.txt
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
Shells automatically load Vivado `settings64.sh` and the variables in `startsg.local`, and activate the conda env `casper`.
|
|
138
|
+
Scilab is in `/opt/scilab`; run `scilab` (linked in `~/.local/bin`).
|
|
139
|
+
|
|
140
|
+
> `~/toolflow` is part of the image, not a mount. `down`/`up` recreate the container and
|
|
141
|
+
> discard changes made there; keep your projects under `~/work`.
|
|
142
|
+
|
|
143
|
+
## Networking (pasta)
|
|
144
|
+
|
|
145
|
+
The container uses pasta networking (no bridge network). Ports are forwarded with `-p`,
|
|
146
|
+
the interface is named `eth0`, and the container sees the same IP as the host.
|
|
147
|
+
`container.mac` is applied with pasta's `--ns-mac-addr` (e.g. for a MAC-locked node-locked license);
|
|
148
|
+
the interface exists only in the container's network namespace, so reusing the host NIC's MAC is safe.
|
|
149
|
+
|
|
150
|
+
## After changing the config
|
|
151
|
+
|
|
152
|
+
| Change | Action |
|
|
153
|
+
|---|---|
|
|
154
|
+
| Directories, ports, passwords, MAC, mounts | `casperbox up` |
|
|
155
|
+
| `container.user`, or a different host user (UID/GID changed) | `casperbox build`, then `casperbox up` |
|
|
156
|
+
|
|
157
|
+
## Development
|
|
158
|
+
|
|
159
|
+
```
|
|
160
|
+
src/casperbox/
|
|
161
|
+
├── cli.py Typer commands
|
|
162
|
+
├── config.py casperbox.toml parsing and validation
|
|
163
|
+
├── podman.py podman build/run arguments and container queries
|
|
164
|
+
├── versions.py toolflow versions in assets/versions
|
|
165
|
+
├── templates/ casperbox.toml template
|
|
166
|
+
└── assets/ build context: Dockerfiles, build scripts, rootfs, software.list
|
|
167
|
+
tests/ pytest tests
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
```bash
|
|
171
|
+
uv sync
|
|
172
|
+
uv run pytest
|
|
173
|
+
uv run casperbox --help
|
|
174
|
+
uv tool install -e . # installed casperbox uses this source tree
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
Adding apt packages: add one per line to `assets/common/packages/software.list`, then `casperbox build`.
|
|
178
|
+
|
|
179
|
+
Adding a toolflow version: copy `assets/versions/m2021a` to `assets/versions/<new>`, edit
|
|
180
|
+
`toolflow.toml` (`TOOLFLOW_VERSION` must match the directory name) and the Dockerfile as needed.
|
|
181
|
+
|
|
182
|
+
The shell-based tool (`casper.sh`) is available at tag `v0.1.0`.
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "casperbox"
|
|
3
|
+
version = "0.2.1"
|
|
4
|
+
description = "Build and run CASPER toolflow development containers with rootless podman"
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
requires-python = ">=3.11"
|
|
7
|
+
dependencies = [
|
|
8
|
+
"typer>=0.12",
|
|
9
|
+
]
|
|
10
|
+
|
|
11
|
+
[project.scripts]
|
|
12
|
+
casperbox = "casperbox.cli:main"
|
|
13
|
+
|
|
14
|
+
[dependency-groups]
|
|
15
|
+
dev = [
|
|
16
|
+
"pytest>=8",
|
|
17
|
+
]
|
|
18
|
+
|
|
19
|
+
[build-system]
|
|
20
|
+
requires = ["hatchling"]
|
|
21
|
+
build-backend = "hatchling.build"
|
|
22
|
+
|
|
23
|
+
[tool.hatch.build.targets.wheel]
|
|
24
|
+
packages = ["src/casperbox"]
|
|
25
|
+
|
|
26
|
+
[tool.pytest.ini_options]
|
|
27
|
+
testpaths = ["tests"]
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
"""casperbox: build and run CASPER toolflow development containers with rootless podman."""
|
|
2
|
+
|
|
3
|
+
from importlib.metadata import PackageNotFoundError, version
|
|
4
|
+
|
|
5
|
+
try:
|
|
6
|
+
__version__ = version("casperbox")
|
|
7
|
+
except PackageNotFoundError: # running from a source tree without installation
|
|
8
|
+
__version__ = "0+unknown"
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# apt packages installed into the image by common/scripts/install_base.sh
|
|
2
|
+
# One package per line; text after # is ignored.
|
|
3
|
+
|
|
4
|
+
# ---- basic tools ----
|
|
5
|
+
ca-certificates
|
|
6
|
+
curl
|
|
7
|
+
wget
|
|
8
|
+
git
|
|
9
|
+
sudo
|
|
10
|
+
locales
|
|
11
|
+
tzdata
|
|
12
|
+
bzip2
|
|
13
|
+
xz-utils
|
|
14
|
+
unzip
|
|
15
|
+
file
|
|
16
|
+
less
|
|
17
|
+
vim
|
|
18
|
+
nano
|
|
19
|
+
procps
|
|
20
|
+
psmisc
|
|
21
|
+
iproute2
|
|
22
|
+
iputils-ping
|
|
23
|
+
net-tools
|
|
24
|
+
lsb-release
|
|
25
|
+
|
|
26
|
+
# ---- build tools ----
|
|
27
|
+
build-essential
|
|
28
|
+
make
|
|
29
|
+
gcc
|
|
30
|
+
g++
|
|
31
|
+
device-tree-compiler
|
|
32
|
+
|
|
33
|
+
# ---- ssh / vnc / desktop ----
|
|
34
|
+
openssh-server
|
|
35
|
+
tigervnc-standalone-server
|
|
36
|
+
tigervnc-common
|
|
37
|
+
xfce4
|
|
38
|
+
xfce4-terminal
|
|
39
|
+
dbus-x11
|
|
40
|
+
x11-xserver-utils
|
|
41
|
+
x11-utils
|
|
42
|
+
xfonts-base
|
|
43
|
+
fonts-dejavu
|
|
44
|
+
firefox
|
|
45
|
+
|
|
46
|
+
# ---- Vivado runtime dependencies ----
|
|
47
|
+
libtinfo5
|
|
48
|
+
libncurses5
|
|
49
|
+
libx11-6
|
|
50
|
+
libxext6
|
|
51
|
+
libxrender1
|
|
52
|
+
libxtst6
|
|
53
|
+
libxi6
|
|
54
|
+
libxft2
|
|
55
|
+
libxrandr2
|
|
56
|
+
libxcursor1
|
|
57
|
+
libxinerama1
|
|
58
|
+
libsm6
|
|
59
|
+
libice6
|
|
60
|
+
libfreetype6
|
|
61
|
+
libfontconfig1
|
|
62
|
+
libglib2.0-0
|
|
63
|
+
libgtk2.0-0
|
|
64
|
+
libgtk-3-0
|
|
65
|
+
libcanberra-gtk-module
|
|
66
|
+
libcanberra-gtk3-module
|
|
67
|
+
libasound2
|
|
68
|
+
libgl1
|
|
69
|
+
libglu1-mesa
|
|
70
|
+
graphviz
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# shellcheck shell=bash
|
|
2
|
+
# CASPER toolflow environment: Vivado, mlib_devel (startsg.local), conda env
|
|
3
|
+
# Sourced by /etc/profile (login shells) and ~/.bashrc (interactive shells); safe to source repeatedly.
|
|
4
|
+
|
|
5
|
+
# Vivado settings64.sh etc. require bash
|
|
6
|
+
[ -n "${BASH_VERSION:-}" ] || return 0
|
|
7
|
+
[ -r /etc/casper/toolflow.env ] || return 0
|
|
8
|
+
|
|
9
|
+
set -a
|
|
10
|
+
# shellcheck disable=SC1091
|
|
11
|
+
. /etc/casper/toolflow.env
|
|
12
|
+
# Generated at container startup: VIVADO_DIR / XILINX_PATH / COMPOSER_PATH
|
|
13
|
+
# shellcheck disable=SC1091
|
|
14
|
+
[ -r /etc/casper/runtime.env ] && . /etc/casper/runtime.env
|
|
15
|
+
set +a
|
|
16
|
+
|
|
17
|
+
export MLIB_DEVEL_PATH="${CASPER_TOOLFLOW_DIR}/mlib_devel"
|
|
18
|
+
|
|
19
|
+
# ~/.local/bin (scilab etc. are linked here)
|
|
20
|
+
case ":${PATH}:" in
|
|
21
|
+
*":${HOME}/.local/bin:"*) ;;
|
|
22
|
+
*) export PATH="${HOME}/.local/bin:${PATH}" ;;
|
|
23
|
+
esac
|
|
24
|
+
|
|
25
|
+
# mlib_devel local config (XILINX_PATH / JASPER_BACKEND / XLNX_DT_REPO_PATH etc.)
|
|
26
|
+
if [ -r "${MLIB_DEVEL_PATH}/startsg.local" ]; then
|
|
27
|
+
# shellcheck disable=SC1091
|
|
28
|
+
. "${MLIB_DEVEL_PATH}/startsg.local"
|
|
29
|
+
fi
|
|
30
|
+
|
|
31
|
+
# Vivado (load once to avoid growing PATH repeatedly)
|
|
32
|
+
_casper_vivado_settings="${XILINX_PATH:-}/settings64.sh"
|
|
33
|
+
if [ -z "${CASPER_VIVADO_LOADED:-}" ] && [ -n "${XILINX_PATH:-}" ] && [ -r "${_casper_vivado_settings}" ]; then
|
|
34
|
+
# shellcheck disable=SC1090
|
|
35
|
+
. "${_casper_vivado_settings}" >/dev/null
|
|
36
|
+
export CASPER_VIVADO_LOADED=1
|
|
37
|
+
fi
|
|
38
|
+
unset _casper_vivado_settings
|
|
39
|
+
|
|
40
|
+
# conda: activate the toolflow python env by default (CONDA_ENV_NAME, e.g. casper)
|
|
41
|
+
# Every shell must define the conda function and run activate:
|
|
42
|
+
# - environment variables are inherited from the parent, but the conda function and PS1 are not;
|
|
43
|
+
# - if the env is already active, conda only reactivates (no stacking) and restores the "(casper)" prompt.
|
|
44
|
+
if [ -r /opt/conda/etc/profile.d/conda.sh ]; then
|
|
45
|
+
# shellcheck disable=SC1091
|
|
46
|
+
. /opt/conda/etc/profile.d/conda.sh
|
|
47
|
+
conda activate "${CONDA_ENV_NAME}"
|
|
48
|
+
fi
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Container entrypoint (runs as root):
|
|
3
|
+
# 1. Set the user password from CONTAINER_PWD and the VNC password from VNC_PASSWORD
|
|
4
|
+
# 2. Start sshd (22) and vncserver :1 (5901)
|
|
5
|
+
# 3. Stay in the foreground and clean up on stop signals
|
|
6
|
+
set -euo pipefail
|
|
7
|
+
|
|
8
|
+
log() { echo "[entrypoint] $*"; }
|
|
9
|
+
|
|
10
|
+
# shellcheck disable=SC1091
|
|
11
|
+
. /etc/casper/toolflow.env
|
|
12
|
+
user="${CASPER_USER}"
|
|
13
|
+
group="$(id -gn "${user}")"
|
|
14
|
+
home_dir="/home/${user}"
|
|
15
|
+
|
|
16
|
+
: "${CONTAINER_PWD:?CONTAINER_PWD is not set}"
|
|
17
|
+
VNC_PASSWORD="${VNC_PASSWORD:-${CONTAINER_PWD}}"
|
|
18
|
+
VNC_GEOMETRY="${VNC_GEOMETRY:-1920x1080}"
|
|
19
|
+
if [[ ! "${VNC_GEOMETRY}" =~ ^[0-9]+x[0-9]+$ ]]; then
|
|
20
|
+
log "Invalid VNC_GEOMETRY: ${VNC_GEOMETRY}, using 1920x1080"
|
|
21
|
+
VNC_GEOMETRY=1920x1080
|
|
22
|
+
fi
|
|
23
|
+
|
|
24
|
+
# ---- Passwords ----
|
|
25
|
+
log "Setting password for user ${user}"
|
|
26
|
+
printf '%s:%s\n' "${user}" "${CONTAINER_PWD}" | chpasswd
|
|
27
|
+
|
|
28
|
+
log "Setting VNC password"
|
|
29
|
+
install -d -m 700 -o "${user}" -g "${group}" "${home_dir}/.vnc"
|
|
30
|
+
printf '%s\n' "${VNC_PASSWORD}" | vncpasswd -f > "${home_dir}/.vnc/passwd"
|
|
31
|
+
chown "${user}:${group}" "${home_dir}/.vnc/passwd"
|
|
32
|
+
chmod 600 "${home_dir}/.vnc/passwd"
|
|
33
|
+
if [[ ! -f "${home_dir}/.vnc/xstartup" ]]; then
|
|
34
|
+
install -m 755 -o "${user}" -g "${group}" /opt/casper/vnc/xstartup "${home_dir}/.vnc/xstartup"
|
|
35
|
+
fi
|
|
36
|
+
unset CONTAINER_PWD VNC_PASSWORD
|
|
37
|
+
|
|
38
|
+
# ---- Vivado paths (mounted at the same path as on the host) ----
|
|
39
|
+
# Two layouts are supported: <VIVADO_DIR>/Vivado/<version>/settings64.sh or <VIVADO_DIR>/settings64.sh
|
|
40
|
+
: "${VIVADO_DIR:?VIVADO_DIR is not set}"
|
|
41
|
+
xilinx_path=""
|
|
42
|
+
composer_path=""
|
|
43
|
+
if [[ -r "${VIVADO_DIR}/Vivado/${VIVADO_VERSION}/settings64.sh" ]]; then
|
|
44
|
+
xilinx_path="${VIVADO_DIR}/Vivado/${VIVADO_VERSION}"
|
|
45
|
+
[[ -d "${VIVADO_DIR}/Model_Composer/${VIVADO_VERSION}" ]] \
|
|
46
|
+
&& composer_path="${VIVADO_DIR}/Model_Composer/${VIVADO_VERSION}"
|
|
47
|
+
elif [[ -r "${VIVADO_DIR}/settings64.sh" ]]; then
|
|
48
|
+
xilinx_path="${VIVADO_DIR}"
|
|
49
|
+
else
|
|
50
|
+
log "Warning: settings64.sh for Vivado ${VIVADO_VERSION} not found under ${VIVADO_DIR}, please check VIVADO_DIR"
|
|
51
|
+
fi
|
|
52
|
+
log "Vivado: ${xilinx_path:-<not found>}"
|
|
53
|
+
{
|
|
54
|
+
echo "# Generated by the entrypoint at container startup"
|
|
55
|
+
printf "VIVADO_DIR='%s'\n" "${VIVADO_DIR}"
|
|
56
|
+
printf "XILINX_PATH='%s'\n" "${xilinx_path}"
|
|
57
|
+
printf "COMPOSER_PATH='%s'\n" "${composer_path}"
|
|
58
|
+
} > /etc/casper/runtime.env
|
|
59
|
+
chmod 644 /etc/casper/runtime.env
|
|
60
|
+
|
|
61
|
+
# ---- sshd ----
|
|
62
|
+
ssh-keygen -A >/dev/null
|
|
63
|
+
mkdir -p /run/sshd
|
|
64
|
+
log "Starting sshd"
|
|
65
|
+
/usr/sbin/sshd
|
|
66
|
+
|
|
67
|
+
# ---- vncserver ----
|
|
68
|
+
rm -f /tmp/.X1-lock /tmp/.X11-unix/X1
|
|
69
|
+
log "Starting vncserver :1 (${VNC_GEOMETRY})"
|
|
70
|
+
su - "${user}" -c "vncserver :1 -geometry ${VNC_GEOMETRY} -depth 24 -localhost no -SecurityTypes VncAuth"
|
|
71
|
+
|
|
72
|
+
cleanup() {
|
|
73
|
+
log "Stopping services"
|
|
74
|
+
su - "${user}" -c "vncserver -kill :1" >/dev/null 2>&1 || true
|
|
75
|
+
pkill -TERM -x sshd 2>/dev/null || true
|
|
76
|
+
exit 0
|
|
77
|
+
}
|
|
78
|
+
trap cleanup TERM INT
|
|
79
|
+
|
|
80
|
+
log "Container ready (toolflow ${TOOLFLOW_VERSION})"
|
|
81
|
+
sleep infinity &
|
|
82
|
+
wait $!
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Configure mlib_devel (runs as the container user):
|
|
3
|
+
# 1. Clone mlib_devel and device-tree-xlnx into ~/toolflow
|
|
4
|
+
# 2. Install mlib_devel's python dependencies into the conda env
|
|
5
|
+
# 3. Generate mlib_devel/startsg.local
|
|
6
|
+
set -euo pipefail
|
|
7
|
+
|
|
8
|
+
: "${MLIB_DEVEL_REPO:?}" "${MLIB_DEVEL_BRANCH:?}"
|
|
9
|
+
: "${DEVICE_TREE_XLNX_REPO:?}" "${DEVICE_TREE_XLNX_BRANCH:?}"
|
|
10
|
+
: "${CONDA_ENV_NAME:?}" "${VIVADO_VERSION:?}"
|
|
11
|
+
CONDA_DIR="${CONDA_DIR:-/opt/conda}"
|
|
12
|
+
GIT_CLONE_DEPTH="${GIT_CLONE_DEPTH:-1}"
|
|
13
|
+
|
|
14
|
+
toolflow_dir="${HOME}/toolflow"
|
|
15
|
+
mlib_dir="${toolflow_dir}/mlib_devel"
|
|
16
|
+
dt_dir="${toolflow_dir}/device-tree-xlnx"
|
|
17
|
+
|
|
18
|
+
depth_args=()
|
|
19
|
+
if [[ "${GIT_CLONE_DEPTH}" != "0" ]]; then
|
|
20
|
+
depth_args=(--depth "${GIT_CLONE_DEPTH}")
|
|
21
|
+
fi
|
|
22
|
+
|
|
23
|
+
mkdir -p "${toolflow_dir}"
|
|
24
|
+
|
|
25
|
+
echo ">>> Cloning mlib_devel (${MLIB_DEVEL_BRANCH})"
|
|
26
|
+
git clone "${depth_args[@]}" --single-branch --branch "${MLIB_DEVEL_BRANCH}" \
|
|
27
|
+
"${MLIB_DEVEL_REPO}" "${mlib_dir}"
|
|
28
|
+
|
|
29
|
+
echo ">>> Cloning device-tree-xlnx (${DEVICE_TREE_XLNX_BRANCH})"
|
|
30
|
+
git clone "${depth_args[@]}" --single-branch --branch "${DEVICE_TREE_XLNX_BRANCH}" \
|
|
31
|
+
"${DEVICE_TREE_XLNX_REPO}" "${dt_dir}"
|
|
32
|
+
|
|
33
|
+
echo ">>> Installing mlib_devel dependencies into conda env ${CONDA_ENV_NAME}"
|
|
34
|
+
# shellcheck disable=SC1091
|
|
35
|
+
source "${CONDA_DIR}/etc/profile.d/conda.sh"
|
|
36
|
+
conda activate "${CONDA_ENV_NAME}"
|
|
37
|
+
python -m pip install --no-cache-dir --upgrade pip
|
|
38
|
+
# requirements.txt has -e git+... dependencies; put their sources in ~/toolflow/src
|
|
39
|
+
(cd "${mlib_dir}" && python -m pip install --no-cache-dir --src "${toolflow_dir}/src" -r requirements.txt)
|
|
40
|
+
|
|
41
|
+
echo ">>> Generating ${mlib_dir}/startsg.local"
|
|
42
|
+
cat > "${mlib_dir}/startsg.local" <<EOF
|
|
43
|
+
# Generated by casperbox at image build time
|
|
44
|
+
# Vivado is mounted at the host path; the entrypoint writes /etc/casper/runtime.env at container startup
|
|
45
|
+
[ -r /etc/casper/runtime.env ] && . /etc/casper/runtime.env
|
|
46
|
+
export XILINX_PATH COMPOSER_PATH
|
|
47
|
+
export PLATFORM=lin64
|
|
48
|
+
export JASPER_BACKEND=vivado
|
|
49
|
+
export XLNX_DT_REPO_PATH=${dt_dir}
|
|
50
|
+
#export MATLAB_PATH=/path/to/matlab
|
|
51
|
+
# python: shells activate conda env ${CONDA_ENV_NAME} automatically via /etc/profile.d/casper.sh
|
|
52
|
+
EOF
|
|
53
|
+
|
|
54
|
+
echo "mlib_devel configured: ${mlib_dir}"
|