Module records and aliases
Installation records what a module reports about itself. dpm_install_module opens a module once, writes its version and description to a .meta file in /var/lib/dpm/metadata/, and records the alternate names it declared in modules.aliases beside it. dpm_uninstall_module removes both, leaving the module file in place. dpm_list_modules reads those records and opens no module. A module with no record lists with a version of <uninstalled> and still loads when a caller names it. An unreadable or absent metadata directory costs the listing its detail and costs nothing else. Aliases give a module alternate names, declared through the new dpm_module_aliases contract symbol or added with dpm_add_module_alias. A name is recorded once: one already serving as an alias, or belonging to an installed module, is refused rather than repointed. dpm_require matches a name against the installed modules, then the alias table, then the module path. The metadata directory is a fifth override field and the -M flag, and [modules] metadata in core.conf. The test suite is four binaries covering context, modules, records, and aliases, each a ctest case of its own, alongside the CLI cases.
This commit is contained in:
@@ -4,7 +4,7 @@ A DPM module is one shared object in the module directory. libdpm-core.so loads
|
||||
|
||||
## The Module Contract
|
||||
|
||||
A module includes `<dpm/core.h>`, links `-ldpm-core`, and exports the following symbols as extern "C". All returned strings must be non-NULL, static or module-owned, and valid for the lifetime of the loaded module; callers never free them.
|
||||
A module includes `<dpm/core.h>`, links `-ldpm-core`, and exports the following four symbols as extern "C". All returned strings must be non-NULL, static or module-owned, and valid for the lifetime of the loaded module; callers never free them.
|
||||
|
||||
`int dpm_module_execute(dpm_ctx* ctx, const char* command, int argc, char** argv)`
|
||||
The command entry point, and the only entry through which the module performs work. `ctx` is the host context that dispatched the call; the module reaches every service (`dpm_log`, `dpm_config_get`, `dpm_get_resolved_module_path`, ...) through it, and reaches peer modules through it as well. `command` is the subcommand name, equal to argv[0] when argc > 0. NULL or empty `command` must behave as the module's help command. Returns 0 on success, nonzero on failure. Where a nonzero return needs explaining, record the reason with `dpm_set_last_error` immediately before returning, and the caller reads it back with `dpm_get_last_error`. It must be callable immediately after load with no other setup.
|
||||
@@ -15,6 +15,18 @@ The module's own version as an X.Y.Z string. libdpm-core.so reports this value t
|
||||
`const char* dpm_module_description(void)`
|
||||
A one-line human-readable description, shown in module listings.
|
||||
|
||||
`const char* dpm_module_aliases(void)`
|
||||
A comma-separated list of alternate names your module answers to, or NULL for none:
|
||||
|
||||
```
|
||||
extern "C" const char* dpm_module_aliases(void)
|
||||
{
|
||||
return "installer, files";
|
||||
}
|
||||
```
|
||||
|
||||
NULL is a complete answer. The symbol itself is required, and a module that does not export it is refused at load with the other contract failures.
|
||||
|
||||
The `dpm_ctx` type and the service declarations all come from the installed public header:
|
||||
|
||||
```
|
||||
@@ -110,7 +122,35 @@ Where your module calls a peer, put a **stub module** in the fixture module path
|
||||
|
||||
## Installing
|
||||
|
||||
Modules install to `lib/dpm/modules` under the install prefix (`/usr/lib/dpm/modules` on a distribution install). libdpm-core.so discovers the module on its next scan; no registration step exists beyond the file being present and valid.
|
||||
Modules install to `lib/dpm/modules` under the install prefix (`/usr/lib/dpm/modules` on a distribution install), and the package's install step then records the module:
|
||||
|
||||
```
|
||||
dpm --install-module mymodule
|
||||
```
|
||||
|
||||
That loads the module once, writes its version and description into `/var/lib/dpm/metadata/mymodule.meta`, and records each alias it declared whose name is free. From then on `dpm --list-modules` reports your module from that record and opens nothing, which is what keeps listing the modules on a system from executing them.
|
||||
|
||||
Removal is the counterpart:
|
||||
|
||||
```
|
||||
dpm --uninstall-module mymodule
|
||||
```
|
||||
|
||||
which deletes the record and every alias resolving to the module, leaving the `.so` where it is.
|
||||
|
||||
A module present in the module path with no record is reported in listings with a version of `<uninstalled>`. It still loads and runs when a caller requires it by name, with a warning, so a module put in place by hand works before anyone has installed it.
|
||||
|
||||
## Aliases
|
||||
|
||||
An alias is a second name a module answers to. Your declared aliases are recorded at installation; an operator adds more with:
|
||||
|
||||
```
|
||||
dpm --add-alias mymodule mm
|
||||
dpm --remove-alias mm
|
||||
dpm --list-aliases [mymodule]
|
||||
```
|
||||
|
||||
A name is recorded once. Adding a name that is already an alias, or that is an installed module's own name, is refused rather than repointed, so an existing route to a module is never taken over silently. Module names resolve before aliases, so a module's own name always reaches that module.
|
||||
|
||||
## A Working Example
|
||||
|
||||
|
||||
Reference in New Issue
Block a user