diff --git a/src/UserIntent.cpp b/src/UserIntent.cpp index f49ba2e..0316ff6 100644 --- a/src/UserIntent.cpp +++ b/src/UserIntent.cpp @@ -1,206 +1,208 @@ #include "UserIntent.hpp" +#include + #include #include -#include #include "Archiver.hpp" namespace xwim { - unique_ptr make_compress_intent(const UserOpt &userOpt) { - if (userOpt.paths.size() == 1) { - return make_unique( - CompressSingleIntent{ - *userOpt.paths.begin(), - userOpt.out - }); - } +unique_ptr make_compress_intent(const UserOpt &userOpt) { + if (userOpt.paths.size() == 1) { + return make_unique( + CompressSingleIntent{*userOpt.paths.begin(), userOpt.out}); + } - if (!userOpt.out.has_value()) { - throw XwimError("Cannot guess output for multiple targets"); - } + if (!userOpt.out.has_value()) { + throw XwimError("Cannot guess output for multiple targets"); + } - return make_unique( - CompressManyIntent{ - userOpt.paths, - userOpt.out.value() - }); + return make_unique( + CompressManyIntent{userOpt.paths, userOpt.out.value()}); +} + +unique_ptr make_extract_intent(const UserOpt &userOpt) { + for (const path &p : userOpt.paths) { + if (!can_handle_archive(p)) { + throw XwimError("Cannot extract path {}", p); } + } - unique_ptr make_extract_intent(const UserOpt &userOpt) { - for (const path& p: userOpt.paths) { - if (!can_handle_archive(p)) { - throw XwimError("Cannot extract path {}", p); - } - } + return make_unique(ExtractIntent{userOpt.paths, userOpt.out}); +} - return make_unique( - ExtractIntent{ - userOpt.paths, - userOpt.out - }); - } - - unique_ptr try_infer_compress_intent(const UserOpt &userOpt) { - if(!userOpt.out.has_value()) { - spdlog::debug("No provided"); - if(userOpt.paths.size() != 1) { - spdlog::debug("Not a single-path compression. Cannot guess for many-path compression"); - return nullptr; - } - - spdlog::debug("Only one provided. Assume single-path compression."); - return make_unique(CompressSingleIntent{*userOpt.paths.begin(), userOpt.out}); - } - - spdlog::debug(" provided: {}", userOpt.out.value()); - if(can_handle_archive(userOpt.out.value())) { - spdlog::debug("{} given and a known archive format, assume compression", userOpt.out.value()); - return make_compress_intent(userOpt); - } - - spdlog::debug("Cannot compress multiple paths without a user-provided output archive"); +unique_ptr try_infer_compress_intent(const UserOpt &userOpt) { + if (!userOpt.out.has_value()) { + spdlog::debug("No provided"); + if (userOpt.paths.size() != 1) { + spdlog::debug( + "Not a single-path compression. Cannot guess for many-path " + "compression"); return nullptr; } - unique_ptr try_infer_extract_intent(const UserOpt &userOpt) { - bool can_extract_all = std::all_of( - userOpt.paths.begin(), userOpt.paths.end(), - [](const path &path) { return can_handle_archive(path); }); + spdlog::debug("Only one provided. Assume single-path compression."); + return make_unique( + CompressSingleIntent{*userOpt.paths.begin(), userOpt.out}); + } - if(!can_extract_all) { - spdlog::debug("Cannot extract all provided . Assume this is not an extraction."); - for(const path& p: userOpt.paths) { - if(!can_handle_archive(p)) { - spdlog::debug("Cannot handle {}", p); - } - } + spdlog::debug(" provided: {}", userOpt.out.value()); + if (can_handle_archive(userOpt.out.value())) { + spdlog::debug("{} given and a known archive format, assume compression", + userOpt.out.value()); + return make_compress_intent(userOpt); + } - return nullptr; + spdlog::debug( + "Cannot compress multiple paths without a user-provided output archive"); + return nullptr; +} + +unique_ptr try_infer_extract_intent(const UserOpt &userOpt) { + bool can_extract_all = + std::all_of(userOpt.paths.begin(), userOpt.paths.end(), + [](const path &path) { return can_handle_archive(path); }); + + if (!can_extract_all) { + spdlog::debug( + "Cannot extract all provided . Assume this is not an " + "extraction."); + for (const path &p : userOpt.paths) { + if (!can_handle_archive(p)) { + spdlog::debug("Cannot handle {}", p); } - - if(userOpt.out.has_value() && can_handle_archive(userOpt.out.value())) { - spdlog::debug("Could extract all provided . But also {} looks like an archive. Ambiguous intent. Assume this is not an extraction.", userOpt.out.value()); - return nullptr; - } - - spdlog::debug("Could extract all provided . But also looks like an archive. Ambiguous intent. Assume this is not an extraction."); - return make_extract_intent(userOpt); } - unique_ptr make_intent(const UserOpt &userOpt) { - if (userOpt.wants_compress() && userOpt.wants_extract()) { - throw XwimError("Cannot compress and extract simultaneously"); - } - if(userOpt.paths.empty()) { - throw XwimError("No input given..."); - } + return nullptr; + } - // explicitly specified intent - if (userOpt.wants_compress()) return make_compress_intent(userOpt); - if (userOpt.wants_extract()) return make_extract_intent(userOpt); + if (userOpt.out.has_value() && can_handle_archive(userOpt.out.value())) { + spdlog::debug( + "Could extract all provided . But also {} looks like an " + "archive. Ambiguous intent. Assume this is not an extraction.", + userOpt.out.value()); + return nullptr; + } - spdlog::info("Intent not explicitly provided, trying to infer intent"); + spdlog::debug( + "Could extract all provided . But also looks like an " + "archive. Ambiguous intent. Assume this is not an extraction."); + return make_extract_intent(userOpt); +} - if(auto intent = try_infer_extract_intent(userOpt)) { - spdlog::info("Extraction intent inferred"); - return intent; - } - spdlog::info("Cannot infer extraction intent"); +unique_ptr make_intent(const UserOpt &userOpt) { + if (userOpt.wants_compress() && userOpt.wants_extract()) { + throw XwimError("Cannot compress and extract simultaneously"); + } + if (userOpt.paths.empty()) { + throw XwimError("No input given..."); + } - if(auto intent = try_infer_compress_intent(userOpt)) { - spdlog::info("Compression intent inferred"); - return intent; - } - spdlog::info("Cannot infer compression intent"); + // explicitly specified intent + if (userOpt.wants_compress()) return make_compress_intent(userOpt); + if (userOpt.wants_extract()) return make_extract_intent(userOpt); + spdlog::info("Intent not explicitly provided, trying to infer intent"); - throw XwimError("Cannot guess intent"); + if (auto intent = try_infer_extract_intent(userOpt)) { + spdlog::info("Extraction intent inferred"); + return intent; + } + spdlog::info("Cannot infer extraction intent"); + + if (auto intent = try_infer_compress_intent(userOpt)) { + spdlog::info("Compression intent inferred"); + return intent; + } + spdlog::info("Cannot infer compression intent"); + + throw XwimError("Cannot guess intent"); +} + +void ExtractIntent::execute() { + bool has_out = this->out.has_value(); + bool is_single = this->archives.size() == 1; + + for (const path &p : this->archives) { + unique_ptr archiver = make_archiver(p); + path out; + + if (has_out) { + if (is_single) { // just dump content of archive into `out` + std::filesystem::create_directories(this->out.value()); + out = this->out.value(); + } else { // create an `out` folder and extract inside there + std::filesystem::create_directories(this->out.value()); + out = this->out.value() / strip_archive_extension(p); + } + } else { + out = std::filesystem::current_path() / strip_archive_extension(p); + std::filesystem::create_directories(out); } + archiver->extract(p, out); - void ExtractIntent::execute() { - bool has_out = this->out.has_value(); - bool is_single = this->archives.size() == 1; + // move folder if only one entry and that entries name is already + // the stripped archive name + auto dit = std::filesystem::directory_iterator(out); - for (path p: this->archives) { - unique_ptr archiver = make_archiver(p); - path out; + if (dit == std::filesystem::directory_iterator()) { + spdlog::debug("Archive is empty"); + } else if (is_directory(dit->path())) { + auto first_path = dit->path(); + auto next_entry = next(dit); - if(has_out) { - if(is_single) { // just dump content of archive into `out` - std::filesystem::create_directories(this->out.value()); - out = this->out.value(); - } else { // create an `out` folder and extract inside there - std::filesystem::create_directories(this->out.value()); - out = this->out.value() / strip_archive_extension(p); - } - } else { - out = std::filesystem::current_path() / strip_archive_extension(p); - std::filesystem::create_directories(out); - } + if (next_entry == std::filesystem::directory_iterator()) { + spdlog::debug("Archive has single entry which is a directory"); + if (std::filesystem::equivalent(first_path.filename(), + out.filename())) { + spdlog::debug("Archive entry named like archive"); + int i = rand_int(0, 100000); - archiver->extract(p, out); + path tmp_out = path{out}; + tmp_out.concat(fmt::format(".xwim{}", i)); - // move folder if only one entry and that entries name is already - // the stripped archive name - auto dit = std::filesystem::directory_iterator(out); + spdlog::debug("Moving {} to {}", first_path, tmp_out); + std::filesystem::rename(first_path, tmp_out); + spdlog::debug("Removing parent {}", out); + std::filesystem::remove(out); + spdlog::debug("Moving {} to {}", tmp_out, out); + std::filesystem::rename(tmp_out, out); - if(dit == std::filesystem::directory_iterator()) { - spdlog::debug("Archive is empty"); - } else if(is_directory(dit->path())){ - auto first_path = dit->path(); - auto next_entry = next(dit); - - if(next_entry == std::filesystem::directory_iterator()) { - spdlog::debug("Archive has single entry which is a directory"); - if(std::filesystem::equivalent(first_path.filename(), out.filename())) { - spdlog::debug("Archive entry named like archive"); - int i = rand_int(0, 100000); - - path tmp_out = path{out}; - tmp_out.concat(fmt::format(".xwim{}", i)); - - spdlog::debug("Moving {} to {}", first_path, tmp_out); - std::filesystem::rename(first_path, tmp_out); - spdlog::debug("Removing parent {}", out); - std::filesystem::remove(out); - spdlog::debug("Moving {} to {}", tmp_out, out); - std::filesystem::rename(tmp_out, out); - - } else { - spdlog::debug("Archive entry differs from archive name"); - } - } else { - spdlog::debug("Archive has multiple entries"); - } - } - } - }; - - void CompressSingleIntent::execute() { - if(this->out.has_value()) { - if(!can_handle_archive(this->out.value())) { - throw XwimError("Unknown archive format {}", this->out.value()); - } - - unique_ptr archiver = make_archiver(this->out.value()); - set ins{this->in}; - archiver->compress(ins, this->out.value()); } else { - path out = default_archive(strip_archive_extension(this->in).stem()); - unique_ptr archiver = make_archiver(out); - set ins{this->in}; - archiver->compress(ins, out); + spdlog::debug("Archive entry differs from archive name"); } - }; + } else { + spdlog::debug("Archive has multiple entries"); + } + } + } +}; - void CompressManyIntent::execute() { - if(!can_handle_archive(this->out)) { - throw XwimError("Unknown archive format {}", this->out); - } +void CompressSingleIntent::execute() { + if (this->out.has_value()) { + if (!can_handle_archive(this->out.value())) { + throw XwimError("Unknown archive format {}", this->out.value()); + } - unique_ptr archiver = make_archiver(this->out); - archiver->compress(this->in_paths, this->out); - }; + unique_ptr archiver = make_archiver(this->out.value()); + set ins{this->in}; + archiver->compress(ins, this->out.value()); + } else { + path out = default_archive(strip_archive_extension(this->in).stem()); + unique_ptr archiver = make_archiver(out); + set ins{this->in}; + archiver->compress(ins, out); + } +}; + +void CompressManyIntent::execute() { + if (!can_handle_archive(this->out)) { + throw XwimError("Unknown archive format {}", this->out); + } + + unique_ptr archiver = make_archiver(this->out); + archiver->compress(this->in_paths, this->out); +}; } // namespace xwim