I had this in the CEP proposal but I removed it for simplicity since it doesn't really matter for the JSON metadata. It can be added in a separate one (e.g. for the plugin hook request). Note some of the details below are no longer current, but I am copying it here verbatim.
Python API
Current state
menuinst 1.x
provides a Python API comprised of a single function menuinst.install(...)
with the following signature:
def install(path, remove=False, prefix=sys.prefix, recursing=False, root_prefix=sys.prefix):
...
Note that calling menuinst.install
for platforms other than Windows currently fails due to the extra root_prefix
argument added for conda-standalone
compatibility.
Other projects provide a layer on top of menuinst.install
:
constructor/nsis/_nsis.py
introduces mk_menus
and rm_menus
, which iterate PREFIX/Menu
looking for suitable JSON files. These functions only exist to offer support for constructor's menu_packages
option. Adding a --shortcuts-only
filter CLI flag to conda
would make this unnecessary.
def mk_menus(remove=False, prefix=None, pkg_names=None, root_prefix=None):
...
def rm_menus(prefix=None, root_prefix=None):
...
conda
provides make_menu
, which actively excludes Linux / MacOS.
def make_menu(prefix, file_path, remove=False):
...
Motivation
The official API is confusing (install can also remove) and leaves opportunity for downstream to create their own logic for basic functionality. menuinst
should be the sole provider here.
Suggested actions
menuinst
needs to provide two functions: install
and remove
.
def install(metadata: [str, dict], target_prefix: str = sys.prefix, root_prefix: str = sys.prefix) -> List[str]:
...
def remove(metadata: [str, dict], target_prefix: str = sys.prefix, root_prefix: str = sys.prefix) -> List[str]:
...
metadata
can be either a path to a JSON file, a file handler or an already parsed object. Regardless the source, the resulting metadata object needs to satisfy the metadata schema. Both functions return a list of strings that point to the path of the menu items created or removed.
Additionally, an utility function for prefixes could provide:
def install_all(prefix: str, root_prefix: str = sys.prefix, filter: callable = None) -> List[List[str]]:
...
def remove_all(prefix: str, root_prefix: str = sys.prefix, filter: callable = None) -> List[List[str]]:
...
It should be discussed whether:
root_prefix
is only used internally by conda-standalone
/ constructor
and hence should be made a private name _root_prefix
.
recursing
is needed on Windows or not.
- A list (of lists) of strings is the best way to return the created shortcuts. Some platforms create a directory with shortcuts (Windows), some create several directories (MacOS), some create a list of files in a given location (Linux).
Backwards compatibility
New conda
releases will pin accordingly. Releasing this API would entail a new major version, which should be enough to prevent breakages. Current version 4.12
is pinning menuinst
as >=1.4.11,<2
.
CLI API
Current state
menuinst 1.x
does provide a CLI through menuinst.main
:
$> menuinst [--remove] [--prefix=sys.prefix] [json_file json_file ...]
However, constructor
needs a way to call it from conda-standalone
, which prompted this project to provide a custom entry point that mimics a conda
sub-command:
$> conda-standalone constructor [--prefix] [--make-menus|--rm-menus] ...
This is needed because, even with menuinst
own CLI, conda-standalone
is a pyinstaller
-frozen executable which cannot call arbitrary entry points in the bundle.
Motivation
A standard menuinst
CLI (standalone or through conda) is needed and must not be provided as part of the conda-standalone
project only. It is a surprising behaviour that needs to be replicated by other implementations and, as such, should be part of the main codebase.
constructor
allows a different standalone conda executable to be bundled through the --conda-exe
option, which opens the possibility of using micromamba
as the bundled conda. The constructor
sub-command is expected though, so micromamba
needs to provide it as well.
Suggested actions
Provide a conda constructor
subcommand, officially part of the conda
core. It should implement the same CLI as currently found in the constructor
entry point, delegating the menu creation and removal to the menuinst
public API. This CLI should be standardized so other projects can implement it if needed.
menuinst
itself does not need to provide a CLI, but if it does, it should be as similar as possible to the constructor
counterparts.
Alternatively, add support in conda-standalone for conda run
, so one can call arbitrary code within the frozen binary. This would allow us to place scripts and executables inside conda-standalone without having to patch the entry point:
$> conda-standalone run python -m menuinst ...
$> conda-standalone run python -m constructor_helper ...
Unfortunately, this is difficult to replicate in non-Python implementations.