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:
148
src/cli/dpm.cpp
148
src/cli/dpm.cpp
@@ -50,11 +50,19 @@ namespace {
|
||||
"Options:\n"
|
||||
" -c, --config-dir PATH Configuration directory (default /etc/dpm/conf.d/)\n"
|
||||
" -m, --module-path PATH Module directory (overrides configuration)\n"
|
||||
" -M, --metadata-dir PATH Module record directory (overrides configuration)\n"
|
||||
" -r, --root PATH Target root for package operations (default /)\n"
|
||||
" -L, --log-level LEVEL FATAL, ERROR, WARN, INFO, or DEBUG\n"
|
||||
" -l, --list-modules List available modules\n"
|
||||
" -h, --help Show this help message\n"
|
||||
"\n"
|
||||
"Module records:\n"
|
||||
" --install-module NAME Record what a module reports about itself\n"
|
||||
" --uninstall-module NAME Remove a module's record and its aliases\n"
|
||||
" --add-alias MODULE ALIAS Record an alternate name for a module\n"
|
||||
" --remove-alias ALIAS Remove an alternate name\n"
|
||||
" --list-aliases [MODULE] List recorded aliases\n"
|
||||
"\n"
|
||||
"For module-specific help, use: dpm <module> help\n");
|
||||
}
|
||||
|
||||
@@ -125,7 +133,7 @@ namespace {
|
||||
dpm_cursor_free(cur);
|
||||
|
||||
if (infos.empty()) {
|
||||
std::printf("No valid modules found in %s\n",
|
||||
std::printf("No modules found in %s\n",
|
||||
dpm_get_resolved_module_path(ctx));
|
||||
return 0;
|
||||
}
|
||||
@@ -152,17 +160,70 @@ namespace {
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Prints the table of recorded aliases
|
||||
*
|
||||
* @param ctx The libdpm-core.so context
|
||||
* @param module NULL for every alias, or a module name to filter by
|
||||
* @return 0 on success, 1 on failure
|
||||
*/
|
||||
int list_aliases(dpm_ctx* ctx, const char* module) {
|
||||
dpm_alias_cursor* cur = dpm_list_module_aliases(ctx, module);
|
||||
if (!cur) {
|
||||
const char* err = dpm_get_last_error(ctx);
|
||||
std::fprintf(stderr, "dpm: %s\n", err ? err : "alias listing failed");
|
||||
return 1;
|
||||
}
|
||||
|
||||
std::vector<dpm_alias_info> infos;
|
||||
dpm_alias_info info;
|
||||
while (dpm_alias_cursor_next(cur, &info) == 0) {
|
||||
infos.push_back(info);
|
||||
}
|
||||
|
||||
if (infos.empty()) {
|
||||
std::printf("No aliases recorded\n");
|
||||
dpm_alias_cursor_free(cur);
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t alias_w = std::strlen("ALIAS");
|
||||
for (const auto& i : infos) {
|
||||
alias_w = std::max(alias_w, std::strlen(i.alias));
|
||||
}
|
||||
|
||||
std::printf("%-*s %s\n", static_cast<int>(alias_w), "ALIAS",
|
||||
"MODULE");
|
||||
for (const auto& i : infos) {
|
||||
std::printf("%-*s %s\n", static_cast<int>(alias_w), i.alias,
|
||||
i.module);
|
||||
}
|
||||
|
||||
dpm_alias_cursor_free(cur);
|
||||
return 0;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
dpm_open_overrides overrides = {nullptr, nullptr, nullptr, -1};
|
||||
dpm_open_overrides overrides = {nullptr, nullptr, nullptr, -1, nullptr};
|
||||
bool list = false;
|
||||
|
||||
/* Holders for --opt=value forms. */
|
||||
std::string config_dir;
|
||||
std::string module_path;
|
||||
std::string metadata_dir;
|
||||
std::string root;
|
||||
|
||||
/* Record operations, each holding what its flag was given. */
|
||||
const char* install_module = nullptr;
|
||||
const char* uninstall_module = nullptr;
|
||||
const char* alias_module = nullptr;
|
||||
const char* alias_name = nullptr;
|
||||
const char* remove_alias = nullptr;
|
||||
const char* list_alias_of = nullptr;
|
||||
bool aliases_requested = false;
|
||||
|
||||
int i = 1;
|
||||
for (; i < argc; i++) {
|
||||
const char* arg = argv[i];
|
||||
@@ -195,6 +256,11 @@ int main(int argc, char** argv) {
|
||||
if (!v) { return 1; }
|
||||
module_path = v;
|
||||
overrides.module_path = module_path.c_str();
|
||||
} else if (option_matches(arg, "-M", "--metadata-dir", &inline_value)) {
|
||||
const char* v = take_value();
|
||||
if (!v) { return 1; }
|
||||
metadata_dir = v;
|
||||
overrides.metadata_dir = metadata_dir.c_str();
|
||||
} else if (option_matches(arg, "-r", "--root", &inline_value)) {
|
||||
const char* v = take_value();
|
||||
if (!v) { return 1; }
|
||||
@@ -214,6 +280,34 @@ int main(int argc, char** argv) {
|
||||
} else if (std::strcmp(arg, "-l") == 0 ||
|
||||
std::strcmp(arg, "--list-modules") == 0) {
|
||||
list = true;
|
||||
} else if (option_matches(arg, "--install-module", "--install-module",
|
||||
&inline_value)) {
|
||||
install_module = take_value();
|
||||
if (!install_module) { return 1; }
|
||||
} else if (option_matches(arg, "--uninstall-module",
|
||||
"--uninstall-module", &inline_value)) {
|
||||
uninstall_module = take_value();
|
||||
if (!uninstall_module) { return 1; }
|
||||
} else if (std::strcmp(arg, "--add-alias") == 0) {
|
||||
if (i + 2 >= argc) {
|
||||
std::fprintf(stderr,
|
||||
"dpm: --add-alias requires MODULE and ALIAS\n");
|
||||
return 1;
|
||||
}
|
||||
alias_module = argv[++i];
|
||||
alias_name = argv[++i];
|
||||
} else if (option_matches(arg, "--remove-alias", "--remove-alias",
|
||||
&inline_value)) {
|
||||
remove_alias = take_value();
|
||||
if (!remove_alias) { return 1; }
|
||||
} else if (std::strcmp(arg, "--list-aliases") == 0) {
|
||||
aliases_requested = true;
|
||||
|
||||
// The module argument is optional, so a following word is
|
||||
// taken only when it is not another option.
|
||||
if (i + 1 < argc && argv[i + 1][0] != '-') {
|
||||
list_alias_of = argv[++i];
|
||||
}
|
||||
} else if (std::strcmp(arg, "-h") == 0 ||
|
||||
std::strcmp(arg, "--help") == 0) {
|
||||
show_help();
|
||||
@@ -239,6 +333,56 @@ int main(int argc, char** argv) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (install_module) {
|
||||
int rc = dpm_install_module(ctx, install_module);
|
||||
if (rc != 0) {
|
||||
const char* err = dpm_get_last_error(ctx);
|
||||
std::fprintf(stderr, "dpm: %s\n",
|
||||
err ? err : "module could not be installed");
|
||||
}
|
||||
dpm_close(ctx);
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (uninstall_module) {
|
||||
int rc = dpm_uninstall_module(ctx, uninstall_module);
|
||||
if (rc != 0) {
|
||||
const char* err = dpm_get_last_error(ctx);
|
||||
std::fprintf(stderr, "dpm: %s\n",
|
||||
err ? err : "module could not be uninstalled");
|
||||
}
|
||||
dpm_close(ctx);
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (alias_module) {
|
||||
int rc = dpm_add_module_alias(ctx, alias_module, alias_name);
|
||||
if (rc != 0) {
|
||||
const char* err = dpm_get_last_error(ctx);
|
||||
std::fprintf(stderr, "dpm: %s\n",
|
||||
err ? err : "alias could not be recorded");
|
||||
}
|
||||
dpm_close(ctx);
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (remove_alias) {
|
||||
int rc = dpm_remove_module_alias(ctx, remove_alias);
|
||||
if (rc != 0) {
|
||||
const char* err = dpm_get_last_error(ctx);
|
||||
std::fprintf(stderr, "dpm: %s\n",
|
||||
err ? err : "alias could not be removed");
|
||||
}
|
||||
dpm_close(ctx);
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (aliases_requested) {
|
||||
int rc = list_aliases(ctx, list_alias_of);
|
||||
dpm_close(ctx);
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (i >= argc) {
|
||||
show_help();
|
||||
dpm_close(ctx);
|
||||
|
||||
Reference in New Issue
Block a user