- Provides better handling of invalid invocation - Provides usage output - More flexible for future extension (e.g. compression)
This commit is contained in:
parent
45a5d3372d
commit
7058c326c6
7 changed files with 179 additions and 6 deletions
|
@ -4,6 +4,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <spdlog/spdlog.h>
|
||||
#include <optional>
|
||||
namespace logger = spdlog;
|
||||
|
||||
#include <filesystem>
|
||||
|
@ -22,7 +23,7 @@ namespace xwim {
|
|||
*/
|
||||
const std::set<std::string> fileformats{".7z", ".7zip", ".jar", ".tgz",
|
||||
".bz2", ".bzip2", ".gz", ".gzip",
|
||||
".rar", ".tar", "xz", ".zip"};
|
||||
".rar", ".tar", ".xz", ".zip"};
|
||||
|
||||
/** Strip archive extensions from a path
|
||||
*
|
||||
|
@ -43,4 +44,26 @@ inline std::filesystem::path stem(const std::filesystem::path& path) {
|
|||
return p_stem;
|
||||
}
|
||||
|
||||
/** Get the archive extension of a path.
|
||||
*
|
||||
* The archive extension may be a combination of supported fileformats in which
|
||||
* case all of them are returned.
|
||||
*
|
||||
* @returns Archive extension of the archive or path() if no (known) extension
|
||||
* exists.
|
||||
*/
|
||||
inline std::filesystem::path ext(const std::filesystem::path& path) {
|
||||
std::filesystem::path p_ext{path};
|
||||
logger::trace("Extracting extension of {}", p_ext.string());
|
||||
|
||||
std::filesystem::path p_ext_collector;
|
||||
while (fileformats.find(p_ext.extension().string()) != fileformats.end()) {
|
||||
// path extension() const
|
||||
p_ext_collector = p_ext.extension().concat(p_ext_collector.string());
|
||||
p_ext.replace_extension();
|
||||
}
|
||||
|
||||
return p_ext_collector;
|
||||
}
|
||||
|
||||
} // namespace xwim
|
||||
|
|
17
src/main.cpp
17
src/main.cpp
|
@ -1,4 +1,5 @@
|
|||
#include <spdlog/common.h>
|
||||
#include <cstdlib>
|
||||
namespace logger = spdlog;
|
||||
|
||||
#include <iostream>
|
||||
|
@ -7,6 +8,7 @@ namespace logger = spdlog;
|
|||
#include <list>
|
||||
|
||||
#include "util/log.hpp"
|
||||
#include "util/argparse.hpp"
|
||||
#include "archive.hpp"
|
||||
#include "spec.hpp"
|
||||
#include "fileformats.hpp"
|
||||
|
@ -14,9 +16,18 @@ namespace logger = spdlog;
|
|||
int main(int argc, char** argv) {
|
||||
xwim::log::init();
|
||||
|
||||
xwim::argparse::XwimPath xwim_path;
|
||||
|
||||
try {
|
||||
std::filesystem::path filepath{argv[1]};
|
||||
xwim::Archive archive{filepath};
|
||||
xwim_path = xwim::argparse::parse(argc, argv);
|
||||
} catch (xwim::argparse::ArgParseException& ex) {
|
||||
logger::error("{}\n", ex.what());
|
||||
std::cout << xwim::argparse::usage();
|
||||
std::exit(1);
|
||||
}
|
||||
|
||||
try {
|
||||
xwim::Archive archive{xwim_path.path()};
|
||||
xwim::ArchiveSpec archive_spec = archive.check();
|
||||
|
||||
logger::info("{}", archive_spec);
|
||||
|
@ -26,7 +37,7 @@ int main(int argc, char** argv) {
|
|||
if (!archive_spec.has_single_root || !archive_spec.is_root_filename) {
|
||||
extract_spec.make_dir = true;
|
||||
|
||||
std::filesystem::path stem = xwim::stem(filepath);
|
||||
std::filesystem::path stem = xwim::stem(xwim_path.path());
|
||||
|
||||
extract_spec.dirname = stem;
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
xwim_src = ['main.cpp',
|
||||
'archive.cpp',
|
||||
'archive_sys.cpp']
|
||||
'archive_sys.cpp',
|
||||
'util/argparse.cpp']
|
||||
|
||||
xwim_libs = [dependency('libarchive', required: true),
|
||||
dependency('fmt', required: true),
|
||||
|
|
29
src/util/argparse.cpp
Normal file
29
src/util/argparse.cpp
Normal file
|
@ -0,0 +1,29 @@
|
|||
#include "argparse.hpp"
|
||||
|
||||
namespace xwim {
|
||||
namespace argparse {
|
||||
XwimPath parse(int argc, char** argv) {
|
||||
return XwimPath{argc, argv};
|
||||
}
|
||||
|
||||
// contructs XwimPath{} first so that destructurs may running
|
||||
// http://www.vishalchovatiya.com/7-best-practices-for-exception-handling-in-cpp-with-example/
|
||||
XwimPath::XwimPath(int argc, char** argv) : XwimPath{} {
|
||||
if (argc < 2) throw ArgParseException{"No argument provided"};
|
||||
if (argc > 2) throw ArgParseException{"Too many arguments provided"};
|
||||
|
||||
this->_path = std::filesystem::path{argv[1]};
|
||||
|
||||
// Remove when compression in place
|
||||
if(!is_archive()) throw ArgParseException{"Not a known archive format"};
|
||||
}
|
||||
|
||||
bool XwimPath::is_archive() {
|
||||
return !xwim::ext(_path).empty();
|
||||
}
|
||||
|
||||
std::filesystem::path XwimPath::path() const {
|
||||
return std::filesystem::path{_path};
|
||||
}
|
||||
}
|
||||
}
|
79
src/util/argparse.hpp
Normal file
79
src/util/argparse.hpp
Normal file
|
@ -0,0 +1,79 @@
|
|||
#pragma once
|
||||
|
||||
#include <filesystem>
|
||||
#include <ostream>
|
||||
#include <sstream>
|
||||
|
||||
#include "../fileformats.hpp"
|
||||
|
||||
namespace xwim {
|
||||
/**
|
||||
* xwim allows for
|
||||
* 1. an archive
|
||||
* 2. a file or folder
|
||||
*
|
||||
* In case of (1) the archive will be extracted according to the xwim
|
||||
* do-what-i-mean rules.
|
||||
*
|
||||
* In case of (2) the file or folder will be compressed into a "platform native"
|
||||
* format, i.e. what appears to be the most widely used format on that platform.
|
||||
* In case of unix this is tar.gz. In case of windows this is zip. The archive
|
||||
* gets the same name as the file or folder and a proper extension.
|
||||
*
|
||||
* A list of files or folders is unsupported as it would be too ambigious to
|
||||
* choose a name for the archive. A list of archives is unsupported for
|
||||
* consistency reasons. Any mixture is unsupported as it would be too ambigious
|
||||
* what the user wants. This is subject to change in the future.
|
||||
*/
|
||||
namespace argparse {
|
||||
|
||||
class XwimPath {
|
||||
private:
|
||||
std::filesystem::path _path;
|
||||
|
||||
public:
|
||||
XwimPath() : _path{} {};
|
||||
XwimPath(int argc, char** argv);
|
||||
|
||||
bool is_archive();
|
||||
std::filesystem::path path() const;
|
||||
};
|
||||
|
||||
class ArgParseException : public std::exception {
|
||||
private:
|
||||
std::string _what;
|
||||
|
||||
public:
|
||||
ArgParseException(std::string what) : _what{what} {};
|
||||
|
||||
virtual const char* what() const noexcept { return this->_what.c_str(); }
|
||||
};
|
||||
|
||||
XwimPath parse(int argc, char** argv);
|
||||
|
||||
inline std::string usage() {
|
||||
std::stringstream s;
|
||||
s << "USAGE:"
|
||||
<< "\t xwim <path>\n"
|
||||
<< "\n"
|
||||
|
||||
<< "PARAMS:" << std::left << std::setfill('.') << std::setw(10)
|
||||
<< "\t path "
|
||||
<< " Archive\n"
|
||||
<< "\n"
|
||||
|
||||
<< "FORMATS:\n"
|
||||
<< "\t .7z, .7zip .jar, .tgz, .bz2, .bzip2\n"
|
||||
<< "\t .gz, .gzip, .rar, .tar, .xz, .zip\n"
|
||||
<< "\n"
|
||||
|
||||
<< "EXAMPLES:\n"
|
||||
<< "\t Extract archive archive.tar.gz:\n"
|
||||
<< "\t xwim archive.tar.gz\n"
|
||||
<< std::endl;
|
||||
|
||||
return s.str();
|
||||
}
|
||||
|
||||
} // namespace argparse
|
||||
} // namespace xwim
|
|
@ -34,7 +34,7 @@ spdlog::level::level_enum _init_from_env() {
|
|||
}
|
||||
|
||||
return lvl;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Get log level from compile time definition.
|
||||
|
|
|
@ -32,3 +32,33 @@ TEST(FileformatsTest, StemStripsNothingWithoutExtension) {
|
|||
|
||||
ASSERT_EQ(xwim::stem(archive_path), std::filesystem::path{"filerar"});
|
||||
}
|
||||
|
||||
TEST(FileExtTest, ExtGetsKnownExtension) {
|
||||
std::filesystem::path archive_path{"/some/path/to/file.rar"};
|
||||
|
||||
ASSERT_EQ(xwim::ext(archive_path), std::filesystem::path{".rar"});
|
||||
}
|
||||
|
||||
TEST(FileExtTest, CombinedExtensionGetsAll) {
|
||||
std::filesystem::path archive_path{"/some/path/to/file.tar.gz"};
|
||||
|
||||
ASSERT_EQ(xwim::ext(archive_path), std::filesystem::path{".tar.gz"});
|
||||
}
|
||||
|
||||
TEST(FileExtTest, ExtEmptyForUnknownExtension) {
|
||||
std::filesystem::path archive_path{"/some/path/to/file.ukn"};
|
||||
|
||||
ASSERT_TRUE(xwim::ext(archive_path).empty());
|
||||
}
|
||||
|
||||
TEST(FileExtTest, CombinedExtensionGetsKnown) {
|
||||
std::filesystem::path archive_path{"/some/path/to/file.ukn.tar.gz"};
|
||||
|
||||
ASSERT_EQ(xwim::ext(archive_path), std::filesystem::path{".tar.gz"});
|
||||
}
|
||||
|
||||
TEST(FileExtTest, CombinedExtensionLastUnknownEmpty) {
|
||||
std::filesystem::path archive_path{"/some/path/to/file.tar.gz.ukn"};
|
||||
|
||||
ASSERT_TRUE(xwim::ext(archive_path).empty());
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue