[M6] resolver: pkg-config probe + codegen for PkgConfig
This commit is contained in:
@@ -64,6 +64,7 @@ auto Database::resolve(const std::string& package, const std::string& version,
|
||||
.find_package = row.find_package,
|
||||
.targets = row.targets,
|
||||
.source = row.source,
|
||||
.pkg_config_module = row.pkg_config_module,
|
||||
};
|
||||
}
|
||||
return std::unexpected(util::Error{
|
||||
|
||||
@@ -15,6 +15,16 @@ struct Recipe {
|
||||
std::vector<std::string> targets; // post-substitution
|
||||
std::string source; // 'curated' | 'manual' | etc.
|
||||
|
||||
// When set, the dep is consumed via PkgConfig instead of a normal
|
||||
// find_package. Codegen emits
|
||||
// find_package(PkgConfig REQUIRED)
|
||||
// pkg_check_modules(<UPPER> REQUIRED IMPORTED_TARGET <pkg_config_module>)
|
||||
// and the recipe's `targets` list holds the synthesized
|
||||
// PkgConfig::<UPPER> entries. `find_package` for these recipes is
|
||||
// the literal string "PkgConfig REQUIRED" — kept consistent so
|
||||
// overlay rows don't need a sentinel.
|
||||
std::optional<std::string> pkg_config_module;
|
||||
|
||||
bool operator==(const Recipe&) const = default;
|
||||
};
|
||||
|
||||
@@ -29,6 +39,7 @@ struct OverlayRow {
|
||||
std::vector<std::string> targets;
|
||||
std::string source;
|
||||
std::int64_t verified_at = 0;
|
||||
std::optional<std::string> pkg_config_module;
|
||||
};
|
||||
|
||||
// RAII wrapper for an open sqlite3 connection used by the overlay database.
|
||||
|
||||
@@ -90,6 +90,26 @@ auto overlay_open(const std::filesystem::path& path)
|
||||
});
|
||||
}
|
||||
|
||||
// Schema migration: legacy overlays predate pkg_config_module.
|
||||
// SQLite ADD COLUMN errors when the column already exists; treat
|
||||
// "duplicate column" as success.
|
||||
constexpr const char* MIGRATE_PC =
|
||||
"ALTER TABLE recipes ADD COLUMN pkg_config_module TEXT";
|
||||
char* mig_err = nullptr;
|
||||
if (sqlite3_exec(state->handle(), MIGRATE_PC, nullptr, nullptr, &mig_err) !=
|
||||
SQLITE_OK) {
|
||||
if (mig_err && std::string_view{mig_err}.find("duplicate column") ==
|
||||
std::string_view::npos) {
|
||||
std::string msg = std::format("cannot migrate overlay schema: {}",
|
||||
mig_err ? mig_err : "?");
|
||||
sqlite3_free(mig_err);
|
||||
return std::unexpected(util::Error{
|
||||
util::ErrorCode::LinkdbCorrupt, std::move(msg), "", path, std::nullopt,
|
||||
});
|
||||
}
|
||||
sqlite3_free(mig_err);
|
||||
}
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
@@ -99,8 +119,8 @@ auto overlay_insert_manual(OverlayState& state, const std::string& package,
|
||||
constexpr const char* SQL =
|
||||
"INSERT OR REPLACE INTO recipes "
|
||||
"(package, version_range, nixpkgs_attr, find_package, targets, components, source, "
|
||||
" verified_at) "
|
||||
"VALUES (?, ?, ?, ?, ?, NULL, 'manual', ?)";
|
||||
" verified_at, pkg_config_module) "
|
||||
"VALUES (?, ?, ?, ?, ?, NULL, 'manual', ?, ?)";
|
||||
|
||||
sqlite3* db = state.handle();
|
||||
sqlite3_stmt* stmt = nullptr;
|
||||
@@ -119,6 +139,11 @@ auto overlay_insert_manual(OverlayState& state, const std::string& package,
|
||||
sqlite3_bind_text(stmt, 4, r.find_package.c_str(), -1, SQLITE_TRANSIENT);
|
||||
sqlite3_bind_text(stmt, 5, targets_str.c_str(), -1, SQLITE_TRANSIENT);
|
||||
sqlite3_bind_int64(stmt, 6, now);
|
||||
if (r.pkg_config_module) {
|
||||
sqlite3_bind_text(stmt, 7, r.pkg_config_module->c_str(), -1, SQLITE_TRANSIENT);
|
||||
} else {
|
||||
sqlite3_bind_null(stmt, 7);
|
||||
}
|
||||
|
||||
auto rc = sqlite3_step(stmt);
|
||||
sqlite3_finalize(stmt);
|
||||
@@ -137,8 +162,8 @@ auto overlay_insert(OverlayState& state, const std::string& package,
|
||||
constexpr const char* SQL =
|
||||
"INSERT OR REPLACE INTO recipes "
|
||||
"(package, version_range, nixpkgs_attr, find_package, targets, components, source, "
|
||||
" verified_at) "
|
||||
"VALUES (?, ?, ?, ?, ?, NULL, ?, ?)";
|
||||
" verified_at, pkg_config_module) "
|
||||
"VALUES (?, ?, ?, ?, ?, NULL, ?, ?, ?)";
|
||||
|
||||
sqlite3* db = state.handle();
|
||||
sqlite3_stmt* stmt = nullptr;
|
||||
@@ -155,6 +180,11 @@ auto overlay_insert(OverlayState& state, const std::string& package,
|
||||
sqlite3_bind_text(stmt, 5, targets_str.c_str(), -1, SQLITE_TRANSIENT);
|
||||
sqlite3_bind_text(stmt, 6, source.c_str(), -1, SQLITE_TRANSIENT);
|
||||
sqlite3_bind_int64(stmt, 7, verified_at);
|
||||
if (r.pkg_config_module) {
|
||||
sqlite3_bind_text(stmt, 8, r.pkg_config_module->c_str(), -1, SQLITE_TRANSIENT);
|
||||
} else {
|
||||
sqlite3_bind_null(stmt, 8);
|
||||
}
|
||||
|
||||
auto rc = sqlite3_step(stmt);
|
||||
sqlite3_finalize(stmt);
|
||||
@@ -245,7 +275,8 @@ auto overlay_evict_auto(OverlayState& state, const std::string& package)
|
||||
auto overlay_query(OverlayState& state, const std::string& package)
|
||||
-> util::Result<std::vector<OverlayRow>> {
|
||||
constexpr const char* SQL =
|
||||
"SELECT version_range, nixpkgs_attr, find_package, targets, source, verified_at "
|
||||
"SELECT version_range, nixpkgs_attr, find_package, targets, source, verified_at, "
|
||||
" pkg_config_module "
|
||||
"FROM recipes WHERE package = ?";
|
||||
|
||||
sqlite3* db = state.handle();
|
||||
@@ -276,6 +307,9 @@ auto overlay_query(OverlayState& state, const std::string& package)
|
||||
}
|
||||
row.source = column_text(stmt, 4);
|
||||
row.verified_at = sqlite3_column_int64(stmt, 5);
|
||||
if (sqlite3_column_type(stmt, 6) != SQLITE_NULL) {
|
||||
row.pkg_config_module = column_text(stmt, 6);
|
||||
}
|
||||
out.push_back(std::move(row));
|
||||
}
|
||||
sqlite3_finalize(stmt);
|
||||
|
||||
Reference in New Issue
Block a user