diff --git a/activate.sh b/activate.sh new file mode 100644 index 00000000..89b2af48 --- /dev/null +++ b/activate.sh @@ -0,0 +1,3 @@ +#!/bin/bash + +export UENV_CONFIGURATION_PATH=$(realpath .)/configuration.toml \ No newline at end of file diff --git a/configuration.toml b/configuration.toml new file mode 100644 index 00000000..78e2d2ad --- /dev/null +++ b/configuration.toml @@ -0,0 +1,2 @@ +use_squashfuse = false #change to 'true' if you want to mount uenv rootless, without needing a setuid binary +uenv_local_repos = [""] #add a list of local uenv repos to search through for `uenv image ls`, `uenv start`, and `uenv run` in addition to the user repo. \ No newline at end of file diff --git a/meson.build b/meson.build index 4f4cd65d..ca54e673 100644 --- a/meson.build +++ b/meson.build @@ -28,6 +28,7 @@ fmt_dep = subproject('fmt', default_options: ['werror=false', 'warning_level=0 json_dep = subproject('nlohmann_json', default_options: ['werror=false', 'warning_level=0']).get_variable('nlohmann_json_dep') spdlog_dep = subproject('spdlog', default_options: ['werror=false', 'warning_level=0','std_format=disabled','external_fmt=enabled']).get_variable('spdlog_dep') sqlite3_dep = subproject('sqlite3', default_options: ['werror=false', 'warning_level=0']).get_variable('sqlite3_dep') +tomlplusplus_dep = subproject('tomlplusplus', default_options: ['werror=false', 'warning_level=0']).get_variable('tomlplusplus_dep') subproject('curl', default_options: ['werror=false', 'warning_level=0', 'tests=disabled', 'unittests=disabled', 'tool=disabled']) curl_dep = dependency('libcurl', required: true) @@ -65,12 +66,12 @@ lib_uenv = static_library( 'libuenv', lib_src, include_directories: lib_inc, - dependencies: [curl_dep, sqlite3_dep, fmt_dep, spdlog_dep, json_dep, barkeep_dep], + dependencies: [curl_dep, sqlite3_dep, fmt_dep, spdlog_dep, json_dep, barkeep_dep, tomlplusplus_dep], ) uenv_dep = declare_dependency( link_with: lib_uenv, - dependencies: [curl_dep, sqlite3_dep, fmt_dep, spdlog_dep, json_dep, barkeep_dep], + dependencies: [curl_dep, sqlite3_dep, fmt_dep, spdlog_dep, json_dep, barkeep_dep, tomlplusplus_dep], include_directories: lib_inc ) @@ -101,7 +102,7 @@ if uenv_cli cli = executable('uenv', sources: cli_src, - dependencies: [uenv_dep, sqlite3_dep, fmt_dep, spdlog_dep, cli11_dep, barkeep_dep], + dependencies: [uenv_dep, sqlite3_dep, fmt_dep, spdlog_dep, cli11_dep, barkeep_dep, tomlplusplus_dep], c_args: [ '-DVERSION="@0@"'.format(version), ], diff --git a/src/cli/ls.cpp b/src/cli/ls.cpp index b899ed3c..cf55e6c4 100644 --- a/src/cli/ls.cpp +++ b/src/cli/ls.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include #include @@ -43,6 +44,18 @@ int image_ls(const image_ls_args& args, const global_settings& settings) { return 1; } + //parse configuration.toml + toml::table config; + char *config_location = getenv("UENV_CONFIGURATION_PATH"); //gets config file from UENV_CONFIGURATION_PATH env variable + std::string_view config_sv{config_location}; + try{ + config = toml::parse_file(config_sv); + } catch(const toml::parse_error& err){ + term::error("{}", fmt::format("Error parsing configuration.toml:\n{}",err)); + } + + toml::array& config_repo = *config["uenv_local_repos"].as_array(); + // open the repo auto store = uenv::open_repository(settings.config.repo.value()); if (!store) { @@ -72,9 +85,40 @@ int image_ls(const image_ls_args& args, const global_settings& settings) { term::error("invalid search term: {}", store.error()); return 1; } - + printf("User Repository: %s\n", settings.config.repo.value().c_str()); print_record_set(*result, args.no_header, args.json); + // query the local repos + for (auto& repo : config_repo){ + if (repo.is_string()){//if repo is string, query + std::string repo_path_string = repo.value_or(""); + + //validate local repo and skip if validation fails + if (auto rpath = uenv::validate_repo_path(repo_path_string, false, false)) { + //open local repo if valid + std::filesystem::path repo_path = repo_path_string; + auto local_store = uenv::open_repository(repo_path); + + if (!local_store) { + term::error("unable to open local repo: {}", local_store.error()); + return 1; + } + + const auto local_result = local_store->query(label); + if (!local_result) { + term::error("invalid search term: {}", local_store.error()); + return 1; + } + printf("\nLocal Repository: %s\n", repo.value_or("")); + print_record_set(*local_result, args.no_header, args.json); //print local repo listing + + } else { + spdlog::warn("invalid repo path {}", rpath.error()); + continue; + } + } + } + return 0; } diff --git a/src/cli/run.cpp b/src/cli/run.cpp index 48fb8090..a5ac8f61 100644 --- a/src/cli/run.cpp +++ b/src/cli/run.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include #include @@ -59,11 +60,27 @@ You need to finish the current session by typing 'exit' or hitting ''.)" return 1; } + //parse configuration.toml + toml::table config; + char *config_location = getenv("UENV_CONFIGURATION_PATH"); //gets config file from UENV_CONFIGURATION_PATH env variable + std::string_view config_sv{config_location}; + try{ + config = toml::parse_file(config_sv); + } catch(const toml::parse_error& err){ + term::error("{}", fmt::format("Error parsing configuration.toml:\n{}",err)); + } + bool use_squashfuse = config["use_squashfuse"].value_or(false); //parse use_squashfuse key from configuration.toml + auto runtime_environment = generate_environment(*env, globals.calling_environment, "SQFSMNT_FWD_"); // generate the mount list std::vector commands = {"squashfs-mount"}; + + if (use_squashfuse){ + commands.push_back("--squashfuse"); + } + for (auto e : env->uenvs) { commands.push_back(fmt::format("{}:{}", e.second.sqfs_path.string(), e.second.mount_path)); diff --git a/src/cli/start.cpp b/src/cli/start.cpp index 73787b9a..0f8564be 100644 --- a/src/cli/start.cpp +++ b/src/cli/start.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include #include @@ -102,11 +103,27 @@ will not work, because it starts a new interactive shell.)", return 1; } + //parse configuration.toml + toml::table config; + char *config_location = getenv("UENV_CONFIGURATION_PATH"); //gets config file from UENV_CONFIGURATION_PATH env variable + std::string_view config_sv{config_location}; + try{ + config = toml::parse_file(config_sv); + } catch(const toml::parse_error& err){ + term::error("{}", fmt::format("Error parsing configuration.toml:\n{}",err)); + } + bool use_squashfuse = config["use_squashfuse"].value_or(false); //parse use_squashfuse key from configuration.toml + auto runtime_environment = generate_environment(*env, globals.calling_environment, "SQFSMNT_FWD_"); // generate the mount list std::vector commands = {"squashfs-mount"}; + + if (use_squashfuse){ + commands.push_back("--squashfuse"); + } + for (auto e : env->uenvs) { commands.push_back(fmt::format("{}:{}", e.second.sqfs_path.string(), e.second.mount_path)); diff --git a/src/uenv/env.cpp b/src/uenv/env.cpp index 3c5602a7..0ae1b158 100644 --- a/src/uenv/env.cpp +++ b/src/uenv/env.cpp @@ -12,6 +12,7 @@ #include #include #include +#include #include #include @@ -159,22 +160,77 @@ concretise_env(const std::string& uenv_args, const auto results = *result; if (results.empty()) { - return unexpected(fmt::format("no uenv matches '{}'", *label)); - } + //parse configuration.toml + toml::table config; + char *config_location = getenv("UENV_CONFIGURATION_PATH"); //gets config file from UENV_CONFIGURATION_PATH env variable + std::string_view config_sv{config_location}; + try{ + config = toml::parse_file(config_sv); + } catch(const toml::parse_error& err){ + return unexpected( + fmt::format("Error parsing configuration.toml:\n{}",err)); + } - // ensure that all results share a unique sha - if (!results.unique_sha()) { + toml::array& config_repo = *config["uenv_local_repos"].as_array(); //parses toml key as an array of repos + + auto local_results = results; + //recuse through uenv_local_repo array + for (auto& repo : config_repo){ + if (repo.is_string()){ //if repo is a string, then query + std::string repo_path_string = repo.value_or(""); + + //validate local repo and skip if validation fails + if (auto rpath = uenv::validate_repo_path(repo_path_string, false, false)) { + + //open local repo if valid + std::filesystem::path repo_path = repo_path_string; + auto local_store = uenv::open_repository(repo_path); + + const auto local_result = local_store->query(*label); + local_results = *local_result; + if (!local_results.empty()){ //if repo finds uenv, then set sqfs_path and break + const auto& r = *local_results.begin(); + sqfs_path = local_store->uenv_paths(r.sha).squashfs; + //printf("Uenv found in local repository: %s\n", repo.value_or("")); + break; + } + } else { + spdlog::warn("invalid repo path {}", rpath.error()); + break; + } + } + else{ + return unexpected( + fmt::format("Error: uenv local config isn't a string")); + } + } + if (local_results.empty()){ //if uenv couldn't be found in local or local repo + return unexpected(fmt::format("no uenv matches '{}'", *label)); + } + // ensure that all results share a unique sha + if (!local_results.unique_sha()) { auto errmsg = fmt::format( "more than one uenv matches the uenv description " "'{}':\n", desc.label().value()); - errmsg += format_record_set(results); + errmsg += format_record_set(local_results); return unexpected(errmsg); - } + } + } else { + // ensure that all results share a unique sha + if (!results.unique_sha()) { + auto errmsg = fmt::format( + "more than one uenv matches the uenv description " + "'{}':\n", + desc.label().value()); + errmsg += format_record_set(results); + return unexpected(errmsg); + } - // set sqfs_path - const auto& r = *results.begin(); - sqfs_path = store->uenv_paths(r.sha).squashfs; + // set sqfs_path + const auto& r = *results.begin(); + sqfs_path = store->uenv_paths(r.sha).squashfs; + } } // otherwise an explicit filename was provided, e.g. // "/scratch/myimages/develp/store.squashfs" diff --git a/subprojects/tomlplusplus.wrap b/subprojects/tomlplusplus.wrap new file mode 100644 index 00000000..8807085e --- /dev/null +++ b/subprojects/tomlplusplus.wrap @@ -0,0 +1,8 @@ +[wrap-file] +directory = tomlplusplus-3.4.0 +source_url = https://github.com/marzer/tomlplusplus/archive/refs/tags/v3.4.0.tar.gz +source_filename = tomlplusplus-3.4.0.tar.gz +source_hash = 8517f65938a4faae9ccf8ebb36631a38c1cadfb5efa85d9a72e15b9e97d25155 + +[provide] +tomlplusplus = tomlplusplus_dep \ No newline at end of file