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

handle SIGINT and SIGTERM when pulling, and improve formatting of output #25

Merged
merged 1 commit into from
Nov 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ lib_src = [
'src/util/curl.cpp',
'src/util/fs.cpp',
'src/util/shell.cpp',
'src/util/signal.cpp',
'src/util/strings.cpp',
'src/util/subprocess.cpp',
]
Expand Down
10 changes: 7 additions & 3 deletions src/cli/add_remove.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -322,11 +322,14 @@ int image_rm([[maybe_unused]] const image_rm_args& args,
spdlog::debug("image_rm: treating {} as a label", U);
auto label = uenv::parse_uenv_label(U);
if (!label) {
spdlog::error("the label {} is not valid: {}", U,
label.error().message());
term::error("the label {} is not valid: {}", U,
label.error().message());
return 1;
}
if (!label->partially_qualified()) {
spdlog::error("no uenv matches {}", U);
term::error(
"the label {} does not provide at least name/version:tag", U);
return 1;
Expand All @@ -335,12 +338,13 @@ int image_rm([[maybe_unused]] const image_rm_args& args,

if (auto r = store->query(*label)) {
if (r->empty()) {
spdlog::error("no uenv matches {}", U);
term::error("no uenv matches {}", U);
return 1;
} else if (r->size() > 1) {
term::error("the pattern {} matches more than one uenv:", U);
print_record_set(*r, true);
term::msg("use a more specific pattern");
term::error("the pattern {} matches more than one "
"uenv:\n{}use a more specifc version",
U, format_record_set(*r));
return 1;
} else {
// check whether there are more than one tag attached to sha
Expand Down
74 changes: 43 additions & 31 deletions src/cli/pull.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// vim: ts=4 sts=4 sw=4 et

#include <csignal>
#include <filesystem>
#include <string>

Expand All @@ -17,6 +18,7 @@
#include <util/curl.h>
#include <util/expected.h>
#include <util/fs.h>
#include <util/signal.h>

#include "help.h"
#include "pull.h"
Expand Down Expand Up @@ -133,37 +135,47 @@ int image_pull([[maybe_unused]] const image_pull_args& args,
spdlog::debug("label in repo: {}", label_in_repo);

if (args.force || !sha_in_repo) {
bool pull_sqfs = !args.only_meta && (args.force || !sqfs_exists);
bool pull_meta = args.force || !meta_exists;

spdlog::debug("pull meta: {}", pull_meta);
spdlog::debug("pull sqfs: {}", pull_sqfs);

auto rego_url = site::registry_url();
spdlog::debug("registry url: {}", rego_url);

auto digests = oras::discover(rego_url, args.nspace, record);
if (!digests || digests->empty()) {
fmt::print("unable to pull image - rerun with -vvv flag and send "
"error report to service desk.\n");
return 1;
}
spdlog::debug("manifests: {}", fmt::join(*digests, ", "));

const auto digest = *(digests->begin());

if (auto okay = oras::pull_digest(rego_url, args.nspace, record, digest,
paths.store);
!okay) {
fmt::print("unable to pull image - rerun with -vvv flag and send "
"error report to service desk.\n");
return 1;
}

auto tag_result =
oras::pull_tag(rego_url, args.nspace, record, paths.store);
if (!tag_result) {
return 1;
try {
bool pull_sqfs = !args.only_meta && (args.force || !sqfs_exists);
bool pull_meta = args.force || !meta_exists;

spdlog::debug("pull meta: {}", pull_meta);
spdlog::debug("pull sqfs: {}", pull_sqfs);

auto rego_url = site::registry_url();
spdlog::debug("registry url: {}", rego_url);

auto digests = oras::discover(rego_url, args.nspace, record);
if (!digests || digests->empty()) {
fmt::print(
"unable to pull image - rerun with -vvv flag and send "
"error report to service desk.\n");
return 1;
}
spdlog::debug("manifests: {}", fmt::join(*digests, ", "));

const auto digest = *(digests->begin());

if (auto okay = oras::pull_digest(rego_url, args.nspace, record,
digest, paths.store);
!okay) {
fmt::print(
"unable to pull image - rerun with -vvv flag and send "
"error report to service desk.\n");
return 1;
}

auto tag_result =
oras::pull_tag(rego_url, args.nspace, record, paths.store);
if (!tag_result) {
return 1;
}
} catch (util::signal_exception& e) {
spdlog::debug("removing record {}", record);
store->remove(record.sha);
spdlog::debug("deleting path {}", paths.store);
std::filesystem::remove_all(paths.store);
raise(e.signal);
}
}

Expand Down
9 changes: 8 additions & 1 deletion src/uenv/oras.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
#include <uenv/oras.h>
#include <uenv/uenv.h>
#include <util/fs.h>
#include <util/sigint.h>
#include <util/signal.h>
#include <util/subprocess.h>

namespace uenv {
Expand Down Expand Up @@ -127,6 +127,8 @@ util::expected<void, int> pull_tag(const std::string& registry,
return util::unexpected{-1};
}

util::set_signal_catcher();

const fs::path& sqfs = destination / "store.squashfs";

std::size_t downloaded_mb{0u};
Expand All @@ -142,6 +144,11 @@ util::expected<void, int> pull_tag(const std::string& registry,
});
while (!proc->finished()) {
std::this_thread::sleep_for(500ms);
// handle a signacl, usually SIGTERM or SIGINT
if (util::signal_raised()) {
spdlog::warn("signal raised - interrupting download");
throw util::signal_exception(util::last_signal_raised());
}
if (fs::is_regular_file(sqfs)) {
auto downloaded_bytes = fs::file_size(sqfs);
downloaded_mb = downloaded_bytes / (1024 * 1024);
Expand Down
62 changes: 23 additions & 39 deletions src/uenv/print.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,23 @@

namespace uenv {

void print_record_set(const record_set& records, bool no_header) {
std::string format_record_set(const record_set& records, bool no_header) {
if (records.empty()) {
if (!no_header) {
fmt::println("no matching uenv");
return "no matching uenv\n";
}
return;
return "";
}

auto size_string = [](std::size_t size) {
auto size_mb = size / (1024 * 1024);
return fmt::format(std::locale("en_US.UTF-8"), "{:<{}L}", size_mb, 6);
};
// print the records
std::size_t w_name = std::string_view("uenv").size();
std::size_t w_sys = std::string_view("system").size();
std::size_t w_arch = std::string_view("arch").size();
std::size_t w_size = std::string_view("size(MB)").size();
std::size_t w_date = std::string_view("yyyy/mm/dd").size();
std::size_t w_id = 16;

Expand All @@ -28,56 +33,35 @@ void print_record_set(const record_set& records, bool no_header) {
r.name.size() + r.version.size() + r.tag.size() + 2);
w_sys = std::max(w_sys, r.system.size());
w_arch = std::max(w_arch, r.uarch.size());
w_size = std::max(w_size, size_string(r.size_byte).size());
}
w_name += 2;
w_sys += 2;
w_arch += 2;
w_size += 2;
w_date += 2;
w_id += 2;
std::string result;
if (!no_header) {
auto header = fmt::format("{:<{}}{:<{}}{:<{}}{:<{}}{:<{}}\n", "uenv",
w_name, "arch", w_arch, "system", w_sys, "id",
w_id, "date", w_date);
fmt::print("{}", color::yellow(header));
auto header =
fmt::format("{:<{}}{:<{}}{:<{}}{:<{}}{:<{}}{:<{}}\n", "uenv",
w_name, "arch", w_arch, "system", w_sys, "id", w_id,
"size(MB)", w_size, "date", w_date);
result += fmt::format("{}", color::yellow(header));
}
for (auto& r : records) {
auto name = fmt::format("{}/{}:{}", r.name, r.version, r.tag);
fmt::print("{:<{}}{:<{}}{:<{}}{:<{}}{:s}\n", name, w_name, r.uarch,
w_arch, r.system, w_sys, r.id.string(), w_id, r.date);
}
}

std::string format_record_set(const record_set& records) {
if (records.empty()) {
return "";
}

// print the records
std::size_t w_name = std::string_view("uenv").size();
std::size_t w_sys = std::string_view("system").size();
std::size_t w_arch = std::string_view("arch").size();
std::size_t w_id = 16;

for (auto& r : records) {
w_name = std::max(w_name,
r.name.size() + r.version.size() + r.tag.size() + 2);
w_sys = std::max(w_sys, r.system.size());
w_arch = std::max(w_arch, r.uarch.size());
}
w_name += 2;
w_sys += 2;
w_arch += 2;
w_id += 2;

std::string result{};
for (auto& r : records) {
auto name = fmt::format("{}/{}:{}", r.name, r.version, r.tag);
result +=
fmt::format("{:<{}}{:<{}}{:<{}}{:<{}}{:s}\n", name, w_name, r.uarch,
w_arch, r.system, w_sys, r.id.string(), w_id, r.date);
fmt::format("{:<{}}{:<{}}{:<{}}{:<{}}{:{}}{:s}\n", name, w_name,
r.uarch, w_arch, r.system, w_sys, r.id.string(), w_id,
size_string(r.size_byte), w_size, r.date);
}

return result;
}

void print_record_set(const record_set& records, bool no_header) {
fmt::print("{}", format_record_set(records, no_header));
}

} // namespace uenv
2 changes: 1 addition & 1 deletion src/uenv/print.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,5 @@

namespace uenv {
void print_record_set(const record_set& result, bool no_header);
std::string format_record_set(const record_set& records);
std::string format_record_set(const record_set& records, bool no_header = true);
} // namespace uenv
64 changes: 0 additions & 64 deletions src/util/sigint.h

This file was deleted.

37 changes: 37 additions & 0 deletions src/util/signal.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
#include <atomic>
#include <csignal>

#include <util/signal.h>

namespace util {

std::atomic<bool> signal_received{false};
std::atomic<int> last_signal{0};

void signal_handler(int signal) {
if (signal == SIGINT || signal == SIGTERM) {
signal_received.store(true);
last_signal.store(signal);
}
}

void set_signal_catcher() {
signal_received.store(false);
struct sigaction h;

h.sa_handler = signal_handler;
sigemptyset(&h.sa_mask);
h.sa_flags = SA_RESETHAND;
sigaction(SIGINT, &h, nullptr);
sigaction(SIGTERM, &h, nullptr);
}

bool signal_raised() {
return signal_received.exchange(false);
}

int last_signal_raised() {
return last_signal.load();
}

} // namespace util
25 changes: 25 additions & 0 deletions src/util/signal.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#pragma once

#include <exception>

#include <fmt/format.h>

namespace util {

class signal_exception : public std::exception {
public:
const int signal;
const std::string msg;
signal_exception(int signal)
: signal(signal), msg(fmt::format("signal {} raised", signal)) {
}
const char* what() const throw() {
return msg.c_str();
}
};

void set_signal_catcher();
bool signal_raised();
int last_signal_raised();

} // namespace util
Loading