From c6e0e92db2abfcc574d9ecc0fb89a8c108a563b7 Mon Sep 17 00:00:00 2001 From: Armin Friedl Date: Sat, 25 Jun 2022 21:36:08 +0200 Subject: [PATCH] Add more formats, delete leftovers --- src/Archiver.cpp | 24 ++++--- src/Archiver.hpp | 9 +-- src/Formats.hpp | 49 ++++++++++++++ src/Xwim.cpp | 165 --------------------------------------------- src/Xwim.hpp | 106 ----------------------------- src/XwimConfig.hpp | 15 ----- 6 files changed, 64 insertions(+), 304 deletions(-) create mode 100644 src/Formats.hpp delete mode 100644 src/Xwim.cpp delete mode 100644 src/Xwim.hpp delete mode 100644 src/XwimConfig.hpp diff --git a/src/Archiver.cpp b/src/Archiver.cpp index 7f2214e..384274f 100644 --- a/src/Archiver.cpp +++ b/src/Archiver.cpp @@ -1,4 +1,5 @@ #include "Archiver.hpp" +#include "Formats.hpp" #include @@ -37,9 +38,9 @@ fs::path archive_extension(const fs::path& path) { while (tmp_path.has_extension()) { tmp_ext = tmp_path.extension() += tmp_ext; - auto search = extensions_format.find(tmp_ext); + Format format = find_extension_format(tmp_ext); - if (search != extensions_format.end()) { + if (format != Format::UNKNOWN) { // (Combined) extension known. Remember as `ext` and keep // looking for even longer extensions. ext = tmp_ext; @@ -76,9 +77,9 @@ fs::path strip_archive_extension(const fs::path& path) { tmp_ext = tmp_path.extension() += tmp_ext; spdlog::debug("Looking for {} in known extensions", tmp_ext); - auto search = extensions_format.find(tmp_ext); + Format format = find_extension_format(tmp_ext); tmp_longest_ext++; - if (search != extensions_format.end()) { + if (format != Format::UNKNOWN) { // (Combined) extension known. Remember as `longest_ext` and keep // looking for even longer extensions. longest_ext = tmp_longest_ext; @@ -119,19 +120,22 @@ Format parse_format(const fs::path& path) { spdlog::debug("Looking for path {}", path); fs::path ext = archive_extension(path); spdlog::debug("Looking for ext {}", ext); - auto search = extensions_format.find(ext); - if (search == extensions_format.end()) { + Format format = find_extension_format(ext); + + if (format == Format::UNKNOWN) { throw XwimError{"No known archiver for {}", path}; } - return search->second; + return format; } unique_ptr make_archiver(const string& archive_name) { switch (parse_format(archive_name)) { - case Format::TAR_GZ: - case Format::ZIP: - return make_unique(); + case Format::TAR_GZIP: case Format::TAR_BZIP2: + case Format::TAR_COMPRESS: case Format::TAR_LZIP: + case Format::TAR_XZ: case Format::TAR_ZSTD: + case Format::ZIP: + return make_unique(); default: throw XwimError{ "Cannot construct archiver for {}. `extension_format` surjection " diff --git a/src/Archiver.hpp b/src/Archiver.hpp index 430f442..f522c5b 100644 --- a/src/Archiver.hpp +++ b/src/Archiver.hpp @@ -8,17 +8,10 @@ #include #include "util/Common.hpp" +#include "Formats.hpp" namespace xwim { -// Invariant: -// `extensions_format` defines a surjection from `format_extensions` -// to `Formats` -const std::set format_extensions{".tar.gz", ".zip"}; -enum class Format { TAR_GZ, ZIP }; -const std::map extensions_format{ - {".tar.gz", Format::TAR_GZ}, {".zip", Format::ZIP}}; - class Archiver { public: virtual void compress(std::set ins, diff --git a/src/Formats.hpp b/src/Formats.hpp new file mode 100644 index 0000000..ea71a39 --- /dev/null +++ b/src/Formats.hpp @@ -0,0 +1,49 @@ +#pragma once + +namespace xwim { + using namespace std; + + // Invariant: + // `extensions_format` defines a surjection from `format_extensions` + // to `Formats` + enum class Format { + UNKNOWN, + TAR_BZIP2, TAR_GZIP, TAR_LZIP, TAR_XZ, TAR_COMPRESS, TAR_ZSTD, + ZIP + }; + + const set format_extensions{ + // tar formats see: https://en.wikipedia.org/wiki/Tar_(computing)#Suffixes_for_compressed_files + + /* bzip2 */ ".tar.bz2", ".tb2", ".tbz", ".tbz2", ".tz2", + /* gzip */ ".tar.gz", ".taz", ".tgz", + /* lzip */ ".tar.lz", + /* xz */ ".tar.xz", ".txz", + /* compress */ ".tar.Z", ".tZ", ".taZ", + /* zstd */ ".tar.zst", ".tzst", + + /* zip */ ".zip" + }; + + const map, Format> extensions_format{ + {{".tar.bz2", ".tb2", ".tbz", ".tbz2", ".tz2"}, Format::TAR_BZIP2}, + {{".tar.gz", ".taz", ".tgz"}, Format::TAR_GZIP}, + {{".tar.lz"}, Format::TAR_LZIP}, + {{".tar.xz", ".txz"}, Format::TAR_XZ}, + {{".tar.Z", ".tZ", ".taZ"}, Format::TAR_COMPRESS}, + {{".tar.zst", ".tzst"}, Format::TAR_ZSTD}, + + {{".zip"}, Format::ZIP} + }; + + inline Format find_extension_format(const string& ext) { + for(auto ef: extensions_format) { + auto f = ef.first.find(ext); + if(f != ef.first.end()) { + return ef.second; + } + } + + return Format::UNKNOWN; + } +} diff --git a/src/Xwim.cpp b/src/Xwim.cpp deleted file mode 100644 index 001b610..0000000 --- a/src/Xwim.cpp +++ /dev/null @@ -1,165 +0,0 @@ -#include "Xwim.hpp" - -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "Archiver.hpp" -#include "util/Common.hpp" - -namespace xwim { -using namespace std; -namespace fs = std::filesystem; - -#if defined(unix) || defined(__unix__) || defined(__unix) -std::string default_extension = ".tar.gz"; -#elif defined(_win32) || defined(__win32__) || defined(__windows__) -std::string default_extension = ".zip"; -#else -std::string default_extension = ".zip"; -#endif - -Xwim::Xwim() : action{Action::UNKNOWN} {} - -void Xwim::try_infer() { - infer_action(); - infer_output(); - - if (action == Action::COMPRESS) { - archiver = make_archiver(out.string()); - } else if (action == Action::EXTRACT) { - // we can only handle one archive for extraction at a time. - // Checked in `infer_extraction_output` - archiver = make_archiver(ins.begin()->string()); - } -} -void Xwim::dwim() { - switch (action) { - case Action::COMPRESS: - this->archiver->compress(ins, out); - break; - case Action::EXTRACT: - this->archiver->extract(*ins.begin(), out); - sanitize_output(); - break; - default: - spdlog::error("Unknown action"); - } -} - -void Xwim::sanitize_output() { - fs::path in_stripped = xwim::strip_archive_extension(*ins.begin()); - - int count = 0; - fs::directory_entry first_entry; - for(auto& e: fs::directory_iterator(out)) { - count++; - if(first_entry.path().empty()) { - first_entry = e; - } - } - - if (count >= 2) { - spdlog::debug("Found multiple entries in extraction directory. Moving {} to {}", out, in_stripped); - fs::rename(out, in_stripped); - } else { - if(first_entry.is_directory()) { - spdlog::debug("Found single directory in extraction directory. Moving {} to {}", - first_entry.path(), in_stripped); - fs::rename(first_entry, in_stripped); - fs::remove(out); - } else { - spdlog::debug( - "Found single file in extraction directory. Moving {} to {}", out, in_stripped); - fs::rename(out, in_stripped); - } - } -} - -void Xwim::infer_action() { - if (action != Action::UNKNOWN) return; - - if (ins.size() == 1 && can_extract(*ins.begin())) { - action = Action::EXTRACT; - } else { - action = Action::COMPRESS; - } - spdlog::debug("Inferred action: {}", action); -} - -void Xwim::infer_output() { - if (!out.empty()) return; - - switch (action) { - case Action::COMPRESS: - infer_compression_output(); - break; - case Action::EXTRACT: - infer_extraction_output(); - break; - default: - throw XwimError{"Cannot infer output, action is unknown"}; - } - - spdlog::debug("Inferred out: {}", out.string()); -} - -void Xwim::infer_compression_output() { - if (ins.size() == 1) { - // archive name is just the name of the input with default archive - // extension - fs::path archive_stem = xwim::strip_archive_extension(*ins.begin()); - archive_stem += default_extension; - out = archive_stem; - } else { - // We cannot guess the name of the output archive - - // TODO use readline/lineoise/editline for path completion - cout << "Archive name: "; - cin >> out; - out = fs::path(out); - } -} -void Xwim::infer_extraction_output() { - if (ins.size() > 1) { - throw XwimError{"Cannot extract more than one archive at a time"}; - } - - // create a temporary path for extraction - fs::path archive_stem = xwim::strip_archive_extension(*ins.begin()); - - // note: we use here what is considered an `extensions` by `fs::path` so that - // we can strip it again easily later on - archive_stem += "."; - archive_stem += to_string(rand_int(999, 99999)); - archive_stem += ".tmp"; - this->out = archive_stem; -} - -void Xwim::setCompress() { - this->action = Action::COMPRESS; - spdlog::debug("Set action to {}", this->action); -} -void Xwim::setExtract() { - this->action = Action::EXTRACT; - spdlog::debug("Set action to {}", this->action); -} -void Xwim::setOut(fs::path path) { - this->out = path; - spdlog::debug("Set out to {}", this->out); -} -void Xwim::setIns(vector ins) { - this->ins.insert(ins.begin(), ins.end()); - if (this->ins.size() != ins.size()) { - spdlog::warn("Duplicate input files found. Removed {} duplicate(s).", - (ins.size() - this->ins.size())); - } -} -} // namespace xwim diff --git a/src/Xwim.hpp b/src/Xwim.hpp deleted file mode 100644 index 665e770..0000000 --- a/src/Xwim.hpp +++ /dev/null @@ -1,106 +0,0 @@ -#pragma once - -#include -#include - -#include -#include -#include -#include -#include - -#include "Archiver.hpp" -#include "util/Common.hpp" -#include "UserOpt.hpp" - -namespace xwim { -using namespace std; -namespace fs = std::filesystem; - -enum class Action { EXTRACT, COMPRESS }; - -struct XwimIntent { - -}; - -class XwimBuilder { - private: - UserOpt user_opt; - - public: - XwimBuilder(UserOpt user_opt) : user_opt(user_opt){}; - Xwim build(); -}; - -class Xwim { - public: - virtual XwimResult dwim() = 0; -}; - -class XwimCompressor : public Xwim { -private: - fs::path archive; - std::set paths; -}; - -class XwimExtractor : public Xwim {}; - -class XwimConfig { - public: - Action get_action(); -} - -class Xwim { - private: - XwimEngine xwim_engine; - UserOpt user_opt; - - public: - Xwim(UserOpt user_opt); - void dwim(); -} - -class Xwim { - private: - Action action; - fs::path out; - set ins; - unique_ptr archiver; - - void infer_action(); - void infer_output(); - void infer_compression_output(); - void infer_extraction_output(); - void sanitize_output(); - - public: - Xwim(); - - void try_infer(); - void dwim(); - - void setCompress(); - void setExtract(); - void setOut(fs::path); - void setIns(vector ins); -}; - -} // namespace xwim - -template <> -struct fmt::formatter { - constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); } - - template - auto format(const xwim::Action& action, FormatContext& ctx) { - switch (action) { - case xwim::Action::UNKNOWN: - return format_to(ctx.out(), "UNKNOWN"); - case xwim::Action::EXTRACT: - return format_to(ctx.out(), "EXTRACT"); - case xwim::Action::COMPRESS: - return format_to(ctx.out(), "COMPRESS"); - }; - return format_to(ctx.out(), ""); - } -}; diff --git a/src/XwimConfig.hpp b/src/XwimConfig.hpp deleted file mode 100644 index 8ae6e9b..0000000 --- a/src/XwimConfig.hpp +++ /dev/null @@ -1,15 +0,0 @@ -#pragma once - -namespace xwim { - -enum class Action { COMPRESS, EXTRACT }; - -class XwimConfig { - -public: - Action get_action(); - - -} - -}