Skip to content

Commit

Permalink
handle SIGINT and SIGTERM when pulling, and improve formatting of out…
Browse files Browse the repository at this point in the history
…put (#25)
  • Loading branch information
bcumming authored Nov 29, 2024
1 parent 046303f commit 8a082c7
Show file tree
Hide file tree
Showing 10 changed files with 163 additions and 172 deletions.
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

0 comments on commit 8a082c7

Please sign in to comment.