Modules can report why they failed

A module had one channel back to its caller: the int returned from
dpm_module_execute, handed through by dpm_execute. Any detail behind
that number could only reach a log, so a caller wanting the reason had
to read output rather than ask for it.

dpm_set_last_error joins the exported API. A module records its reason
on the context handed to its entry point, which belongs to the caller,
and the caller reads it back with dpm_get_last_error.

The two accessors on the context now say what they do to it:
dpm_module_path becomes dpm_get_resolved_module_path, naming the value
it reports rather than the setting it came from, and dpm_last_error
becomes dpm_get_last_error, pairing with the setter.

Path normalization moves to sanitizers.cpp, which holds the conversions
that put a value written by a person into the single form the library
stores it in.
This commit is contained in:
2026-08-19 00:49:42 -04:00
parent c71913ded9
commit 50d71ca55f
14 changed files with 162 additions and 58 deletions

View File

@@ -221,7 +221,7 @@ void dpm_close(dpm_ctx* ctx);
* @param ctx The libdpm-core.so context
* @param name The module name (its filename minus .so)
* @return A module handle owned by the context, or NULL on failure
* with the precise reason retrievable via dpm_last_error()
* with the precise reason retrievable via dpm_get_last_error()
*/
DPM_PUBLIC_ABI_EXPORT
dpm_module* dpm_require(dpm_ctx* ctx, const char* name);
@@ -356,7 +356,24 @@ void dpm_log(dpm_ctx* ctx, int level, const char* message);
* @return The module directory path this context resolved
*/
DPM_PUBLIC_ABI_EXPORT
const char* dpm_module_path(dpm_ctx* ctx);
const char* dpm_get_resolved_module_path(dpm_ctx* ctx);
/**
* @brief Records a failure reason on the context
*
* A module reports why it failed by recording the reason here and
* returning nonzero, which carries detail its return code cannot.
*
* The context holds one reason at a time, so the most recent write is
* what dpm_get_last_error reports. Record the reason immediately before
* returning, so that later work does not replace it.
*
* @param ctx The libdpm-core.so context; NULL is a no-op
* @param msg The failure description, copied into the context; NULL is
* a no-op
*/
DPM_PUBLIC_ABI_EXPORT
void dpm_set_last_error(dpm_ctx* ctx, const char* msg);
/**
* @brief Returns the most recent failure recorded on the context
@@ -366,7 +383,7 @@ const char* dpm_module_path(dpm_ctx* ctx);
* NULL if none; overwritten by the next failing call
*/
DPM_PUBLIC_ABI_EXPORT
const char* dpm_last_error(dpm_ctx* ctx);
const char* dpm_get_last_error(dpm_ctx* ctx);
/* ------------------------------------------------------------------ */
/* Module contract (implemented by modules, called by libdpm-core.so) */

View File

@@ -89,5 +89,5 @@ namespace dpm_core {
* @param ctx The libdpm-core.so context; NULL is a no-op
* @param msg The failure description
*/
void set_error(dpm_ctx* ctx, const std::string& msg);
void set_last_error(dpm_ctx* ctx, const std::string& msg);
} // namespace dpm_core

View File

@@ -0,0 +1,35 @@
/**
* @file sanitizers.hpp
* @brief Normalizing a value into the shape the library stores it in
*
* @copyright Copyright (c) 2026 SILO GROUP LLC
* @author Chris Punches <chris.punches@silogroup.org>
*
* Part of the Dark Horse Linux Package Manager (DPM)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#pragma once
#include <string>
namespace dpm_core {
/**
* @brief Appends a trailing slash when one is absent
*
* @param s The path to normalize
* @return The path, ending in a slash unless it is empty
*/
std::string with_trailing_slash(std::string s);
} // namespace dpm_core