AvogadroLibs 2.1.0-20261111
Loading...
Searching...
No Matches
PackageManager Class Reference

Singleton that manages pyproject.toml-based plugin packages. More...

#include <packagemanager.h>

Inheritance diagram for PackageManager:

Classes

struct  PackageInfo
struct  CommandLine

Signals

void packagesInstalled ()
void packageInstalled (const QString &packageDir)
void packageInstallFailed (const QString &packageDir, const QString &message)
void featureRegistered (const QString &type, const QString &packageDir, const QString &command, const QString &identifier, const QVariantMap &metadata)
void featureRemoved (const QString &type, const QString &packageDir, const QString &command, const QString &identifier)

Public Member Functions

void installPackages (const QStringList &packageDirs)
bool registerPackage (const QString &packageDir)
bool unregisterPackage (const QString &packageName)
void loadRegisteredPackages (const QString &typeFilter=QString())
QStringList scanDirectory (const QString &directoryPath)
QStringList registeredPackages () const
PackageInfo packageInfo (const QString &packageName) const
QStringList packageFeatureTypes (const QString &packageName) const

Static Public Member Functions

static PackageManager * instance ()
static QStringList featureTypes ()
static QString featureSettingsKey (const QString &packageDir, const QString &command, const QString &identifier)
static QString packageFeatureKey (const QString &packageDir, const QString &command, const QString &identifier)
static QJsonObject loadOptionsFromFile (const QString &userOptionsPath)
static void mergeOptionsFromFile (QJsonObject &opts, const QString &userOptionsPath)
static QString packageVersion (const QString &packageDir)
static bool hasPixiManifest (const QString &packageDir)
static QString pixiScriptPath (const QString &packageDir, const QString &command)
static QString venvScriptPath (const QString &packageDir, const QString &command)
static CommandLine resolveCommandLine (const QString &packageDir, const QString &command)
static CommandLine resolveCommandLine (const QString &packageDir, const QString &command, const QString &pixiExecutable)
static QJsonObject loadOptionsFromScript (const QString &packageDir, const QString &command, const QString &identifier)
static bool isDynamicUserOptions (const QString &userOptionsValue)
static QJsonObject resolveUserOptions (const QString &userOptionsValue, const QString &packageDir, const QString &command, const QString &identifier)
static bool removeSupersededVenv (const QString &packageDir, const QString &command)
static void clearInstallFailure (const QString &packageDir)

Detailed Description

Packages are registered once (at download time or manually) and cached in QSettings. On startup, loadRegisteredPackages() replays the cached registrations as featureRegistered() signals so that consumer plugins (Command, ScriptCharges, Forcefield, etc.) can create their actions and models without re-parsing TOML or calling scripts.

During a session, registerPackage() can be called at any time (e.g. after the plugin downloader installs a new package) and signals fire immediately.

Member Function Documentation

◆ featureTypes()

QStringList featureTypes ( )
static

Known feature-type strings (TOML table names under [tool.avogadro]).

◆ featureSettingsKey()

QString featureSettingsKey ( const QString & packageDir,
const QString & command,
const QString & identifier )
static

A short, readable, stable key naming one feature, for use as a QSettings group. Unlike packageFeatureKey() this embeds no absolute path, so it does not turn into a deep tree of settings groups.

◆ packageFeatureKey()

QString packageFeatureKey ( const QString & packageDir,
const QString & command,
const QString & identifier )
static

Build a stable key for one package-provided feature. Consumers can use this as a map key to track registrations and removals. Components must not be empty.

◆ loadOptionsFromFile()

QJsonObject loadOptionsFromFile ( const QString & userOptionsPath)
static

Load package user-options from JSON or TOML (selected by extension). Returns an empty object on error.

◆ mergeOptionsFromFile()

void mergeOptionsFromFile ( QJsonObject & opts,
const QString & userOptionsPath )
static

Merge package user-options into opts. Keys from the file override existing values in opts.

◆ packageVersion()

QString packageVersion ( const QString & packageDir)
static

The [project.version] declared by the pyproject.toml in packageDir, or an empty string if it cannot be read.

◆ hasPixiManifest()

bool hasPixiManifest ( const QString & packageDir)
static

Whether packageDir declares a pixi workspace of its own: a pixi.toml, or a pyproject.toml with a non-empty [tool.pixi] table.

pixi finds its manifest by walking up from the directory it is run in, so a package that declares none is not merely unsupported — pixi silently operates on an ancestor's workspace instead. "pixi install" then reports success having installed something else entirely, and the package's own command is nowhere on PATH ("command not found", exit 127). Such a package has to be installed with pip into .venv.

◆ pixiScriptPath()

QString pixiScriptPath ( const QString & packageDir,
const QString & command )
static

Absolute path to command as installed in the pixi environment of packageDir (.pixi/envs/default), or an empty string if the package has no pixi environment with that command in it.

Package commands are run with "pixi run &ndash;as-is", which is shorthand for --no-install --frozen and so will never create a missing environment. Callers must therefore check this rather than merely checking that the pixi executable exists.

◆ venvScriptPath()

QString venvScriptPath ( const QString & packageDir,
const QString & command )
static

Absolute path to command as installed in the virtual environment of packageDir (.venv), or an empty string if there is none. This is the fallback for packages that were pip-installed because pixi was not available when they were set up.

◆ resolveCommandLine() [1/2]

CommandLine resolveCommandLine ( const QString & packageDir,
const QString & command )
static

Resolve how to run command from packageDir, so that every caller applies the same backend policy.

