meta_package_manager.bar_plugin module

SwiftBar and Xbar plugin for Meta Package Manager (the mpm CLI).

Default update cycle should be set to several hours so we have a chance to get user’s attention once a day. Higher frequency might ruin the system as all checks are quite resource intensive, and Homebrew might hit GitHub’s API calls quota.

meta_package_manager.bar_plugin.SWIFTBAR_MIN_VERSION = (2, 1, 0)

SwiftBar 2.1.0 fixes an issue with multiple parameters in the font strings.

The fix was first handed out as a 2.1.2-labelled test build, a number that never reached a release: the public train renumbered it down to 2.1.0. Requiring the build we validated on would lock the plugin out of every released SwiftBar.

See swiftbar/SwiftBar#445.

meta_package_manager.bar_plugin.XBAR_MIN_VERSION = (2, 1, 7)

Xbar v2.1.7-beta is the latest version available on Homebrew.

meta_package_manager.bar_plugin.MPM_MIN_VERSION = (5, 0, 0)

Mpm v5.0.0 was the first version taking care of the complete layout rendering.

meta_package_manager.bar_plugin.INSTALL_ARGV = ('uv', 'tool', 'install', '--upgrade', 'meta-package-manager')

Bootstrap command offered when no runnable mpm is found.

A global uv tool install, the primary method of the installation page: it puts mpm on the PATH of every shell, where a pip install would have buried it in whichever interpreter happened to run this plugin. --upgrade makes the same command serve the outdated-mpm case, so nothing pins the specifier to MPM_MIN_VERSION: the latest release always satisfies it, and Xbar mangles a quoted >= specifier anyway (see matryer/xbar#831).

The GNOME Shell extension offers the same command from its own missing-mpm menu, and tests/test_gnome_extension.py holds the two in sync.

meta_package_manager.bar_plugin.INSTALL_DOCS_URL = 'https://mpm.run/install/'

Installation page, offered beside INSTALL_ARGV.

uv may itself be missing, and is not the right answer everywhere: a distribution package, Homebrew or a standalone binary all install mpm too.

meta_package_manager.bar_plugin.PLUGIN_DOCS_URL = 'https://mpm.run/bar-plugin/'

Documentation of this plugin, linked from the About submenu.

The same address the <xbar.abouturl> header hands the host, which only surfaces it in its own plugin browser and never in the menu.

meta_package_manager.bar_plugin.MPM_TIMEOUT = 60

Maximum duration in seconds the plugin lets any single mpm call run.

Passed as --timeout to every mpm invocation so the plugin is never at the mercy of mpm’s own per-operation defaults, which are tuned for interactive CLI use and far too long for a background menubar refresh (120s for read-only queries, 500s for state-changing operations like sync). A wedged package manager then fails the whole refresh in a minute instead of freezing the menubar for several.

class meta_package_manager.bar_plugin.MPMPlugin[source]

Bases: object

Implements the minimal code necessary to locate and call the mpm CLI on the system.

Once mpm is located, we can rely on it to produce the main output of the plugin.

The output must supports both Xbar dialect and SwiftBar dialect.

static getenv_str(var, default=None)[source]

Utility to get environment variables.

Note that all environment variables are strings. Always returns a lowered-case string.

Return type:

str | None

static getenv_bool(var, default=False)[source]

Utility to normalize boolean environment variables.

Relies on configparser.RawConfigParser.BOOLEAN_STATES to translate strings into boolean.

Return type:

bool

static getenv_int(var, default)[source]

Utility to normalize integer environment variables.

Falls back to the default on anything that is not a number, so a typo in a plugin setting degrades the layout instead of killing the menu.

Return type:

int

static normalize_params(font_string, valid_ids=None)[source]

Parse a multi-parameters string and return a normalized string.

The string is expected to be a space-separated list of parameters, each parameter being a key/value pair separated by an equal sign.

Only keeps the parameters that are in the valid_ids set and ignores the rest. By default, only color, font and size are kept.

Multiple values for the same parameter will be deduplicated, and the last one will be kept.

Available parameters are documented by both hosts:

Return type:

str

static str_to_version(version_string)[source]

Transforms a string into a tuple of integers representing a version.

Return type:

tuple[int, ...]

static version_to_str(version_tuple)[source]

Transforms a tuple of integers representing a version into a string.

Return type:

str

property table_rendering: bool[source]

Aligns package names and versions, like a table, for easier visual parsing.

If True, will aligns all items using a fixed-width font.

property plugin_version: str[source]

Version this script advertises to its host.

Read back from the <xbar.version> header rather than kept in a constant beside it: that header is the one place the number is written, both hosts parse it out of the source, and bump-my-version rewrites it on release. A second copy is a second thing to drift.

property hide_when_up_to_date: bool[source]

Remove the menu bar icon entirely while there is nothing to report.

SwiftBar hides a plugin whose run produces no output, so rendering nothing is how the icon is made to disappear. That forces the plugin to tell a deliberate silence from a broken mpm call, which is why print_menu() only tolerates an empty output when this is set.

Xbar has no such behavior, hence the SwiftBar-only declaration.

Value is sourced from the VAR_HIDE_WHEN_UP_TO_DATE environment variable.

property default_font: str[source]

Make it easier to change font, sizes and colors of the output.

property monospace_font: str[source]

Make it easier to change font, sizes and colors of the output.

property error_font: str[source]

Error font is the monospace font, in red.

It carries no size of its own. A smaller string is still laid out in a row the menu sizes for the larger font, and both hosts leave the surplus under the text instead of splitting it: at size=10, an error line ended up with 15 pixels of space below it where every other row leaves 9.

property is_swiftbar: bool[source]

SwiftBar is kind enough to tell us about its presence.

static search_venv(folder)[source]

Search for signs of a virtual env in the provided folder.

Returns CLI arguments that can be used to run mpm from the virtualenv context, or None if the folder is not a venv.

Inspired by autoswitch_virtualenv.plugin.zsh and uv’s get_interpreter_info.py.

Return type:

tuple[str, ...] | None

search_mpm()[source]

Iterate over possible CLI commands to execute mpm.

Should be able to produce the full spectrum of alternative commands we can use to invoke mpm over different context.

The order in which the candidates are returned by this method is conserved by the ranked_mpm() method below.

Venv-based findings come first, because the plugin prefers the mpm it is part of. This file ships inside the package, so walking back up its own folders reaches the project that installed it, and that mpm is the one this plugin was released with, whose dependencies are already resolved. Both hosts import the file through a symlink into their own plugin folder, hence the resolution below: an unresolved path walks that folder and finds nothing, leaving the plugin to drive whichever other mpm the system answers with.

The rest are fallbacks, for a plugin that reached the host on its own: a system-wide installation, then the module under an interpreter. None of them is trusted on sight, check_mpm() running each before it is ranked.

Return type:

Generator[tuple[str, ...], None, None]

check_mpm(mpm_cli_args)[source]

Test-run mpm execution and extract its version.

Two readings of the same string come back. The numeric tuple is what compares against MPM_MIN_VERSION; the release is the token as printed, which a development build spells 8.0.0.dev0+40ce0879. The release is last because ranked_mpm sorts candidates on this tuple: anything inserted earlier would join the ranking.

Return type:

tuple[bool, bool, tuple[int, ...] | None, str | Exception | None, str | None]

property ranked_mpm: list[tuple[tuple[str, ...], bool, bool, tuple[int, ...] | None, str | Exception | None, str | None]][source]

Rank the mpm candidates we found on the system.

Sort them by: - runnability - up-to-date status - version number - error

On tie, the order from search_mpm is respected.

property best_mpm: tuple[tuple[str, ...], bool, bool, tuple[int, ...] | None, str | Exception | None, str | None][source]
static pp(label, *args)[source]

Print one menu-line with the SwiftBar/Xbar dialect.

First argument is the menu-line label, separated by a pipe to all other non- empty parameters, themselves separated by a space.

Skip printing of the line if label is empty. A None parameter renders nothing, so a package without an upgrade CLI still gets its label-only menu line.

Return type:

None

static print_error_header()[source]

Generic header for blocking error.

Return type:

None

print_error(message, submenu='')[source]

Print a formatted error message line by line.

A red, fixed-width font is used to preserve traceback and exception layout. For compactness, the block message is dedented and empty lines are skipped.

Message is always casted to a string as we allow passing of exception objects and have them rendered.

Return type:

None

print_about()[source]

Footer naming both halves of the install and the CLI behind them.

This script and mpm are installed separately and upgraded separately: a plugin file copied into the host’s folder stays at the version it was copied at while mpm moves under it, and nothing else in the menu shows that drift. The mpm line reports the release as printed, suffix included, where the ranking compares numbers alone.

Kept to a single collapsed row so a menu opened for its packages is not pushed down by three lines of provenance.

Return type:

None

print_menu()[source]

Print the main menu.

Return type:

None