Add --list-volumes to list named volumes

Long-only (no free short letter left), lists each volume's name and
host directory, tab-aligned the same way -l/--list-images already
aligns name:tag output -- list_volumes_command() reuses that scheme.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Gv3s5jckJKzh6JkMoi2Akz
This commit is contained in:
2026-08-21 13:15:28 +00:00
parent aac656be31
commit afca0f7ce3
3 changed files with 55 additions and 16 deletions
+39 -7
View File
@@ -41,16 +41,18 @@ namespace {
constexpr std::array<std::string_view, 2> kRequiredTools = {"containers-storage", "bwrap"};
enum class Mode { kNone, kMount, kUnmount, kTest, kRun, kCleanup, kListImages, kVolume };
enum class Mode { kNone, kMount, kUnmount, kTest, kRun, kCleanup, kListImages, kVolume, kListVolumes };
// --log-level/--user/--group have no short form (--log-level's was freed up so -l
// could become --list-images; -u is already --umount), so they need long-option
// vals outside the printable-char range short options use.
// --log-level/--user/--group/--list-volumes have no short form (--log-level's was
// freed up so -l could become --list-images; -u is already --umount; --list-volumes
// has no natural free letter left), so they need long-option vals outside the
// printable-char range short options use.
constexpr int kLogLevelOpt = 256;
constexpr int kUserOpt = 257;
constexpr int kGroupOpt = 258;
constexpr int kListVolumesOpt = 259;
constexpr std::array<struct option, 14> kLongOptions = {{
constexpr std::array<struct option, 15> kLongOptions = {{
{"help", no_argument, nullptr, 'h'},
{"version", no_argument, nullptr, 'V'},
{"test", no_argument, nullptr, 't'},
@@ -64,6 +66,7 @@ constexpr std::array<struct option, 14> kLongOptions = {{
{"user", required_argument, nullptr, kUserOpt},
{"group", required_argument, nullptr, kGroupOpt},
{"volume", required_argument, nullptr, 'v'},
{"list-volumes", no_argument, nullptr, kListVolumesOpt},
{nullptr, 0, nullptr, 0},
}};
@@ -75,6 +78,7 @@ void print_usage(const char* prog) {
" {0} -c|--cleanup <layer-id>\n"
" {0} -l|--list-images <directory>\n"
" {0} -v|--volume <name> <directory>\n"
" {0} --list-volumes\n"
" {0} -t|--test\n"
" {0} -h|--help\n"
" {0} -V|--version\n"
@@ -109,6 +113,8 @@ void print_usage(const char* prog) {
" -v, --volume <name> <dir> create a named volume mapped to a host directory\n"
" (created if missing), recorded in the config\n"
" file's volumes section\n"
" --list-volumes list all named volumes (see -v/--volume) with\n"
" their host directory\n"
" -t, --test run the test suite\n"
" --log-level <level> set log verbosity (trace, debug, info, warn,\n"
" error, critical, off)\n"
@@ -300,6 +306,25 @@ int create_volume_command(const std::string& name, const std::string& directory,
return 0;
}
int list_volumes_command(const AppConfig& config) {
size_t max_len = 0;
for (const auto& volume : config.volumes) {
max_len = std::max(max_len, volume.name.size());
}
// Same tab-alignment scheme as list_images_command(): pad each name to one
// 8-column tab stop past the longest one, however long that is.
constexpr size_t kTabWidth = 8;
size_t target_tabs = max_len / kTabWidth + 1;
for (const auto& volume : config.volumes) {
size_t tabs_used = volume.name.size() / kTabWidth;
size_t tabs_needed = target_tabs > tabs_used ? target_tabs - tabs_used : 1;
fmt::print("{}{}{}\n", volume.name, std::string(tabs_needed, '\t'), volume.directory);
}
return 0;
}
int run_container(const std::filesystem::path& image_tar,
const std::vector<std::string>& requested_command, bool use_nsenter,
const std::optional<std::string>& user, const std::optional<std::string>& group) {
@@ -387,7 +412,8 @@ int main(int argc, char* argv[]) {
case 'r':
case 'c':
case 'l':
case 'v': {
case 'v':
case kListVolumesOpt: {
Mode requested;
switch (opt) {
case 't':
@@ -408,9 +434,12 @@ int main(int argc, char* argv[]) {
case 'l':
requested = Mode::kListImages;
break;
default:
case 'v':
requested = Mode::kVolume;
break;
default:
requested = Mode::kListVolumes;
break;
}
if (mode != Mode::kNone && mode != requested) {
spdlog::error("multiple actions specified");
@@ -484,6 +513,9 @@ int main(int argc, char* argv[]) {
if (mode == Mode::kVolume) {
return create_volume_command(mode_arg, argv[optind], config_path, *config);
}
if (mode == Mode::kListVolumes) {
return list_volumes_command(*config);
}
if (mode == Mode::kRun) {
std::vector<std::string> command(argv + optind, argv + argc);
// As root, containers-storage mount doesn't need to reexec into a private