feat: add plugin dependencies - #855
Conversation
|
Big fan of the incremental implementation of this FR. It makes it very easy for me to review. A hard dependency variant sounds viable. Major
Minor
|
Adds an optional "dependencies" array to plugin.json ("name" or
"name@<range>"). Backends now spawn dependency-first (stable topological
sort; spawn is sequential and waits for each plugin's on_load, so the
ordering is real), and frontend shims are injected in the same order.
Cycles, unknown names and unsatisfied version ranges warn once and never
prevent a plugin from loading. Without the field the load order is
unchanged, covered by a Catch2 test. Enumeration order everywhere else
(settings UI, quick access) is untouched.
When a plugin being installed declares dependencies that are missing or disabled, the installer lists them (with their version ranges) before downloading. The user can always continue - nothing is ever installed automatically.
Each plugin's row in settings shows a small chip per declared dependency with a check or cross depending on whether that dependency is installed and enabled. Plugins without dependencies are unaffected.
…a theme A theme's skin.json can declare the same optional "dependencies" field (plugin names, optionally with version ranges). Installing a theme with unmet plugin dependencies shows the same warning dialog as plugins do. Closes SteamClientHomebrew#102
- warn once per distinct dependency problem instead of once per session
- reuse the name index from plugin_deps instead of scanning the plugin
list for every dependency
- keep inclusive and exclusive version ranges distinct in the UI
(">=1.2.0" reads as "min version", ">1.2.0" as "newer than")
- a crashed dependency no longer shows as satisfied in the plugin list
- include <cstddef> in plugin_deps.h instead of relying on transitive
includes
Adds a "requires" field next to "dependencies", for plugins and themes alike, covering the case where the dependency isn't optional. Both fields take part in load ordering, but a required one is also enforced: a plugin that requires another can't be enabled until it's there, and a theme that requires plugins can't be applied. The toggle in settings stays off with a tooltip naming what is missing, and the native side refuses the same requests as a backstop for hand-edited configs. Turning off a plugin that others require asks first, then turns those off as well (and drops back to the default theme if the active one required it), so nothing ever runs without something it requires. Installing is never blocked - the install dialog just marks required dependencies as such, and nothing is ever installed automatically.
02e79ad to
4f1e8b4
Compare
|
Thanks, all five addressed:
Also took a shot at the hard variant, in its own commit so it can be dropped independently. "requires" sits next to "dependencies", npm style: Both order the load, but a required one is enforced: a plugin can't be enabled until its requirements are there, and a theme that lists requirements can't be applied. The toggle stays off with a tooltip naming what's missing, and the native side refuses the same requests so a hand-edited config can't sneak past. Turning off a plugin others require asks first and turns those off too, dropping back to the default theme if the active one required it - otherwise the guarantee would only hold until someone flipped the dependency off. Installing stays permissive either way, the dialog just labels those entries "required", since installing something you can't enable yet is harmless. Rebased onto current next. |
|
Marking this ready - the review notes are addressed and the hard variant is in as its own commit. I can split it up if the branch is too much at once. |
A plugin built with starlight can declare "requires" and "dependencies" in [plugin], and the ids are written into the .star metadata so the same load ordering, install warning and enable rules apply to v2 plugins. Millennium reads both fields back out of the metadata; before this only "dependencies" was picked up, so a required dependency was silently dropped for star plugins.
|
Realised the dependency work only covered v1 plugins, so this adds the v2 side: starlight writes "requires" and "dependencies" from [plugin] into the .star metadata, and Millennium reads both back out. Before this it only read "dependencies", so a required dependency was silently dropped for star plugins. The [plugin] config fields also show up in #887 for the localization side. Whichever lands first, I'll rebase the other. |
|
Honestly given that, maybe we should drop support entirely from V1 plugins, and only have it as a V2 feature? Would be much less to maintain. I'm open to discussion! |
|
Works for me - new plugins that want to declare dependencies can be expected to use the new format anyway, so I'll strip the schema change and the plugin.json reads. Two things I'd keep: v1 plugins staying valid as targets, since the resolver matches by name whatever the format and an old plugin that never migrates can still be depended on - that lives in the shared core and costs nothing. And themes, since skins have no v2 format - that side reads skin.json either way. |
Declaring "requires" and "dependencies" is now exclusive to the .star manifest; the fields are ignored in a loose plugin.json and the schema change is reverted. The resolver still matches targets by name whatever their format, so a v2 plugin can depend on a v1 plugin, and themes keep reading skin.json since skins have no v2 format.
Closes #823 and #102.
Adds an optional "dependencies" field to plugin.json (and skin.json for themes):
Without the field nothing changes (covered by a test). Version ranges support >=, <=, >, <, =.
This also makes sharing between plugins practical: a plugin can expose objects or CSS variables (shared panel colors and such) and a dependent can actually rely on them, since its dependency is guaranteed to be present and loaded first. Same groundwork the locale system from #823 would build on.
Would like your take on one thing: this is deliberately soft - a missing dependency never blocks installing or enabling, authors are expected to degrade gracefully. If you'd rather also have a hard variant (can't enable without it, npm dependencies vs peerDependencies style), that can be added on top - happy to rework in either direction.
Not here: ordered frontend script execution and a ready signal for plugin frontends, can follow up. Note the install dialogs read pluginJson / skin_data from the site API, which forwards the manifests as-is today.