In order of preference:

  1. "pixi run &ndash;as-is" when the pixi executable is found and the pixi environment provides command;
  2. the pixi environment's own script, run directly, when pixi cannot be found (for example an application launched from the Finder or Dock has no Homebrew directory on its PATH) – the script works without pixi, but skips activation, hence CommandLine::environmentBinDir;
  3. the console script pip installed into .venv.

Having the pixi executable is not on its own enough to choose pixi, because "pixi run &ndash;as-is" is shorthand for --no-install --frozen and will not create a missing environment: a package installed before pixi was available has to keep running from .venv until it is installed again.

Returns
a CommandLine whose program is empty when neither environment provides command.

◆ resolveCommandLine() [2/2]

CommandLine resolveCommandLine ( const QString & packageDir,
const QString & command,
const QString & pixiExecutable )
static

As above, but with the pixi executable supplied by the caller rather than searched for. pixiExecutable may be empty, meaning "pixi not found".

◆ loadOptionsFromScript()

QJsonObject loadOptionsFromScript ( const QString & packageDir,
const QString & command,
const QString & identifier )
static

Run the package script with --user-options and parse the JSON output. Uses pixi (preferred) or the venv-installed script as fallback. Returns an empty object on error.

◆ isDynamicUserOptions()

bool isDynamicUserOptions ( const QString & userOptionsValue)
static

Whether a feature's user-options value asks for options to be built fresh by the script rather than read from a file. Such options are generated per invocation, so callers must not cache the resulting GUI.

◆ resolveUserOptions()

QJsonObject resolveUserOptions ( const QString & userOptionsValue,
const QString & packageDir,
const QString & command,
const QString & identifier )
static

Resolve user-options for a package feature. If userOptionsValue is dynamic (see isDynamicUserOptions()), runs the script with --user-options via loadOptionsFromScript(). Otherwise treats it as a relative file path and loads via loadOptionsFromFile(). Returns an empty object on error or if userOptionsValue is empty.

◆ installPackages()

void installPackages ( const QStringList & packageDirs)

Asynchronously run pixi (preferred) or pip install in each directory, then call registerPackage() for each package that installed. Emits packageInstalled() or packageInstallFailed() for each package, then packagesInstalled() when the background thread finishes. A failure is remembered (see scanDirectory()) and the package is not registered; a previously registered package is kept only while one of its environments can still run its command. Safe to call from the main thread.

◆ removeSupersededVenv()

bool removeSupersededVenv ( const QString & packageDir,
const QString & command )
static

Delete the .venv directory of packageDir once its pixi environment can run command, so that a package migrated to pixi does not keep a stale pip-installed tree around. Nothing will ever update that tree, and it would silently serve outdated code if the pixi environment were later removed.

Does nothing if there is no .venv, or if the pixi environment does not provide command — a half-finished install must never leave the package with no way to run at all.

Returns
true if a .venv directory was removed.

◆ clearInstallFailure()

void clearInstallFailure ( const QString & packageDir)
static

Forget recorded install failures for packageDir, so that scanDirectory() offers it again.

◆ registerPackage()

bool registerPackage ( const QString & packageDir)

Parse pyproject.toml in packageDir, cache the result in QSettings, and emit featureRegistered() for every feature found.

Returns
true on success.

◆ unregisterPackage()

bool unregisterPackage ( const QString & packageName)

Remove a package and all its feature registrations from the cache. Emits featureRemoved() for each feature that was registered.

◆ loadRegisteredPackages()

void loadRegisteredPackages ( const QString & typeFilter = QString())

Load all previously-registered packages from QSettings and emit featureRegistered() for each cached feature. Call this once after all consumer plugins have connected.

◆ scanDirectory()

QStringList scanDirectory ( const QString & directoryPath)

Scan directoryPath for subdirectories that contain a pyproject.toml. Each discovered package is compared against the cached hash of its pyproject.toml; new or modified packages are returned as a list of absolute directory paths. The caller is responsible for calling registerPackage() on any directories it wants to install. A package whose install already failed for the current pyproject.toml is not returned again until that file changes; likewise pixi is not retried for a package that pip-installed after pixi failed.

Returns
list of package directories that are new or have been modified.

◆ packageFeatureTypes()

QStringList packageFeatureTypes ( const QString & packageName) const

Return the distinct feature-type strings (e.g. "menu-commands", "file-formats") for a registered package, read from the QSettings cache.

◆ packagesInstalled

void packagesInstalled ( )
signal

Emitted after installPackages() finishes with all requested packages, whether or not each succeeded. See packageInstalled() and packageInstallFailed() for the outcome of each.

◆ packageInstalled

void packageInstalled ( const QString & packageDir)
signal

Emitted for each package installPackages() installed and registered.

◆ packageInstallFailed

void packageInstallFailed ( const QString & packageDir,
const QString & message )
signal

Emitted for each package installPackages() could not install.

Parameters
messageWhich backend(s) failed and the tail of their stderr.

◆ featureRegistered

void featureRegistered ( const QString & type,
const QString & packageDir,
const QString & command,
const QString & identifier,
const QVariantMap & metadata )
signal

Emitted for each feature found in a package.

Parameters
typeOne of the featureTypes() strings, e.g. "menu-commands", "electrostatic-models", etc.
packageDirAbsolute path to the package directory.
commandEntry-point name from [project.scripts].
identifierThe feature's unique identifier.
metadataRemaining TOML sub-table fields as a QVariantMap.

◆ featureRemoved

void featureRemoved ( const QString & type,
const QString & packageDir,
const QString & command,
const QString & identifier )
signal

Emitted when a feature is removed (so consumers can clean up).

Parameters
typeOne of the featureTypes() strings.
packageDirAbsolute path to the package directory.
commandEntry-point name from [project.scripts].
identifierThe feature's unique identifier.

The documentation for this class was generated from the following file: