Relative root path in archive, clang-format, refactoring
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/tag Build is passing

Compressed archives now contain a single root which consists of the file or
folder being compressed. Before, the archive root contained the full relative
path form the current working directory to the compressed file or folder. This
is unintuitive in most cases and not dwim.
This commit is contained in:
Armin Friedl 2020-08-03 00:52:37 +02:00
parent cdb3775eb6
commit d9cbf47036
Signed by: armin
GPG key ID: 48C726EEE7FBCBC8
4 changed files with 296 additions and 74 deletions

View file

@ -1 +1,168 @@
BasedOnStyle: Chromium
---
Language: Cpp
# BasedOnStyle: Google
AccessModifierOffset: -1
AlignAfterOpenBracket: Align
AlignConsecutiveMacros: false
AlignConsecutiveAssignments: false
AlignConsecutiveDeclarations: false
AlignEscapedNewlines: Left
AlignOperands: true
AlignTrailingComments: true
AllowAllArgumentsOnNextLine: true
AllowAllConstructorInitializersOnNextLine: true
AllowAllParametersOfDeclarationOnNextLine: true
AllowShortBlocksOnASingleLine: Never
AllowShortCaseLabelsOnASingleLine: false
AllowShortFunctionsOnASingleLine: All
AllowShortLambdasOnASingleLine: All
AllowShortIfStatementsOnASingleLine: WithoutElse
AllowShortLoopsOnASingleLine: true
AlwaysBreakAfterDefinitionReturnType: None
AlwaysBreakAfterReturnType: None
AlwaysBreakBeforeMultilineStrings: true
AlwaysBreakTemplateDeclarations: Yes
BinPackArguments: true
BinPackParameters: true
BraceWrapping:
AfterCaseLabel: false
AfterClass: false
AfterControlStatement: false
AfterEnum: false
AfterFunction: false
AfterNamespace: false
AfterObjCDeclaration: false
AfterStruct: false
AfterUnion: false
AfterExternBlock: false
BeforeCatch: false
BeforeElse: false
IndentBraces: false
SplitEmptyFunction: true
SplitEmptyRecord: true
SplitEmptyNamespace: true
BreakBeforeBinaryOperators: None
BreakBeforeBraces: Attach
BreakBeforeInheritanceComma: false
BreakInheritanceList: BeforeColon
BreakBeforeTernaryOperators: true
BreakConstructorInitializersBeforeComma: false
BreakConstructorInitializers: BeforeColon
BreakAfterJavaFieldAnnotations: false
BreakStringLiterals: true
ColumnLimit: 80
CommentPragmas: '^ IWYU pragma:'
CompactNamespaces: false
ConstructorInitializerAllOnOneLineOrOnePerLine: true
ConstructorInitializerIndentWidth: 4
ContinuationIndentWidth: 4
Cpp11BracedListStyle: true
DeriveLineEnding: true
DerivePointerAlignment: true
DisableFormat: false
ExperimentalAutoDetectBinPacking: false
FixNamespaceComments: true
ForEachMacros:
- foreach
- Q_FOREACH
- BOOST_FOREACH
IncludeBlocks: Regroup
IncludeCategories:
- Regex: '^<ext/.*\.h>'
Priority: 2
SortPriority: 0
- Regex: '^<.*\.h>'
Priority: 1
SortPriority: 0
- Regex: '^<.*'
Priority: 2
SortPriority: 0
- Regex: '.*'
Priority: 3
SortPriority: 0
IncludeIsMainRegex: '([-_](test|unittest))?$'
IncludeIsMainSourceRegex: ''
IndentCaseLabels: true
IndentGotoLabels: true
IndentPPDirectives: None
IndentWidth: 2
IndentWrappedFunctionNames: false
JavaScriptQuotes: Leave
JavaScriptWrapImports: true
KeepEmptyLinesAtTheStartOfBlocks: false
MacroBlockBegin: ''
MacroBlockEnd: ''
MaxEmptyLinesToKeep: 1
NamespaceIndentation: None
ObjCBinPackProtocolList: Never
ObjCBlockIndentWidth: 2
ObjCSpaceAfterProperty: false
ObjCSpaceBeforeProtocolList: true
PenaltyBreakAssignment: 2
PenaltyBreakBeforeFirstCallParameter: 1
PenaltyBreakComment: 300
PenaltyBreakFirstLessLess: 120
PenaltyBreakString: 1000
PenaltyBreakTemplateDeclaration: 10
PenaltyExcessCharacter: 1000000
PenaltyReturnTypeOnItsOwnLine: 200
PointerAlignment: Left
RawStringFormats:
- Language: Cpp
Delimiters:
- cc
- CC
- cpp
- Cpp
- CPP
- 'c++'
- 'C++'
CanonicalDelimiter: ''
BasedOnStyle: google
- Language: TextProto
Delimiters:
- pb
- PB
- proto
- PROTO
EnclosingFunctions:
- EqualsProto
- EquivToProto
- PARSE_PARTIAL_TEXT_PROTO
- PARSE_TEST_PROTO
- PARSE_TEXT_PROTO
- ParseTextOrDie
- ParseTextProtoOrDie
CanonicalDelimiter: ''
BasedOnStyle: google
ReflowComments: true
SortIncludes: true
SortUsingDeclarations: true
SpaceAfterCStyleCast: false
SpaceAfterLogicalNot: false
SpaceAfterTemplateKeyword: true
SpaceBeforeAssignmentOperators: true
SpaceBeforeCpp11BracedList: false
SpaceBeforeCtorInitializerColon: true
SpaceBeforeInheritanceColon: true
SpaceBeforeParens: ControlStatements
SpaceBeforeRangeBasedForLoopColon: true
SpaceInEmptyBlock: false
SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 2
SpacesInAngles: false
SpacesInConditionalStatement: false
SpacesInContainerLiterals: true
SpacesInCStyleCastParentheses: false
SpacesInParentheses: false
SpacesInSquareBrackets: false
SpaceBeforeSquareBrackets: false
Standard: Auto
StatementMacros:
- Q_UNUSED
- QT_REQUIRE_VERSION
TabWidth: 8
UseCRLF: false
UseTab: Never
...

View file

@ -126,12 +126,12 @@ Per default xwim chooses an appropriate log level according to your build type
- off
# Contributing
While xwim is still in incubator phase (i.e. before version 1.0) it's main
While xwim is still in incubator phase (i.e. before version 1.0) its main
repository is hosted on https://git.friedl.net/incubator/xwim with a mirror on
https://github.com/arminfriedl/xwim. With the first stable release it will most
likely move to GitHub as it's main repository.
likely move to GitHub as its main repository.
If you want to contribute, you can either issue a pull request on it's Github
If you want to contribute, you can either issue a pull request on its Github
mirror (will be cherry picked into the main repository) or send patches to
dev[at]friedl[dot]net.

View file

@ -1,8 +1,9 @@
project('xwim', 'cpp',
version: '0.2',
version: '0.3',
default_options: ['cpp_std=c++17',
'warning_level=3',
'b_coverage=true'])
'b_coverage=true',
'b_ndebug=if-release'])
subdir('src')
subdir('doc')

View file

@ -1,20 +1,22 @@
#include <fcntl.h>
#include <archive_entry.h>
#include <fcntl.h>
#include <spdlog/spdlog.h>
#include "archive.hpp"
#include "fileformats.hpp"
#include "spec.hpp"
namespace logger = spdlog;
#include "archive_sys.hpp"
#include <archive.h>
#include <filesystem>
#include <memory>
bool xwim::ArchiveEntryView::is_empty() {
return (this->ae == nullptr);
}
#include "archive_sys.hpp"
namespace fs = std::filesystem;
bool xwim::ArchiveEntryView::is_empty() { return (this->ae == nullptr); }
std::string xwim::ArchiveEntryView::path_name() {
if (!this->ae) throw ArchiveSysException{"Access to invalid archive entry"};
@ -22,9 +24,9 @@ std::string xwim::ArchiveEntryView::path_name() {
return archive_entry_pathname(this->ae);
}
std::filesystem::path xwim::ArchiveEntryView::path() {
fs::path xwim::ArchiveEntryView::path() {
if (!this->ae) throw ArchiveSysException{"Access to invalid archive entry"};
return std::filesystem::path{this->path_name()};
return fs::path{this->path_name()};
}
mode_t xwim::ArchiveEntryView::file_type() {
@ -36,7 +38,7 @@ bool xwim::ArchiveEntryView::is_directory() {
return S_ISDIR(this->file_type());
}
xwim::ArchiveReaderSys::ArchiveReaderSys(std::filesystem::path& path) {
xwim::ArchiveReaderSys::ArchiveReaderSys(fs::path &path) {
int r; // libarchive error handling
logger::trace("Setting up archive reader");
@ -63,8 +65,12 @@ bool xwim::ArchiveReaderSys::advance() {
logger::trace("Advancing reader to next archive entry");
r = archive_read_next_header(this->ar, &this->ae);
if (r == ARCHIVE_EOF) { this->ae = nullptr; return false; }
if (r != ARCHIVE_OK) throw(ArchiveSysException{"Could not list archive", this->ar});
if (r == ARCHIVE_EOF) {
this->ae = nullptr;
return false;
}
if (r != ARCHIVE_OK)
throw(ArchiveSysException{"Could not list archive", this->ar});
logger::trace("Got entry {}", archive_entry_pathname(ae));
return true;
@ -74,16 +80,17 @@ const xwim::ArchiveEntryView xwim::ArchiveReaderSys::cur() {
return ArchiveEntryView{this->ae};
}
xwim::ArchiveExtractorSys::ArchiveExtractorSys(std::filesystem::path& root) {
xwim::ArchiveExtractorSys::ArchiveExtractorSys(fs::path &root) {
logger::trace("Constructing ArchiveExtractorSys with path {}", root.string());
std::filesystem::create_directories(root);
std::filesystem::current_path(root);
fs::create_directories(root);
fs::current_path(root);
this->writer = archive_write_disk_new();
archive_write_disk_set_standard_lookup(this->writer);
logger::trace("Constructed ArchiveExtractorSys at {:p}", (void*) this->writer);
logger::trace("Constructed ArchiveExtractorSys at {:p}",
(void *)this->writer);
}
xwim::ArchiveExtractorSys::ArchiveExtractorSys() {
@ -91,7 +98,8 @@ xwim::ArchiveExtractorSys::ArchiveExtractorSys() {
this->writer = archive_write_disk_new();
archive_write_disk_set_standard_lookup(this->writer);
logger::trace("Constructed ArchiveExtractorSys at {:p}", (void*) this->writer);
logger::trace("Constructed ArchiveExtractorSys at {:p}",
(void *)this->writer);
}
void xwim::ArchiveExtractorSys::extract_all(xwim::ArchiveReaderSys &reader) {
@ -117,14 +125,17 @@ void xwim::ArchiveExtractorSys::extract_entry(xwim::ArchiveReaderSys& reader) {
}
xwim::ArchiveExtractorSys::~ArchiveExtractorSys() {
logger::trace("Destructing ArchiveExtractorSys at {:p}", (void*) this->writer);
logger::trace("Destructing ArchiveExtractorSys at {:p}",
(void *)this->writer);
if (this->writer) {
archive_write_close(this->writer);
archive_write_free(this->writer);
}
}
xwim::ArchiveCompressorSys::ArchiveCompressorSys(std::filesystem::path& root, xwim::CompressSpec compress_spec): root{root}, compress_spec{compress_spec} {
xwim::ArchiveCompressorSys::ArchiveCompressorSys(
fs::path &root, xwim::CompressSpec compress_spec)
: root{root}, compress_spec{compress_spec} {
this->new_archive = archive_write_new();
for (xwim::archive_filter filter : this->compress_spec.filters) {
@ -134,48 +145,24 @@ xwim::ArchiveCompressorSys::ArchiveCompressorSys(std::filesystem::path& root, xw
archive_write_set_format(this->new_archive, this->compress_spec.format);
}
// forward declared
static fs::path archive_path_norm(const fs::path &root,
const xwim::CompressSpec &compress_spec);
void xwim::ArchiveCompressorSys::compress() {
std::filesystem::path archive_path{this->root};
if(!std::filesystem::exists(archive_path)) {
logger::error("Non-existing path: {}", archive_path.string());
throw ArchiveSysException{"Path does not exists"};
}
fs::path archive_path = archive_path_norm(this->root, this->compress_spec);
std::filesystem::file_status file_status = std::filesystem::status(archive_path);
logger::debug("Writing archive at: {}", archive_path.filename().c_str());
if(file_status.type() != std::filesystem::file_type::directory
&& file_status.type() != std::filesystem::file_type::regular) {
logger::error("Unknown path type: {}", file_status.type());
throw ArchiveSysException{"Unknown path type"};
}
if ((file_status.permissions() & std::filesystem::perms::owner_read) ==
std::filesystem::perms::none &&
(file_status.permissions() & std::filesystem::perms::group_read) ==
std::filesystem::perms::none &&
(file_status.permissions() & std::filesystem::perms::others_read) ==
std::filesystem::perms::none) {
logger::error("Cannot read path with permissions: {}",
file_status.permissions());
throw ArchiveSysException{"Unreadable path"};
}
if(file_status.type() == std::filesystem::file_type::regular) {
while(archive_path.has_extension()) {
archive_path.replace_extension();
}
}
archive_path.concat(this->compress_spec.extension);
logger::debug("Writing archive at: {}", std::filesystem::absolute(archive_path).c_str());
archive_write_open_filename(this->new_archive, std::filesystem::absolute(archive_path).c_str());
archive_write_open_filename(this->new_archive,
archive_path.filename().c_str());
archive *disk = archive_read_disk_new();
archive_read_disk_set_standard_lookup(disk);
int r;
r = archive_read_disk_open(disk, std::filesystem::relative(this->root).c_str());
r = archive_read_disk_open(disk, fs::relative(this->root).c_str());
if (r != ARCHIVE_OK) {
throw ArchiveSysException("Could not open path for archiving", disk);
}
@ -186,13 +173,16 @@ void xwim::ArchiveCompressorSys::compress() {
for (;;) {
entry = archive_entry_new();
r = archive_read_next_header2(disk, entry);
if (r == ARCHIVE_EOF)
break;
if (r == ARCHIVE_EOF) break;
if (r != ARCHIVE_OK) {
throw ArchiveSysException("Could not read next archive entry", disk);
}
archive_read_disk_descend(disk);
const char* ae_path = archive_entry_pathname(entry);
fs::path ae_rel_path = fs::relative(fs::path(ae_path), this->root.parent_path());
archive_entry_set_pathname(entry, ae_rel_path.c_str());
logger::trace("Processing entry {}", archive_entry_pathname(entry));
r = archive_write_header(this->new_archive, entry);
@ -200,6 +190,7 @@ void xwim::ArchiveCompressorSys::compress() {
throw ArchiveSysException("Could not write header for archive entry",
this->new_archive);
}
if (r > ARCHIVE_FAILED) {
int fd = open(archive_entry_sourcepath(entry), O_RDONLY);
ssize_t len = read(fd, buff, sizeof(buff));
@ -209,18 +200,81 @@ void xwim::ArchiveCompressorSys::compress() {
}
close(fd);
}
logger::trace("Entry written {}", archive_entry_pathname(entry));
archive_entry_free(entry);
}
}
xwim::ArchiveCompressorSys::~ArchiveCompressorSys() {
logger::trace("Destructing ArchiveExtractorSys at {:p}", (void*) this->new_archive);
logger::trace("Destructing ArchiveExtractorSys at {:p}",
(void *)this->new_archive);
if (this->new_archive) {
archive_write_close(this->new_archive);
archive_write_free(this->new_archive);
}
}
/** Creates an archive path from the path to compress and normalizes it
*
* Note that currently only single arguments are allowed for `xwim` to
* minimize ambiguity.
*
* The archive path is determined from the argument file/directory by:
* 1. If file:
* 1.1. Stem the filename
* 1.2. Append an extension appropriate for the archive format (from the
* spec)
* 2. If directory:
* 2.1. Remove any trailing '/'
* 2.2. Append an extension appropriate for the archive format (from the
* spec)
*/
static fs::path archive_path_norm(const fs::path &root,
const xwim::CompressSpec &compress_spec) {
fs::path archive_path{root};
fs::file_status archive_path_stat = fs::status(archive_path);
std::set known_types = {fs::file_type::directory, fs::file_type::regular};
fs::perms flag_mask =
fs::perms::owner_read | fs::perms::group_read | fs::perms::others_read;
if (!fs::exists(archive_path)) {
logger::error("Non-existing path: {}", archive_path.string());
throw xwim::ArchiveSysException{"Path does not exists"};
}
if (!known_types.count(archive_path_stat.type())) {
logger::error("Unknown path type: {}", archive_path_stat.type());
throw xwim::ArchiveSysException{"Unknown path type"};
}
if ((archive_path_stat.permissions() & flag_mask) == fs::perms::none) {
logger::error("Cannot read path with permissions: {}",
archive_path_stat.permissions());
throw xwim::ArchiveSysException{"Unreadable path"};
}
if (archive_path_stat.type() == fs::file_type::regular) {
while (archive_path.has_extension()) {
archive_path.replace_extension();
}
}
if (archive_path_stat.type() == fs::file_type::directory) {
if (archive_path.string().back() == '/') {
logger::trace("Found trailing / in path");
std::string ps = archive_path.string();
ps.erase(ps.size() - 1, 1);
archive_path = fs::path{ps};
logger::trace("Normalized path to {}", archive_path.string());
}
}
archive_path.concat(compress_spec.extension);
return archive_path;
}
static int copy_data(struct archive *ar, struct archive *aw) {
int r;
const void *buff;