392 lines
18 KiB
Markdown
392 lines
18 KiB
Markdown
# UniLoader setup (Linux)
|
||
|
||
UniLoader imports component ZIPs or folders into global KiCad libraries or a
|
||
portable project. It watches downloads during your graphical login session and
|
||
asks where to import each component. It creates missing libraries and registers
|
||
them in the selected scope automatically.
|
||
|
||
## Requirements and installation
|
||
|
||
Install Rust 1.95 or newer and your distribution's
|
||
C build tools and `pkg-config`. Desktop dialogs use Rust
|
||
[egui/eframe](https://docs.rs/eframe/latest/eframe/) with the OpenGL renderer and
|
||
both Wayland and X11 support. File browsing uses
|
||
[rfd's XDG desktop portal backend](https://docs.rs/rfd/latest/rfd/#linux--bsd-backends).
|
||
Install `xdg-desktop-portal` and the backend appropriate for your desktop
|
||
(for example, KDE or GTK). A working OpenGL driver, display session and session
|
||
D-Bus are required. `notify-send` is optional for desktop notifications.
|
||
|
||
The UI is compiled into `uniloader`; there are no companion scripts to install.
|
||
The watcher starts another instance of the same executable internally for each
|
||
dialog, keeping the window event loop on its own main thread.
|
||
|
||
On Debian/Ubuntu, a starting set of build packages is `build-essential pkg-config
|
||
libxcb-render0-dev libxcb-shape0-dev libxcb-xfixes0-dev libxkbcommon-dev
|
||
libwayland-dev`; other distributions provide corresponding development packages.
|
||
For optional notifications install `libnotify-bin` on Debian/Ubuntu or `libnotify`
|
||
on Arch Linux. The portal backend can bring its own toolkit dependencies; UniLoader
|
||
does not link a GTK UI. See the [upstream eframe build notes](https://github.com/emilk/eframe_template/#testing-locally)
|
||
if compilation reports a missing system library.
|
||
|
||
Build from the repository directory:
|
||
|
||
```sh
|
||
cargo build --release --locked
|
||
install -Dm755 target/release/uniloader ~/.local/bin/uniloader
|
||
~/.local/bin/uniloader --help
|
||
```
|
||
|
||
Add `~/.local/bin` to your shell's `PATH` to use the shorter `uniloader` command.
|
||
Do not run the importer as root.
|
||
|
||
The importer targets KiCad's modern `.kicad_sym`, `.kicad_mod` and `.kicad_pro`
|
||
formats. It preserves source format versions; the installed KiCad must support
|
||
those versions. Legacy `.lib` symbol conversion is not included. Verify your
|
||
actual component in KiCad before relying on a library for a board design.
|
||
|
||
This release discovers possible open projects by inspecting Linux KiCad process
|
||
arguments and working directories. These are **suggestions**, not an authoritative
|
||
active-window selection: startup arguments can be stale, editor navigation can
|
||
change documents, and some launchers hide the file argument. IPC discovery is a
|
||
follow-up; no IPC configuration is required for this release. Always check the
|
||
project path in the destination dialog, or use Browse / `--project`.
|
||
|
||
## Configuration
|
||
|
||
The default configuration is `${XDG_CONFIG_HOME:-~/.config}/uniloader/config.toml`.
|
||
A missing configuration is generated with defaults on first launch. You can
|
||
select another file with `--config /absolute/path/config.toml`. Existing
|
||
`[libraries].path` and `[options]` settings remain supported. `~` expands in paths;
|
||
relative configuration paths resolve from the process working directory, so use
|
||
absolute or home-relative paths for a service.
|
||
|
||
A minimal setup is:
|
||
|
||
```toml
|
||
[libraries]
|
||
path = "~/KiCad/libraries"
|
||
# Select your installed KiCad version for global library registration:
|
||
kicad_config = "~/.config/kicad/9.0"
|
||
```
|
||
|
||
Use your actual KiCad version directory. When a single installed configuration
|
||
can be identified, UniLoader can discover it. If none or several are found,
|
||
set `kicad_config` explicitly before importing globally. Project imports create
|
||
project-local tables and do not require a global table.
|
||
|
||
The complete example is in `config/config_full.toml`. Available settings are:
|
||
|
||
```toml
|
||
[libraries]
|
||
path = "~/KiCad/libraries"
|
||
kicad_config = "~/.config/kicad/9.0"
|
||
search_paths = []
|
||
model_search_paths = ["~/KiCad/models"]
|
||
|
||
# Optional KiCad variables not already supplied by your environment:
|
||
[libraries.variables]
|
||
# KICAD9_3DMODEL_DIR = "/usr/share/kicad/3dmodels"
|
||
|
||
[options]
|
||
symbols = true
|
||
footprints = true
|
||
models = true
|
||
preserve_source = true
|
||
|
||
[watch]
|
||
directories = ["~/Downloads"]
|
||
settle_seconds = 2
|
||
retry_seconds = 60
|
||
|
||
[destination]
|
||
policy = "ask" # ask, global, project
|
||
# project = "/absolute/path/Board/Board.kicad_pro"
|
||
portable = true
|
||
|
||
[matching]
|
||
enabled = true
|
||
exact = "reuse" # reuse, ask
|
||
ambiguous = "ask" # ask, separate, skip
|
||
# Pad-position comparison tolerance, in millimetres:
|
||
tolerance = 0.15
|
||
|
||
[ui]
|
||
enabled = true
|
||
```
|
||
|
||
`destination.policy = "project"` requires a fixed `project` path. A fixed target
|
||
can be used when KiCad is closed. The default `ask` offers detected projects,
|
||
Global and Browse. Remembering a choice applies to the running session; restart
|
||
UniLoader to clear it. Footprint reuse mappings are persisted by content; to clear
|
||
those mappings, stop UniLoader and remove only the content-mapping JSON files in its data
|
||
directory’s `decisions/` subdirectory, then restart. Explicit fixed configuration persists until edited.
|
||
|
||
Matching searches effective registered libraries and configured `search_paths`.
|
||
Do not add an enormous recursive root such as your entire home directory.
|
||
Missing/unreadable search locations are reported rather than silently treated
|
||
as proof that no duplicate exists. Exact footprint reuse is conservative;
|
||
similar footprints or conflicting names prompt for comparison. The preview
|
||
shows both footprints at the same scale, numbered pads, bounds and differences.
|
||
It approximates some shapes and omits text, drill holes and 3D geometry; the
|
||
window reports limitations. Inspect source files in KiCad when necessary.
|
||
`ambiguous = "separate"` or `"skip"` permits an explicit noninteractive policy;
|
||
the default keeps unanswered choices pending.
|
||
|
||
## Foreground smoke test
|
||
|
||
Start with an expendable test project and a known downloaded component:
|
||
|
||
```sh
|
||
uniloader discover
|
||
uniloader import /path/to/component.zip --project /path/to/Test/Test.kicad_pro --dry-run
|
||
uniloader import /path/to/component.zip --project /path/to/Test/Test.kicad_pro
|
||
uniloader import /path/to/component.zip --global --dry-run
|
||
uniloader watch
|
||
```
|
||
|
||
A manual import also accepts an extracted component folder. No-argument startup
|
||
runs the watcher. Dry run reports choices and intended library changes without
|
||
writing libraries; unresolved decisions may need an interactive import.
|
||
Use `--noninteractive` to avoid opening dialogs. A pending choice is not consent.
|
||
|
||
Project imports create `libraries/UniLoader.kicad_sym`,
|
||
`libraries/UniLoader.pretty/`, and model storage as needed, and merge registration
|
||
entries into `sym-lib-table` and `fp-lib-table` beside the `.kicad_pro` file.
|
||
Project registration uses the nickname `UniLoader_Local`; global registration uses
|
||
`UniLoader_Global`. Library filenames remain `UniLoader.kicad_sym` and
|
||
`UniLoader.pretty` in both scopes. Project paths use `${KIPRJMOD}`. Portable mode copies selected external footprints
|
||
and available referenced models into the project. Global imports use the
|
||
configured library root and register entries in the selected KiCad configuration.
|
||
Existing unrelated table entries are preserved. Existing schematic and PCB
|
||
instances are not automatically replaced by a library import.
|
||
|
||
Open the imported symbol, footprint and model in KiCad. Refresh/reopen the
|
||
library browser or editor if KiCad has cached the table/library. For an existing
|
||
placed component, use KiCad's normal update-from-library operation when you want
|
||
it updated. Copy the test project to another directory and verify its imported
|
||
assets again to check portability.
|
||
|
||
The watcher handles component ZIP downloads (including common SamacSys,
|
||
UltraLibrarian and SnapMagic layouts); use a manual folder import for extracted
|
||
assets. Source archives are preserved by default. Incomplete or invalid ZIPs
|
||
are retried for the configured period, then remain recoverable rather than
|
||
stopping subsequent downloads.
|
||
|
||
## Library health and repair (v0.2.3)
|
||
|
||
Doctor includes the v0.2.2 nickname migration and now checks and rebuilds managed
|
||
library infrastructure, including when the global library root has been deleted.
|
||
|
||
Before applying repairs, close KiCad and stop the watcher:
|
||
|
||
```sh
|
||
systemctl --user stop uniloader.service
|
||
uniloader doctor --global
|
||
uniloader doctor --global --fix
|
||
uniloader doctor --project /path/to/Board/Board.kicad_pro
|
||
uniloader doctor --project /path/to/Board/Board.kicad_pro --fix
|
||
systemctl --user start uniloader.service
|
||
```
|
||
|
||
Without `--fix`, doctor previews directories and files it would create or repair.
|
||
`--global` checks the configured global tables, managed symbol library and managed
|
||
footprints/models. `--project` checks those plus the selected project's libraries,
|
||
tables, and `.kicad_sch` and `.kicad_pcb` files recursively inside its directory
|
||
(including subsheets). Run it for every existing project; projects elsewhere are not automatically discovered
|
||
or modified. External subsheets must be checked separately. Set
|
||
`libraries.kicad_config` to the correct version directory when needed: doctor
|
||
requires an explicit or uniquely detected KiCad configuration for both scopes.
|
||
|
||
Doctor recreates missing managed roots, `UniLoader.pretty/` and `models/`
|
||
directories, valid empty `UniLoader.kicad_sym` files, and missing symbol/footprint
|
||
tables or managed entries. Existing malformed managed libraries, tables, duplicate
|
||
aliases, and wrong file/directory types block the repair plan before it is applied;
|
||
corrupt content is not replaced with an empty library.
|
||
|
||
Doctor identifies managed registrations by their resolved library paths. Stale
|
||
paths can also be repaired when the registration carries the UniLoader nickname
|
||
and `Imported by UniLoader` description. It points owned entries at the configured
|
||
global root or portable project paths, restores the KiCad type, and enables owned
|
||
entries that were disabled. It preserves unrelated registrations and metadata,
|
||
and refuses an occupied target nickname. An unrelated entry using our nickname
|
||
without ownership evidence is reported for manual resolution.
|
||
It updates symbol footprint properties, schematic library IDs and cached symbol
|
||
IDs, and placed PCB footprint IDs according to the original project-over-global
|
||
resolution. An old ambiguous ID keeps that original resolution; doctor cannot
|
||
recover a different intended library. Asset filenames stay the same. Managed
|
||
footprints are parsed and their model paths repaired using the same conservative
|
||
candidate matching as import: a unique match or identical-content candidates
|
||
can be copied/reused in managed model storage. Missing or ambiguous models remain
|
||
unchanged and are reported; transforms and embedded model references are kept.
|
||
Changed S-expression files are reserialized, so whitespace may change.
|
||
|
||
Doctor checks active KiCad registrations for unresolved path variables, missing
|
||
paths, wrong types and readability; validates managed symbol/footprint files; and
|
||
checks managed symbol bindings and project symbol/footprint references against
|
||
the effective global/project registrations and actual components. Missing
|
||
configured footprint/model search roots are reported. Third-party registrations
|
||
are checked but not repointed, recreated or removed. Disabled third-party entries
|
||
and non-KiCad plugins are excluded from reference resolution. It does not audit
|
||
the watcher service or recover component content from download history.
|
||
|
||
Recreating an empty library restores its structure, not deleted symbols,
|
||
footprints or models. Restore those from your backups or deliberately reimport
|
||
the original component with `uniloader import SOURCE --global --force` (or
|
||
`--project FILE --force`). A normal import may skip a previously completed source.
|
||
Doctor reports remaining missing components and models rather than fabricating
|
||
placeholders. It exits nonzero for unresolved findings, including when `--fix`
|
||
has successfully applied the safe portion of the plan. Preview also exits nonzero
|
||
for unresolved findings. No unresolved findings means only that the checked
|
||
scope passed, not that missing historical components were recovered.
|
||
|
||
Repairs use the import writer lock, atomic file replacement, and the normal
|
||
backup/history mechanism. The command prints backup paths under
|
||
`${XDG_DATA_HOME:-~/.local/share}/uniloader/backups/`; `uniloader pending --all`
|
||
also lists changed files and backups. Exact old nicknames (including collision
|
||
suffixes) are retained under `uniloader/nickname-migrations/` in the same data
|
||
root so later project repairs can update global references. Keep this migration
|
||
history until all projects are repaired. Repeated repairs leave unchanged files
|
||
alone. All files are parsed and collisions checked before writing, but a disk
|
||
failure can still interrupt a multi-file repair; restore the listed backups if
|
||
needed. Reopen KiCad after repair to reload its cached tables.
|
||
|
||
Imports into a destination still using an old managed nickname stop with a doctor
|
||
instruction. Repair that destination before resuming imports.
|
||
|
||
## 3D models and broken paths
|
||
|
||
STEP (`.step`/`.stp`) and VRML (`.wrl`) models are copied when referenced by an
|
||
imported footprint. Resolution tries existing paths, bundle files and configured
|
||
model search roots. Windows/provider absolute paths and obsolete extraction
|
||
roots can be repaired through unique relative suffixes or filenames. Different
|
||
matching model files require a selection rather than an arbitrary choice.
|
||
Model transforms remain attached to the reference. Project references point to
|
||
`${KIPRJMOD}/libraries/models/...`; global references use absolute storage paths.
|
||
|
||
Missing models leave the usable component import available with warnings and
|
||
retain the original reference. Such an import is not fully portable. Adding the
|
||
missing model to a search root and deliberately reimporting with `--force` can
|
||
repair the dependency. Disabling `options.models` may also leave external paths.
|
||
UniLoader does not download models or convert CAD formats.
|
||
|
||
## Pending imports and recovery
|
||
|
||
```sh
|
||
uniloader pending
|
||
uniloader pending --all # include completed/skipped imports
|
||
uniloader retry IMPORT_ID
|
||
uniloader retry IMPORT_ID --dry-run --noninteractive
|
||
```
|
||
|
||
Closing a dialog or choosing Later leaves a pending import; it does not choose
|
||
Global, overwrite a file, or guess a model. Retry after fixing the configuration,
|
||
restoring the display environment or obtaining a missing asset. Other downloads
|
||
can continue through the queue. `--force` deliberately reimports a completed
|
||
source when you need to revisit it.
|
||
|
||
Import state/history lives beneath `${XDG_DATA_HOME:-~/.local/share}/uniloader`;
|
||
temporary extraction uses `${XDG_CACHE_HOME:-~/.cache}/uniloader`.
|
||
Changed files have recovery backups recorded by the import result/history.
|
||
Stop the watcher before manually restoring a backup, compare the current file
|
||
with the backup, and copy back only the intended version. A backup may predate
|
||
later manual edits; do not blindly restore every file. Restart KiCad or refresh
|
||
its libraries afterwards. Automatic undo is not included.
|
||
|
||
## Run continuously with a systemd user unit
|
||
|
||
First verify the foreground test above, then install the shipped service:
|
||
|
||
```sh
|
||
install -Dm644 systemd/uniloader.service ~/.config/systemd/user/uniloader.service
|
||
systemctl --user daemon-reload
|
||
systemctl --user enable --now uniloader.service
|
||
systemctl --user status uniloader.service
|
||
journalctl --user -u uniloader.service -f
|
||
```
|
||
|
||
The service uses `%h/.local/bin/uniloader watch` and the default configuration.
|
||
It starts with `graphical-session.target`, stops with that target, and restarts
|
||
after unexpected failure. “Always running” means while logged into your desktop.
|
||
To use a nondefault config, run `systemctl --user edit uniloader.service` and add:
|
||
|
||
```ini
|
||
[Service]
|
||
ExecStart=
|
||
ExecStart=%h/.local/bin/uniloader --config %h/.config/uniloader/work.toml watch
|
||
```
|
||
|
||
Then reload/restart:
|
||
|
||
```sh
|
||
systemctl --user daemon-reload
|
||
systemctl --user restart uniloader.service
|
||
```
|
||
|
||
### Display/session troubleshooting
|
||
|
||
If imports remain pending and logs say dialogs are unavailable, try a manual
|
||
interactive import from your desktop terminal and check the reported display or
|
||
OpenGL error. Check the service manager environment with
|
||
`systemctl --user show-environment`; it needs the real session's display variables
|
||
and session D-Bus. File browsing also needs a running desktop portal and a backend
|
||
that supports file selection; check `journalctl --user -u xdg-desktop-portal` if
|
||
Browse fails. Never invent a `DISPLAY=:0` or copy another user's Xauthority.
|
||
|
||
Some window managers/compositors do not activate `graphical-session.target` or
|
||
import display variables. Put this shell hook in your compositor's session-start
|
||
configuration, after the graphical session exists:
|
||
|
||
```sh
|
||
#!/bin/sh
|
||
for variable in DISPLAY WAYLAND_DISPLAY XAUTHORITY XDG_RUNTIME_DIR XDG_CURRENT_DESKTOP XDG_SESSION_TYPE DBUS_SESSION_BUS_ADDRESS; do
|
||
if printenv "$variable" >/dev/null 2>&1; then
|
||
systemctl --user import-environment "$variable"
|
||
fi
|
||
done
|
||
systemctl --user start uniloader.service
|
||
```
|
||
|
||
If the service was already running with a stale environment, restart it after
|
||
importing variables, then retry pending imports. For compositors without target
|
||
lifecycle integration, add `systemctl --user stop uniloader.service` to your
|
||
session-exit hook. Enabling a unit alone cannot supply a missing GUI session.
|
||
The initial environment comes from the session startup hook, not a hardcoded
|
||
service `Environment=` line.
|
||
|
||
Lingering (`loginctl enable-linger`) does not create a graphical session and is
|
||
not needed here. Operation before login or after logout requires a configured
|
||
noninteractive destination and explicit ambiguity policy; unanswered decisions
|
||
will remain pending.
|
||
|
||
### Update, stop and remove
|
||
|
||
After updating the source:
|
||
|
||
```sh
|
||
cargo build --release --locked
|
||
systemctl --user stop uniloader.service
|
||
install -Dm755 target/release/uniloader ~/.local/bin/uniloader
|
||
systemctl --user start uniloader.service
|
||
```
|
||
|
||
Keep your existing config; compare it with the updated complete example for new
|
||
settings. A service restart reloads configuration.
|
||
|
||
To disable automatic startup:
|
||
|
||
```sh
|
||
systemctl --user disable --now uniloader.service
|
||
```
|
||
|
||
To remove the service and executable:
|
||
|
||
```sh
|
||
rm ~/.config/systemd/user/uniloader.service
|
||
systemctl --user daemon-reload
|
||
rm ~/.local/bin/uniloader
|
||
```
|
||
|
||
Remove any compositor hooks or service overrides you added as well. Imported
|
||
libraries, configuration, source archives and history are retained. Only remove
|
||
those separately when you are sure they are no longer needed.
|