Restructure ExtractIntent
All checks were successful
continuous-integration/drone/push Build is passing

This commit is contained in:
Armin Friedl 2024-03-02 16:01:53 +01:00
parent 92ac6586de
commit 1523f83a6b
Signed by: armin
GPG key ID: 48C726EEE7FBCBC8
2 changed files with 85 additions and 66 deletions

View file

@ -120,65 +120,81 @@ unique_ptr<UserIntent> make_intent(const UserOpt &userOpt) {
throw XwimError("Cannot guess intent"); throw XwimError("Cannot guess intent");
} }
void ExtractIntent::execute() { void ExtractIntent::dwim_reparent(const path &out) {
bool has_out = this->out.has_value(); // move extraction if extraction resulted in only one entry and that entries
bool is_single = this->archives.size() == 1; // name is already the stripped archive name, i.e. reduce unnecessary nesting
for (const path &p : this->archives) {
unique_ptr<Archiver> 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);
// move folder if only one entry and that entries name is already
// the stripped archive name
auto dit = std::filesystem::directory_iterator(out); auto dit = std::filesystem::directory_iterator(out);
auto dit_path = dit->path();
if (dit == std::filesystem::directory_iterator()) { if (dit == std::filesystem::directory_iterator()) {
spdlog::debug("Archive is empty"); spdlog::debug(
} else if (is_directory(dit->path())) { "Cannot flatten extraction folder: extraction folder is empty");
auto first_path = dit->path(); return;
auto next_entry = next(dit); }
if (!is_directory(dit_path)) {
spdlog::debug("Cannot flatten extraction folder: {} is not a directory",
dit_path);
return;
}
if (next(dit) != std::filesystem::directory_iterator()) {
spdlog::debug("Cannot flatten extraction folder: multiple items extracted");
return;
}
if (!std::filesystem::equivalent(dit_path.filename(), out.filename())) {
spdlog::debug(
"Cannot flatten extraction folder: archive entry differs from archive "
"name [extraction folder: {}, archive entry: {}]",
out.filename(), dit_path.filename());
return;
}
spdlog::debug("Output folder [{}] is equivalent to archive entry [{}]", out,
dit_path);
spdlog::info("Flattening extraction folder");
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); int i = rand_int(0, 100000);
path tmp_out = path{out}; path tmp_out = path{out};
tmp_out.concat(fmt::format(".xwim{}", i)); tmp_out.concat(fmt::format(".xwim{}", i));
spdlog::debug("Move {} to {}", dit_path, tmp_out);
spdlog::debug("Moving {} to {}", first_path, tmp_out); std::filesystem::rename(dit_path, tmp_out);
std::filesystem::rename(first_path, tmp_out); spdlog::debug("Remove parent path {}", out);
spdlog::debug("Removing parent {}", out);
std::filesystem::remove(out); std::filesystem::remove(out);
spdlog::debug("Moving {} to {}", tmp_out, out); spdlog::debug("Moving {} to {}", tmp_out, out);
std::filesystem::rename(tmp_out, out); std::filesystem::rename(tmp_out, out);
}
} else { path ExtractIntent::out_path(const path &p) {
spdlog::debug("Archive entry differs from archive name"); if (!this->out.has_value()) {
// not out path given, create from archive name
path out = std::filesystem::current_path() / strip_archive_extension(p);
create_directories(out);
return out;
} }
} else {
spdlog::debug("Archive has multiple entries"); if (this->archives.size() == 1) {
// out given and only one archive to extract, just extract into `out`
create_directories(this->out.value());
return this->out.value();
}
// out given and multiple archives to extract, create subfolder
// for each archive
create_directories(this->out.value());
path out = this->out.value() / strip_archive_extension(p);
return out;
}
void ExtractIntent::execute() {
for (const path &p : this->archives) {
std::unique_ptr<Archiver> archiver = make_archiver(p);
path out = this->out_path(p);
archiver->extract(p, out);
this->dwim_reparent(out);
} }
} }
}
};
path CompressSingleIntent::out_path() { path CompressSingleIntent::out_path() {
if (this->out.has_value()) { if (this->out.has_value()) {
@ -206,5 +222,5 @@ void CompressManyIntent::execute() {
unique_ptr<Archiver> archiver = make_archiver(this->out); unique_ptr<Archiver> archiver = make_archiver(this->out);
archiver->compress(this->in_paths, this->out); archiver->compress(this->in_paths, this->out);
}; }
} // namespace xwim } // namespace xwim

View file

@ -30,6 +30,9 @@ private:
set<path> archives; set<path> archives;
optional<path> out; optional<path> out;
void dwim_reparent(const path& out);
path out_path(const path& p);
public: public:
ExtractIntent(set<path> archives, optional<path> out): archives(archives), out(out) {}; ExtractIntent(set<path> archives, optional<path> out): archives(archives), out(out) {};
~ExtractIntent() override = default; ~ExtractIntent() override = default;