Add more formats, delete leftovers
This commit is contained in:
parent
e6a6e9268e
commit
c6e0e92db2
6 changed files with 64 additions and 304 deletions
|
@ -1,4 +1,5 @@
|
|||
#include "Archiver.hpp"
|
||||
#include "Formats.hpp"
|
||||
|
||||
#include <spdlog/spdlog.h>
|
||||
|
||||
|
@ -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<Archiver> make_archiver(const string& archive_name) {
|
||||
switch (parse_format(archive_name)) {
|
||||
case Format::TAR_GZ:
|
||||
case Format::ZIP:
|
||||
return make_unique<LibArchiver>();
|
||||
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<LibArchiver>();
|
||||
default:
|
||||
throw XwimError{
|
||||
"Cannot construct archiver for {}. `extension_format` surjection "
|
||||
|
|
|
@ -8,17 +8,10 @@
|
|||
#include <set>
|
||||
|
||||
#include "util/Common.hpp"
|
||||
#include "Formats.hpp"
|
||||
|
||||
namespace xwim {
|
||||
|
||||
// Invariant:
|
||||
// `extensions_format` defines a surjection from `format_extensions`
|
||||
// to `Formats`
|
||||
const std::set<std::string> format_extensions{".tar.gz", ".zip"};
|
||||
enum class Format { TAR_GZ, ZIP };
|
||||
const std::map<std::string, Format> extensions_format{
|
||||
{".tar.gz", Format::TAR_GZ}, {".zip", Format::ZIP}};
|
||||
|
||||
class Archiver {
|
||||
public:
|
||||
virtual void compress(std::set<std::filesystem::path> ins,
|
||||
|
|
49
src/Formats.hpp
Normal file
49
src/Formats.hpp
Normal file
|
@ -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<string> 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<set<string>, 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;
|
||||
}
|
||||
}
|
165
src/Xwim.cpp
165
src/Xwim.cpp
|
@ -1,165 +0,0 @@
|
|||
#include "Xwim.hpp"
|
||||
|
||||
#include <spdlog/spdlog.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdlib>
|
||||
#include <filesystem>
|
||||
#include <ios>
|
||||
#include <iostream>
|
||||
#include <iterator>
|
||||
#include <random>
|
||||
#include <string>
|
||||
|
||||
#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<fs::path> 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
|
106
src/Xwim.hpp
106
src/Xwim.hpp
|
@ -1,106 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <fmt/core.h>
|
||||
#include <fmt/format.h>
|
||||
|
||||
#include <exception>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <set>
|
||||
#include <stdexcept>
|
||||
|
||||
#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<fs::path> 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<fs::path> ins;
|
||||
unique_ptr<Archiver> 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<fs::path> ins);
|
||||
};
|
||||
|
||||
} // namespace xwim
|
||||
|
||||
template <>
|
||||
struct fmt::formatter<xwim::Action> {
|
||||
constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); }
|
||||
|
||||
template <typename FormatContext>
|
||||
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(), "");
|
||||
}
|
||||
};
|
|
@ -1,15 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
namespace xwim {
|
||||
|
||||
enum class Action { COMPRESS, EXTRACT };
|
||||
|
||||
class XwimConfig {
|
||||
|
||||
public:
|
||||
Action get_action();
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in a new issue