13#include <unordered_set>
27namespace fs = std::filesystem;
38 fs::path
const& path_dir_download
39 , ns_config::Distribution
const& distribution
40 , std::string
const& recipe
43 return path_dir_download /
"recipes" / distribution.lower() /
"latest" / std::format(
"{}.json", recipe);
69 ns_config::Distribution
const& distribution
70 , fs::path
const& path_dir_download
71 , std::string
const& recipe
75 fs::path recipe_file = get_path_recipe(path_dir_download, distribution, recipe);
77 return_if(not fs::exists(recipe_file),
78 Error(
"E::Recipe '{}' not found locally. Use 'fim-recipe fetch {}' first.", recipe, recipe));
80 std::ifstream file(recipe_file);
81 return_if(!file.is_open(),
82 Error(
"E::Could not open recipe file '{}'", recipe_file.string()));
84 std::string json_contents((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>());
86 return_if(json_contents.empty(), Error(
"E::Empty json file"));
104 ns_config::Distribution
const& distribution
105 , std::string url_remote
106 , fs::path
const& path_file_downloader
107 , fs::path
const& path_dir_download
108 , std::string
const& recipe
110 , std::unordered_set<std::string>& dependencies
115 auto const& deps = recipe_obj.get_dependencies();
118 for (
auto const& sub_recipe : deps)
120 Pop(
fetch_impl(distribution, url_remote, path_file_downloader, path_dir_download, sub_recipe, use_existing, dependencies));
126 if(dependencies.contains(recipe))
128 return Error(
"E::Cyclic dependency for recipe '{}'", recipe);
132 dependencies.insert(recipe);
135 fs::path path_file_output = get_path_recipe(path_dir_download, distribution, recipe);
136 fs::path path_dir_output = path_file_output.parent_path();
138 if (use_existing && Try(fs::exists(path_file_output)))
140 logger(
"I::Using existing recipe from '{}'", path_file_output.string());
142 std::ifstream file(path_file_output);
145 return Error(
"E::Could not open existing recipe file '{}'", path_file_output.string());
148 std::string json_contents((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>());
153 Pop(f_fetch_dependencies(recipe_obj));
158 if (url_remote.ends_with(
'/'))
160 url_remote.pop_back();
163 std::string recipe_url = std::format(
"{}/{}/latest/{}.json", url_remote, distribution.lower(), recipe);
167 logger(
"I::Downloading recipe from '{}'", recipe_url);
168 logger(
"I::Saving to '{}'", path_file_output.string());
171 .with_args(
"-O", path_file_output.string(), recipe_url)
173 logger(
"I::Successfully downloaded recipe '{}' to '{}'", recipe, path_file_output.string());
175 std::ifstream file(path_file_output);
178 return Error(
"E::Could not open downloaded recipe file '{}'", path_file_output.string());
181 std::string json_contents((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>());
186 Pop(f_fetch_dependencies(recipe_obj));
202 ns_config::Distribution
const& distribution
203 , std::string url_remote
204 , fs::path
const& path_file_downloder
205 , fs::path
const& path_dir_download
206 , std::string
const& recipe
207 ,
bool use_existing =
false
210 std::unordered_set<std::string> dependencies;
211 Pop(
fetch_impl(distribution, url_remote, path_file_downloder, path_dir_download, recipe, use_existing, dependencies));
212 return std::vector(dependencies.begin(), dependencies.end());
224 ns_config::Distribution
const& distribution
225 , fs::path
const& path_dir_download
226 , std::string
const& recipe
232 fs::path recipe_file = get_path_recipe(path_dir_download, distribution, recipe);
233 std::println(
"Recipe: {}", recipe);
234 std::println(
"Location: {}", recipe_file.string());
236 std::println(
"Description: {}", recipe_obj.get_description());
238 auto const& packages = recipe_obj.get_packages();
239 std::println(
"Package count: {}", packages.size());
240 std::println(
"Packages:");
241 for (
auto const& pkg : packages)
243 std::println(
" - {}", pkg);
246 auto const& dependencies = recipe_obj.get_dependencies();
247 if (!dependencies.empty())
249 std::println(
"Dependencies: {}", dependencies.size());
250 for (
auto const& dep : dependencies)
252 std::println(
" - {}", dep);
257 std::println(
"Dependencies: 0");
274requires std::invocable<F,std::string,std::vector<std::string>&>
276 , ns_config::Distribution
const& distribution
277 , fs::path
const& path_dir_download
278 , std::vector<std::string>
const& recipes
283 std::vector<std::string> packages;
285 for(
auto&& recipe : recipes)
290 auto const& recipe_packages = recipe_obj.get_packages();
291 std::ranges::copy(recipe_packages, std::back_inserter(packages));
293 if(recipe_obj.get_desktop())
295 desktop = recipe_obj.get_desktop();
296 logger(
"I::Found desktop integration in recipe '{}'", recipe);
301 std::vector<std::string> args;
304 case ns_config::Distribution::ALPINE:
307 args = {
"add",
"--no-cache",
"--update-cache",
"--no-progress"};
310 case ns_config::Distribution::ARCH:
313 args = {
"-Syu",
"--noconfirm",
"--needed"};
316 case ns_config::Distribution::BLUEPRINT:
318 return Error(
"E::Blueprint does not support recipes");
321 case ns_config::Distribution::NONE:
323 return Error(
"E::Unsupported distribution '{}' for recipe installation", distribution);
327 std::ranges::copy(packages, std::back_inserter(args));
329 int exit_code = Pop(callback(program, args));
333 logger(
"I::Setting up desktop integration from recipe");
336 fs::path path_file_desktop_json = Try(fs::temp_directory_path()) /
"recipe_desktop.json";
337 std::ofstream file_desktop(path_file_desktop_json, std::ios::out | std::ios::trunc);
338 return_if(not file_desktop.is_open(), Error(
"E::Could not create temporary desktop JSON file"));
339 file_desktop << desktop_json;
340 file_desktop.close();
344 logger(
"W::Failed to setup desktop integration: {}", ret.error());
348 logger(
"I::Desktop integration setup successful");
351 Try(fs::remove(path_file_desktop_json));
std::unique_ptr< Child > spawn()
Spawns (forks) the child process and begins execution.
FlatImage configuration object.
Defines a class that manages FlatImage's recipe configuration.
Enhanced error handling framework built on std::expected.
A library for file logging.
#define logger(fmt,...)
Compile-time log level dispatch macro with automatic location capture.
fs::path get_path_recipe(fs::path const &path_dir_download, ns_config::Distribution const &distribution, std::string const &recipe)
Constructs the path to a recipe file in the local cache.
Value< std::string > serialize(Desktop const &desktop) noexcept
Serializes a Desktop class into a json string.
Value< Recipe > deserialize(std::string_view str_raw_json) noexcept
Deserializes a string into a Recipe class.
Value< void > setup(ns_config::FlatImage const &fim, fs::path const &path_file_json_src)
Setup desktop integration in FlatImage.
Value< fs::path > create_directories(fs::path const &p)
Creates directories recursively.
Package recipe command implementation.
Value< void > info(ns_config::Distribution const &distribution, fs::path const &path_dir_download, std::string const &recipe)
Displays information about a locally cached recipe.
Value< ns_db::ns_recipe::Recipe > load_recipe(ns_config::Distribution const &distribution, fs::path const &path_dir_download, std::string const &recipe)
Loads a recipe from local cache.
Value< int > install(ns_config::FlatImage const &fim, ns_config::Distribution const &distribution, fs::path const &path_dir_download, std::vector< std::string > const &recipes, F &&callback)
Installs packages from recipes using the appropriate package manager.
Value< std::vector< std::string > > fetch(ns_config::Distribution const &distribution, std::string url_remote, fs::path const &path_file_downloder, fs::path const &path_dir_download, std::string const &recipe, bool use_existing=false)
Fetches a recipe from the remote repository along with all its dependencies recursively.
Value< void > fetch_impl(ns_config::Distribution const &distribution, std::string url_remote, fs::path const &path_file_downloader, fs::path const &path_dir_download, std::string const &recipe, bool use_existing, std::unordered_set< std::string > &dependencies)
Internal implementation that fetches a recipe and its dependencies recursively with cycle detection.
Manages the desktop integration.
Enhanced expected type with integrated logging capabilities.
Main FlatImage configuration object.
A library to spawn sub-processes in linux.