30 namespace stdfs = std::filesystem;
39 inline std::optional<std::string> read_file(
const std::string &path)
41 std::ifstream file(path);
54 inline bool write_file(
const std::string &path,
const std::string &content)
56 std::ofstream file(path);
68 inline bool exists(
const std::string &path)
70 return stdfs::exists(path);
76 inline bool is_file(
const std::string &path)
78 return stdfs::is_regular_file(path);
84 inline bool is_directory(
const std::string &path)
86 return stdfs::is_directory(path);
92 inline bool is_symlink(
const std::string &path)
94 return stdfs::is_symlink(path);
100 inline std::optional<std::uintmax_t> file_size(
const std::string &path)
103 auto size = stdfs::file_size(path, ec);
114 inline std::string parent_path(
const std::string &path)
116 return core::normalize_separators(stdfs::path(path).parent_path().
string());
122 inline std::string filename(
const std::string &path)
124 return stdfs::path(path).filename().string();
134 template <
typename... Args>
135 inline std::string join_paths(
const std::string &first, Args &&...args)
137 stdfs::path result(first);
138 (result /= ... /= stdfs::path(args));
139 return core::normalize_separators(result.string());
145 inline bool create_directories(
const std::string &path)
148 stdfs::create_directories(path, ec);
155 inline bool remove_file(
const std::string &path)
158 stdfs::remove(path, ec);
165 inline bool remove_directory(
const std::string &path)
168 stdfs::remove_all(path, ec);
175 inline bool copy_file(
const std::string &src,
const std::string &dst)
178 stdfs::copy_file(src, dst, stdfs::copy_options::overwrite_existing, ec);
185 inline std::vector<std::string> list_directory(
const std::string &path)
187 std::vector<std::string> entries;
189 for (
const auto &entry : stdfs::directory_iterator(path, ec))
191 entries.push_back(core::normalize_separators(entry.path().string()));
199 inline std::string current_path()
201 return core::normalize_separators(stdfs::current_path().
string());
207 inline bool set_current_path(
const std::string &path)
210 stdfs::current_path(path, ec);
217 inline bool is_absolute_path(
const std::string &path)
223 if (path.size() >= 3 && std::isalpha(
static_cast<unsigned char>(path[0])) && path[1] ==
':' && (path[2] ==
'\\' || path[2] ==
'/'))
227 if (path.size() >= 2 && path[0] ==
'\\' && path[1] ==
'\\')
233 return path[0] ==
'/';
240 inline std::string absolute_path(
const std::string &path)
242 return core::normalize_separators(stdfs::absolute(path).
string());
248 inline std::optional<std::string> canonical_path(
const std::string &path)
251 auto result = stdfs::canonical(path, ec);
256 return core::normalize_separators(result.string());
272 inline core::RuntimeInventory load_inventory_from_directory(
273 const std::string &nak_records_dir,
274 std::vector<std::string> *errors =
nullptr)
276 core::RuntimeInventory inventory;
278 if (!is_directory(nak_records_dir))
282 errors->push_back(
"NAK records directory does not exist: " + nak_records_dir);
287 for (
const auto &entry : list_directory(nak_records_dir))
290 if (entry.size() < 5 || entry.substr(entry.size() - 5) !=
".json")
295 auto content = read_file(entry);
300 errors->push_back(
"Failed to read: " + entry);
306 std::string record_ref = filename(entry);
309 auto result = json::parse_runtime_descriptor(*content, entry);
312 result.value.source_path = entry;
313 inventory.runtimes[record_ref] = result.value;
317 errors->push_back(
"Failed to parse " + entry +
": " + result.error);