Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Expose ALPM DB over HTTP #30

Merged
merged 10 commits into from
May 8, 2024
105 changes: 66 additions & 39 deletions daemon/persistence/box/export/AlpmDBExporter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,27 +30,20 @@

namespace bxt::Persistence::Box {

void create_relative_symlink(const std::filesystem::path& target,
const std::filesystem::path& link) {
if (std::filesystem::is_symlink(link)) { return; }
std::expected<void, FsError>
create_relative_symlink(const std::filesystem::path& target,
const std::filesystem::path& link) {
if (std::filesystem::is_symlink(link)) { return {}; }
std::error_code ec;

const auto relative_target =
std::filesystem::relative(target, link.parent_path(), ec);

if (ec) {
logf("Failed to get relative symlink path. The error is \"{}\". Box "
"will be malformed, exiting.",
ec.message());
exit(1);
}
if (ec) { return bxt::make_error<FsError>(ec); }

std::filesystem::create_symlink(relative_target, link, ec);
if (ec) {
logf("Failed to create symlink. The error is \"{}\". Box will be "
"malformed, exiting.",
ec.message());
exit(1);
}
if (ec) { return bxt::make_error<FsError>(ec); }

return {};
}

AlpmDBExporter::AlpmDBExporter(
Expand Down Expand Up @@ -80,13 +73,14 @@ coro::task<void> AlpmDBExporter::export_to_disk() {
phmap::parallel_flat_hash_map<PackageSectionDTO, Archive::Writer> writers;

for (const auto& section : m_dirty_sections) {
logd("Exporter: \"{}\" export into the package manager format started",
logi("Exporter: \"{}\" export into the package manager format started",
std::string(section));

auto writer = setup_writer(section);

if (!writer.has_value()) {
logf("Exporter: Writer cannot be created, the error is \"{}\"",
logf("Exporter: Writer cannot be created, the error is \"{}\". "
"Stopping...",
writer.error().what());
co_return;
}
Expand All @@ -101,7 +95,7 @@ coro::task<void> AlpmDBExporter::export_to_disk() {

if (!deserialized.has_value()) {
loge("Exporter: Key \"{}\" is not valid. Skipping...", key);
return Utilities::NavigationAction::Next;
return Utilities::NavigationAction::Stop;
romangg marked this conversation as resolved.
Show resolved Hide resolved
}

const auto& [section, name] = *deserialized;
Expand All @@ -111,60 +105,88 @@ coro::task<void> AlpmDBExporter::export_to_disk() {
package.descriptions);

if (!preferred_location.has_value()) {
loge("Can't find preferred location for {}. "
"Skipping.",
logf("Exporter: Can't find preferred location for \"{}\". "
"Stopping...",
name);
return Utilities::NavigationAction::Next;
return Utilities::NavigationAction::Stop;
}

const auto version =
package.descriptions.at(*preferred_location)
.descfile.get("VERSION");

if (!version.has_value()) {
loge("Exporter: Version for \"{}\" is not valid. "
"Skipping...",
logf("Exporter: Version for \"{}\" is not valid. "
"Stopping...",
key);

return Utilities::NavigationAction::Next;
return Utilities::NavigationAction::Stop;
}

logd(
logi(
"Exporter: Description for \"{}/{}-{}\" is being added... ",
std::string(section), name, *version);

const auto preferred_description = package.descriptions.at(
*Core::Domain::select_preferred_pool_location(
package.descriptions));

Utilities::AlpmDb::DatabaseUtils::write_buffer_to_archive(
*writer, fmt::format("{}-{}/desc", name, *version),
preferred_description.descfile.desc);
if (auto write_ok = Utilities::AlpmDb::DatabaseUtils::
write_buffer_to_archive(
*writer, fmt::format("{}-{}/desc", name, *version),
preferred_description.descfile.desc);
!write_ok) {
logf("Exporter: Can't write \"{}/{}-{}\" description to "
"the archive. The error is \"{}\"",
std::string(section), name, *version,
write_ok.error().what());

return Utilities::NavigationAction::Stop;
}

const auto filepath_link = std::filesystem::absolute(
m_box_path / std::string(section)
/ preferred_description.filepath.filename());

create_relative_symlink(preferred_description.filepath,
filepath_link);
if (auto link_created_ok = create_relative_symlink(
preferred_description.filepath, filepath_link);
!link_created_ok) {
logf("Exporter: Can't link the package file for "
"\"{}/{}-{}\". The error is \"{}\". Stopping the "
"export...",
std::string(section), name, *version,
link_created_ok.error().what());

return Utilities::NavigationAction::Stop;
}

if (preferred_description.signature_path) {
const auto signature_link = std::filesystem::absolute(
m_box_path / std::string(section)
/ preferred_description.signature_path->filename());

create_relative_symlink(
*preferred_description.signature_path, signature_link);
if (auto link_created_ok = create_relative_symlink(
*preferred_description.signature_path,
signature_link);
!link_created_ok) {
logf("Exporter: Can't link the signature file for "
"\"{}/{}-{}\". The error is \"{}\". Stopping the "
"export...",
std::string(section), name, *version,
link_created_ok.error().what());

return Utilities::NavigationAction::Stop;
}
}

logd("Exporter: Description for \"{}/{}-{}\" is added",
logi("Exporter: Description and link for \"{}/{}-{}\" is added",
std::string(section), name, *version);

return Utilities::NavigationAction::Next;
},
std::string(section));

logd("Exporter: \"{}\" export finished", std::string(section));
logi("Exporter: \"{}\" export finished", std::string(section));
}

m_dirty_sections.clear();
Expand All @@ -178,7 +200,7 @@ void AlpmDBExporter::add_dirty_sections(
std::make_move_iterator(sections.end()));
}

std::expected<Archive::Writer, Archive::LibArchiveError>
std::expected<Archive::Writer, bxt::Error>
AlpmDBExporter::setup_writer(const PackageSectionDTO& section) {
Archive::Writer writer;

Expand All @@ -193,13 +215,18 @@ std::expected<Archive::Writer, Archive::LibArchiveError>
m_box_path / std::string(section)
/ fmt::format("{}.db.tar.zst", section.repository);

auto open_ok = writer.open_filename(archive_path);
if (!open_ok.has_value()) { return std::unexpected(open_ok.error()); }
if (auto open_ok = writer.open_filename(archive_path); !open_ok) {
return std::unexpected(std::move(open_ok.error()));
}

const auto archive_link = m_box_path / std::string(section)
/ fmt::format("{}.db", section.repository);

create_relative_symlink(archive_path, archive_link);
if (auto link_created_ok =
create_relative_symlink(archive_path, archive_link);
!link_created_ok) {
return std::unexpected(link_created_ok.error());
}

return writer;
}
Expand Down
3 changes: 2 additions & 1 deletion daemon/persistence/box/export/AlpmDBExporter.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include "persistence/box/BoxOptions.h"
#include "persistence/box/export/ExporterBase.h"
#include "persistence/box/store/PackageStoreBase.h"
#include "utilities/Error.h"
#include "utilities/libarchive/Error.h"
#include "utilities/libarchive/Writer.h"

Expand All @@ -35,7 +36,7 @@ class AlpmDBExporter : public ExporterBase {
std::set<Core::Application::PackageSectionDTO>&& override) override;

private:
std::expected<Archive::Writer, Archive::LibArchiveError>
std::expected<Archive::Writer, bxt::Error>
setup_writer(const PackageSectionDTO& section);
std::filesystem::path m_box_path;
std::set<Core::Application::PackageSectionDTO> m_sections;
Expand Down
28 changes: 22 additions & 6 deletions daemon/utilities/alpmdb/Database.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,20 +47,36 @@ coro::task<Result<void>>
visitor);

template<typename TBuffer>
void write_buffer_to_archive(Archive::Writer& writer,
const std::string& name,
const TBuffer& buffer) {
Result<void> write_buffer_to_archive(Archive::Writer& writer,
const std::string& name,
const TBuffer& buffer) {
auto header = Archive::Header::default_file();

archive_entry_set_pathname(header, name.c_str());
archive_entry_set_size(header, buffer.size());

auto entry = writer.start_write(header);

if (!entry.has_value()) { return; }
if (!entry.has_value()) {
return bxt::make_error_with_source<DatabaseError>(
std::move(entry.error()), DatabaseError::ErrorType::IOError);
}

entry->write({buffer.begin(), buffer.end()});
entry->finish();
auto write_ok = entry->write({buffer.begin(), buffer.end()});

if (!write_ok.has_value()) {
return bxt::make_error_with_source<DatabaseError>(
std::move(write_ok.error()), DatabaseError::ErrorType::IOError);
}

auto finish_ok = entry->finish();

if (!finish_ok.has_value()) {
return bxt::make_error_with_source<DatabaseError>(
std::move(finish_ok.error()), DatabaseError::ErrorType::IOError);
}

return {};
}

coro::task<Result<void>>
Expand Down
15 changes: 15 additions & 0 deletions daemon/utilities/errors/FsError.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
/* === This file is part of bxt ===
*
* SPDX-FileCopyrightText: 2024 Artem Grinev <agrinev@manjaro.org>
* SPDX-License-Identifier: AGPL-3.0-or-later
*
*/
#pragma once
#include "utilities/Error.h"

#include <system_error>
namespace bxt {
struct FsError : public bxt::Error {
FsError(const std::error_code& ec) { message = ec.message(); }
};
} // namespace bxt
9 changes: 6 additions & 3 deletions daemon/utilities/libarchive/Error.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,17 @@

namespace Archive {

struct InvalidEntryError : public bxt::Error {
struct ArchiveError : public bxt::Error {
ArchiveError() { message = "Unknown Archive error"; }
};

struct InvalidEntryError : public ArchiveError {
InvalidEntryError() { message = "The entry has no linked archive!"; }
};

struct LibArchiveError : public bxt::Error {
struct LibArchiveError : public ArchiveError {
explicit LibArchiveError(archive* archive) {
message = archive_error_string(archive);
}
};

} // namespace Archive
4 changes: 1 addition & 3 deletions daemon/utilities/libarchive/Writer.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,7 @@ class Writer {
public:
Entry() = default;

template<typename T>
using Result =
std::expected<T, std::variant<InvalidEntryError, LibArchiveError>>;
template<typename T> using Result = std::expected<T, ArchiveError>;

// Use the Result template for function return type
Result<void> write(const std::vector<uint8_t>& data);
Expand Down