Xbar and SwiftBar pluginΒΆ
The Meta Package Manager project is actively maintaining a plugin that is both compatible with Xbar and SwiftBar.
The plugin is written in Python and is a small wrapper around the mpm CLI.
Hint
I recommend SwiftBar, because Xbar has 2 outstanding issues:
ConfigurationΒΆ
The plugin is configurable with these environment variables:
Variable name |
Description |
Type |
Defaults |
SwiftBar support |
Xbar support |
|---|---|---|---|---|---|
|
Group packages into a sub-menu for each manager. |
Boolean |
|
β |
β |
|
Aligns package names and versions in a table for easier visual parsing. |
Boolean |
|
β |
β |
|
Font parameters for regular text. |
String |
Empty |
β |
|
|
Font parameters for monospace text. Used for table rendering and error messages. |
String |
|
β |
ScreenshotsΒΆ
SwiftBarΒΆ
VAR_SUBMENU_LAYOUT = FalseVAR_TABLE_RENDERING = False
VAR_SUBMENU_LAYOUT = FalseVAR_TABLE_RENDERING = True(default)
VAR_SUBMENU_LAYOUT = TrueVAR_TABLE_RENDERING = True
VAR_SUBMENU_LAYOUT = TrueVAR_TABLE_RENDERING = FalseXbarΒΆ
VAR_SUBMENU_LAYOUT = FalseVAR_TABLE_RENDERING = False
VAR_SUBMENU_LAYOUT = FalseVAR_TABLE_RENDERING = True(default)
VAR_SUBMENU_LAYOUT = TrueVAR_TABLE_RENDERING = True
VAR_SUBMENU_LAYOUT = TrueVAR_TABLE_RENDERING = FalseLocationΒΆ
A copy of the latest stable version of the plugin is available on Xbar website and plugin repository.
Once mpm is installed on your system, it can dynamiccaly be located with the dedicated --bar-plugin-path option:
$ mpm --bar-plugin-path
~/Library/Python/3.11/lib/python/site-packages/meta_package_manager/bar_plugin.py
This option is handy for deployment and initial configuration of Xbar/SwiftBar. I use this in my dotfiles to symlink the plugin to its latest version:
$ ln -sf "$(mpm --bar-plugin-path)" "${HOME}/Library/Application Support/xbar/plugins/mpm.7h.py"
Python >= 3.9 requiredΒΆ
The plugin requires Python 3.9 or newer. Which is the version that ships with the latest macOS releases:
macOS version |
Python version[1] |
|---|---|
16.x - TBA |
3.9.6 |
15.x - Sequoia |
3.9.6 |
14.x - Sonoma |
3.9.6 |
13.x - Ventura |
3.8.9 |
That way, the plugin is compatible with the latest macOS releases out of the box, and can be run as-is without any extra dependency.
Caution
It looks like since Monterey (macOS), there is no default Python version installed anymore, and the python CLI is a stub that points to the App Store to install Xcode:
$ python3 --version
xcode-select: note: no developer tools were found at '/Applications/Xcode.app', requesting install. Choose an option in the dialog to download the command line developer tools.
Development workflowΒΆ
Active development of the plugin is happening here, as a side-project of mpm itself.
Releases of the plugin is synchronized with the package. Both share the exact same version to simplify management. This explain why the plugin could appears jumping ahead a couple of major/minor versions while providing tiny or no changes at all.
A release is ready when both the package and the plugin reach a stable state.
If the plugin has been changed between releases, a
copy of the plugin is pushed
under the name meta_package_manager.7h.py, to the
official Xbar plugin repository.
Release processΒΆ
Fork the official Xbar plugin repository.
Fetch a local copy of the fork:
$ git clone https://github.com/kdeldycke/xbar-plugins $ cd xbar-plugins
Create a new branch and switch to it:
$ git branch "meta-package-manager-v4.13.1" $ git checkout "meta-package-manager-v4.13.1"
Replace existing copy of the plugin with the latest tagged version:
$ wget https://raw.githubusercontent.com/kdeldycke/meta-package-manager/v4.13.1/meta_package_manager/bar_plugin.py $ mv ./bar_plugin.py ./Dev/meta_package_manager.7h.py $ chmod 755 ./Dev/meta_package_manager.7h.py
Commit the new plugin:
$ git add ./Dev/meta_package_manager.7h.py $ git commit -m "Upgrade to Meta Package Manager plugin v4.13.1"
Push new branch:
$ git push --set-upstream origin "meta-package-manager-v4.13.1"
Create a pull-request in the original repository.
meta_package_manager.bar_plugin APIΒΆ
Xbar and SwiftBar 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.
Xbar automatically bridge plugin options between its UI and environment variable on script execution.
This is in progress for SwiftBar.
- meta_package_manager.bar_plugin.SWIFTBAR_MIN_VERSION = (2, 1, 2)ΒΆ
SwiftBar v2.1.2 fix an issue with multiple parameters in the font strings.
- 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.MPM_TIMEOUT = 60ΒΆ
Maximum duration in seconds the plugin lets any single
mpmcall run.Passed as
--timeoutto everympminvocation 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 likesync). 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:
objectImplements the minimal code necessary to locate and call the
mpmCLI on the system.Once
mpmis 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.
- static getenv_bool(var, default=False)[source]ΒΆ
Utility to normalize boolean environment variables.
Relies on
configparser.RawConfigParser.BOOLEAN_STATESto translate strings into boolean. See: https://github.com/python/cpython/blob/3c298e2e385fc6f462abaada2fd680deb1a2b58e/Lib/configparser.py#L596-L597- Return type:
- 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_idsset and ignores the rest. By default, onlycolor,fontandsizeare kept.Multiple values for the same parameter will be deduplicated, and the last one will be kept.
Available parameters are: - https://github.com/swiftbar/SwiftBar?tab=readme-ov-file#parameters - https://github.com/matryer/xbar-plugins/blob/main/CONTRIBUTING.md#parameters
- Return type:
- static str_to_version(version_string)[source]ΒΆ
Transforms a string into a tuple of integers representing a version.
- static version_to_str(version_tuple)[source]ΒΆ
Transforms a tuple of integers representing a version into a string.
- Return type:
- property table_rendering: boolΒΆ
Aligns package names and versions, like a table, for easier visual parsing.
If
True, will aligns all items using a fixed-width font.
- 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
mpmfrom the virtualenv context, orNoneif the folder is not a venv.Inspired by autoswitch_virtualenv.plugin.zsh and uvβs get_interpreter_info.py.
- 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
mpmover different context.The order in which the candidates are returned by this method is conserved by the
ranked_mpm()method below.We prioritize venv-based findings first, as theyβre more likely to have all dependencies installed and sorted out. Theyβre also our prime candidates in unittests.
Then we search for system-wide installation. And finally Python modules.
- property ranked_mpm: list[tuple[tuple[str, ...], bool, bool, tuple[int, ...] | None, str | Exception | None]]ΒΆ
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_mpmis respected.
- property best_mpm: tuple[tuple[str, ...], bool, bool, tuple[int, ...] | None, str | Exception | None]ΒΆ
- static pp(label, *args)[source]ΒΆ
Print one menu-line with the Xbar/SwiftBar 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.
- Return type:
- 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:
Print the main menu.
- Return type:
meta_package_manager.bar_plugin_renderer APIΒΆ
mpm-side renderer that builds Xbar/SwiftBar plugin output.
Lives in its own module rather than in
meta_package_manager.bar_plugin because that module is
intentionally stdlib-only: the
meta_package_manager.bar_plugin.MPMPlugin class is the
script that gets installed as the userβs actual bar plugin and must
stay light on dependencies.
This module is the heavier mpm-side companion that augments the
shippable plugin code with click_extra, boltons, the manager pool, and
the theme system to produce the final rendered output from
mpm outdated --plugin-output.
- class meta_package_manager.bar_plugin_renderer.BarPluginRenderer[source]ΒΆ
Bases:
MPMPluginAll utilities used to render output compatible with both Xbar and SwiftBar plugin dialect.
The minimal code to locate
mpm, then call it and print its output resides in the plugin itself atmeta_package_manager.bar_plugin.MPMPlugin.best_mpm().All other stuff, especially the rendering code, is managed here, to allow for more complex layouts relying on external Python dependencies. This also limits the number of required updates on the plugin itself.
Group packages into manager sub-menus.
If
True, will replace the default flat layout with an alternative structure where actions are grouped into submenus, one for each manager.Value is sourced from the
VAR_SUBMENU_LAYOUTenvironment variable.
- property dark_mode: boolΒΆ
Detect dark mode by inspecting environment variables.
Value is sourced from two environment variables depending on the plugin:
OS_APPEARANCEfor SwiftBarXBARDarkModefor XBar
- static render_cli(cmd_args)[source]ΒΆ
Return a formatted CLI compatible with Xbar and SwiftBar plugin format.
I.e. a string with this schema:
shell=cmd_args[0] param1=cmd_args[1] param2=cmd_args[2] ...
- Return type:
- print_cli_item(*args)[source]ΒΆ
Print two CLI entries:
one that opens a visible terminal so the user can follow the execution
a second one, reachable by holding the
Optionkey, that runs silently
- Return type:
- print_upgrade_all_item(manager, submenu='')[source]ΒΆ
Print the menu entry to upgrade all outdated package of a manager.
- Return type:
- render(outdated_data)[source]ΒΆ
Wraps the
_render()method above to capture allprintstatements.- Return type: