Class BowirePluginRoot

Namespace
Kuestenlogik.Bowire.Plugins
Assembly
Kuestenlogik.Bowire.dll

The one answer to "which directories hold the installed plugins" (#549, then #28 Phase D).

public static class BowirePluginRoot
Inheritance
BowirePluginRoot
Inherited Members

Remarks

BowirePaths (#616) gave every storage question a single resolver, and the plugin directory rides on it — but only for the default. Two things sit on top of that default, and both are why this type exists.

The explicit override (#549). The plugin directory is the one storage location a host can also point somewhere else outright, through Bowire:PluginDir — the CLI's --plugin-dir, the BOWIRE_PLUGIN_DIR environment variable and an appsettings.json entry all bind to that key. Before this type, that override reached the loader alone, so a host started with --plugin-dir X installed into X and then listed somewhere else.

Two tiers (#28 Phase D). "Everyone shares one ~/.bowire/plugins" has two failure modes at once: a user cannot install a plugin for their own workflow without administrative rights, and an administrator cannot provision one for everybody. So there are now two directories — a machine-wide tier an admin manages, and the user's own overlay on top of it. EnumeratePackages() walks them in precedence order and is the only place that ordering is expressed.

Static, and set once at start-up, for the same reason BowirePaths is: several readers are static properties with no constructor to inject into. Anything that does have a constructor should keep taking the path as a parameter.

Properties

Current

Where a plugin install lands, and the tier the user owns: the configured directory when a host set one, the storage resolver's default otherwise.

public static string Current { get; }

Property Value

string

Remarks

A property rather than a captured field: Apply(string?) runs when the host is built, which can be after this type is first touched, and Current can be swapped later still. Reading through on every call is what keeps both honest.

IsConfigured

Whether a host explicitly configured the user directory.

public static bool IsConfigured { get; }

Property Value

bool

MachineRoot

The machine-wide tier: %ProgramData%\Bowire\plugins on Windows, /var/lib/bowire/plugins elsewhere.

public static string MachineRoot { get; }

Property Value

string

Remarks

Resolved even when the directory does not exist — most installs have no machine tier at all, and an absent directory reads as "no plugins there" rather than as an error.

Roots

The directories to search, in precedence order: the user's own first, then the machine tier.

public static IReadOnlyList<(string Path, BowirePluginTier Tier)> Roots { get; }

Property Value

IReadOnlyList<(string Path, BowirePluginTier Tier)>

Remarks

The user tier comes first so a locally installed plugin shadows a machine-wide one of the same package id — that is what makes it an overlay, and it is how someone tries a newer build without asking an administrator to change what everybody else gets.

An explicitly configured directory yields only that directory. --plugin-dir /tmp/isolated is an operator saying which plugins are in play, and quietly adding a machine tier they did not ask for would make an isolated run stop being isolated.

Methods

Apply(string?)

Point every plugin-directory reader at directory. Null, empty or whitespace clears the override and returns the resolver default, so a host can call this unconditionally with whatever Bowire:PluginDir yielded.

public static string Apply(string? directory)

Parameters

directory string

Returns

string

The user-tier directory in force after the call.

EnumeratePackages()

Every installed package directory across both tiers, in precedence order, with the tier it came from. A package id present in both is yielded once, from the higher-precedence tier.

public static IEnumerable<(string Directory, string PackageId, BowirePluginTier Tier)> EnumeratePackages()

Returns

IEnumerable<(string Directory, string PackageId, BowirePluginTier Tier)>

Remarks

The single place the overlay rule is applied. Callers that scanned one directory with Directory.GetDirectories should read this instead — the alternative is each of them re-deciding what happens when the same plugin exists twice, which is how the four readers in #549 came to disagree in the first place.

EnumeratePackagesUnder(string, bool)

The same walk, for a caller that resolved the user tier itself.

public static IEnumerable<(string Directory, string PackageId, BowirePluginTier Tier)> EnumeratePackagesUnder(string userRoot, bool includeMachineTier)

Parameters

userRoot string

The directory to treat as the user tier.

includeMachineTier bool

Whether to search the machine tier as well. Pass false when userRoot came from an operator naming a directory — an isolated run has to stay isolated.

Returns

IEnumerable<(string Directory, string PackageId, BowirePluginTier Tier)>

Remarks

Exists because the Tool resolves the directory through BowirePluginOptions, which owns a precedence chain (--plugin-dir over the environment over configuration) that Core has no notion of. Rather than have the loader trust that some earlier call already pushed that answer into Apply(string?), it passes what it resolved and gets the same overlay rule applied to it.