From 579e4274f994695a849a02de5d4e81e6d3479017 Mon Sep 17 00:00:00 2001 From: Timothy Stack Date: Wed, 28 Oct 2020 21:17:57 -0700 Subject: [PATCH] [files] initial impl for opening archives --- TESTS_ENVIRONMENT.in | 6 + release/Makefile | 1 + release/vagrant-static/build.sh | 9 +- release/vagrant-static/provision.sh | 5 + src/CMakeLists.txt | 2 + src/Makefile.am | 5 + src/archive_manager.cc | 218 ++++++++++++++++++++++++++++ src/archive_manager.hh | 51 +++++++ src/base/intern_string.hh | 27 +++- src/lnav.cc | 55 +++++-- src/lnav_util.cc | 17 ++- src/lnav_util.hh | 3 +- src/unique_path.hh | 14 +- src/yajlpp/Makefile.am | 6 + test/Makefile.am | 6 + test/lnav_doctests.cc | 2 +- test/test_logfile.sh | 24 +++ 17 files changed, 414 insertions(+), 37 deletions(-) create mode 100644 src/archive_manager.cc create mode 100644 src/archive_manager.hh diff --git a/TESTS_ENVIRONMENT.in b/TESTS_ENVIRONMENT.in index b7385430..1e41d7f5 100644 --- a/TESTS_ENVIRONMENT.in +++ b/TESTS_ENVIRONMENT.in @@ -10,6 +10,9 @@ export srcdir top_builddir=`dirname $0` export top_builddir +builddir=`pwd` +export builddir + test_dir="@abssrcdir@/test" export test_dir @@ -20,6 +23,9 @@ export BZIP2_SUPPORT BZIP2_CMD="@BZIP2_CMD@" export BZIP2_CMD +LIBARCHIVE_LIBS="@LIBARCHIVE_LIBS@" +export LIBARCHIVE_LIBS + HOME="${top_builddir}/test" export HOME diff --git a/release/Makefile b/release/Makefile index f79ab35c..3879e62c 100644 --- a/release/Makefile +++ b/release/Makefile @@ -10,6 +10,7 @@ clean-outbox: outbox rm -f outbox/* PACKAGE_URLS = \ + https://libarchive.org/downloads/libarchive-3.4.3.tar.gz \ https://ftp.gnu.org/gnu/make/make-4.2.1.tar.gz \ ftp://ftp.gnu.org/gnu/ncurses/ncurses-5.9.tar.gz \ https://ftp.pcre.org/pub/pcre/pcre-8.42.tar.gz \ diff --git a/release/vagrant-static/build.sh b/release/vagrant-static/build.sh index 1674a753..b40a144f 100755 --- a/release/vagrant-static/build.sh +++ b/release/vagrant-static/build.sh @@ -45,23 +45,24 @@ if test x"${OS}" != x"FreeBSD"; then if test x"$(lsb_release | awk '{print $3}')" == x"Alpine"; then TARGET_FILE='/vagrant/lnav-musl.zip' ../lnav/configure \ - CFLAGS='-static -no-pie -s' \ - CXXFLAGS='-static -U__unused -no-pie -s' \ + CFLAGS='-static -no-pie -s -O2' \ + CXXFLAGS='-static -U__unused -no-pie -s -O2' \ LDFLAGS="-L${FAKE_ROOT}/lib" \ CPPFLAGS="-I${FAKE_ROOT}/include" \ --enable-static PATH="${FAKE_ROOT}/bin:${PATH}" else ../lnav/configure \ + --with-libarchive=${FAKE_ROOT} \ LDFLAGS="-L${FAKE_ROOT}/lib" \ - CPPFLAGS="-I${FAKE_ROOT}/include" \ + CPPFLAGS="-I${FAKE_ROOT}/include -O2" \ PATH="${FAKE_ROOT}/bin:${PATH}" fi else ../lnav/configure \ LDFLAGS="-L${FAKE_ROOT}/lib -static" \ LIBS="-lm -lelf" \ - CPPFLAGS="-I${FAKE_ROOT}/include" \ + CPPFLAGS="-I${FAKE_ROOT}/include -O2" \ PATH="${FAKE_ROOT}/bin:${PATH}" fi diff --git a/release/vagrant-static/provision.sh b/release/vagrant-static/provision.sh index 7e1f99da..14066477 100755 --- a/release/vagrant-static/provision.sh +++ b/release/vagrant-static/provision.sh @@ -136,3 +136,8 @@ else make && make install) fi + +(cd libarchive-* && + ./configure --prefix=${FAKE_ROOT} && + make && + make install) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 785b5d02..a5bb8c7f 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -229,6 +229,7 @@ add_library(diag STATIC config.h ansi_scrubber.cc + archive_manager.cc bin2c.h bookmarks.cc bottom_status_source.cc @@ -332,6 +333,7 @@ add_library(diag STATIC spookyhash/SpookyV2.cpp all_logs_vtab.hh + archive_manager.hh attr_line.hh auto_fd.hh auto_mem.hh diff --git a/src/Makefile.am b/src/Makefile.am index 3a0d4cd1..b2337395 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -204,6 +204,7 @@ LNAV_BUILT_FILES = \ AM_LDFLAGS = \ $(STATIC_LDFLAGS) \ + $(LIBARCHIVE_LDFLAGS) \ $(READLINE_LDFLAGS) \ $(SQLITE3_LDFLAGS) \ $(PCRE_LDFLAGS) @@ -212,6 +213,7 @@ AM_CPPFLAGS = \ -DSYSCONFDIR='"$(sysconfdir)"' \ -I$(srcdir)/fmtlib \ -Wall \ + $(LIBARCHIVE_CFLAGS) \ $(READLINE_CFLAGS) \ $(SQLITE3_CFLAGS) \ $(LIBCURL_CPPFLAGS) @@ -226,6 +228,7 @@ LDADD = \ $(READLINE_LIBS) \ $(CURSES_LIB) \ $(SQLITE3_LIBS) \ + $(LIBARCHIVE_LIBS) \ $(LIBCURL) \ -lpcrecpp @@ -243,6 +246,7 @@ dist_noinst_DATA = \ noinst_HEADERS = \ all_logs_vtab.hh \ ansi_scrubber.hh \ + archive_manager.hh \ attr_line.hh \ auto_fd.hh \ auto_mem.hh \ @@ -373,6 +377,7 @@ nodist_libdiag_a_SOURCES = \ libdiag_a_SOURCES = \ ansi_scrubber.cc \ + archive_manager.cc \ bookmarks.cc \ bottom_status_source.cc \ collation-functions.cc \ diff --git a/src/archive_manager.cc b/src/archive_manager.cc new file mode 100644 index 00000000..7db04808 --- /dev/null +++ b/src/archive_manager.cc @@ -0,0 +1,218 @@ +/** + * Copyright (c) 2020, Timothy Stack + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of Timothy Stack nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ''AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * @file archive_manager.cc + */ + +#include "config.h" + +#include +#include + +#if HAVE_ARCHIVE_H +#include "archive.h" +#include "archive_entry.h" +#endif + +#include "auto_mem.hh" +#include "fmt/format.h" +#include "base/lnav_log.hh" + +#include "archive_manager.hh" + +namespace fs = ghc::filesystem; + +namespace archive_manager { + +bool is_archive(const std::string &filename) +{ +#if HAVE_ARCHIVE_H + auto_mem arc(archive_read_free); + + arc = archive_read_new(); + + archive_read_support_filter_all(arc); + archive_read_support_format_all(arc); + auto r = archive_read_open_filename(arc, filename.c_str(), 16384); + if (r == ARCHIVE_OK) { + struct archive_entry *entry; + + if (archive_read_next_header(arc, &entry) == ARCHIVE_OK) { + log_info("detected archive: %s -- %s", + filename.c_str(), + archive_format_name(arc)); + return true; + } else { + log_info("archive read header failed: %s -- %s", + filename.c_str(), + archive_error_string(arc)); + } + } else { + log_info("archive open failed: %s -- %s", + filename.c_str(), + archive_error_string(arc)); + } +#endif + + return false; +} + +fs::path +filename_to_tmp_path(const std::string &filename) +{ + auto fn_path = fs::path(filename); + auto basename = fn_path.filename(); + auto subdir_name = fmt::format("lnav-{}-archives", getuid()); + auto tmp_path = fs::temp_directory_path(); + + // TODO include a content-hash in the path name + return tmp_path / fs::path(subdir_name) / basename; +} + +void walk_archive_files(const std::string &filename, + const std::function& callback) +{ + auto tmp_path = filename_to_tmp_path(filename); + + // TODO take care of locking + if (!fs::exists(tmp_path)) { + extract(filename); + } + + for (const auto& entry : fs::recursive_directory_iterator(tmp_path)) { + if (!entry.is_regular_file()) { + continue; + } + + callback(entry); + } +} + +#if HAVE_ARCHIVE_H +static int +copy_data(struct archive *ar, struct archive *aw) +{ + int r; + const void *buff; + size_t size; + la_int64_t offset; + + for (;;) { + r = archive_read_data_block(ar, &buff, &size, &offset); + if (r == ARCHIVE_EOF) { + return (ARCHIVE_OK); + } + if (r < ARCHIVE_OK) { + return (r); + } + r = archive_write_data_block(aw, buff, size, offset); + if (r < ARCHIVE_OK) { + log_error("%s", archive_error_string(aw)); + return (r); + } + } +} + +void extract(const std::string &filename) +{ + static int FLAGS = ARCHIVE_EXTRACT_TIME + | ARCHIVE_EXTRACT_PERM + | ARCHIVE_EXTRACT_ACL + | ARCHIVE_EXTRACT_FFLAGS; + + auto_mem arc(archive_free); + auto_mem ext(archive_free); + + arc = archive_read_new(); + archive_read_support_format_all(arc); + archive_read_support_filter_all(arc); + ext = archive_write_disk_new(); + archive_write_disk_set_options(ext, FLAGS); + archive_write_disk_set_standard_lookup(ext); + if (archive_read_open_filename(arc, filename.c_str(), 10240) != ARCHIVE_OK) { + return; + } + + auto tmp_path = filename_to_tmp_path(filename); + log_info("extracting %s to %s", filename.c_str(), tmp_path.c_str()); + while (true) { + struct archive_entry *entry; + auto r = archive_read_next_header(arc, &entry); + if (r == ARCHIVE_EOF) { + break; + } + if (r < ARCHIVE_OK) { + log_error("%s", archive_error_string(arc)); + } + if (r < ARCHIVE_WARN) { + return; + } + + auto_mem wentry(archive_entry_free); + wentry = archive_entry_clone(entry); + auto entry_path = tmp_path / fs::path(archive_entry_pathname(entry)); + archive_entry_copy_pathname(wentry, entry_path.c_str()); + auto entry_mode = archive_entry_mode(wentry); + + archive_entry_set_perm( + wentry, S_IRUSR | (S_ISDIR(entry_mode) ? S_IXUSR|S_IWUSR : 0)); + r = archive_write_header(ext, wentry); + if (r < ARCHIVE_OK) { + log_error("%s", archive_error_string(ext)); + } + else if (archive_entry_size(entry) > 0) { + r = copy_data(arc, ext); + if (r < ARCHIVE_OK) { + log_error("%s", archive_error_string(ext)); + } + if (r < ARCHIVE_WARN) { + return; + } + } + r = archive_write_finish_entry(ext); + if (r < ARCHIVE_OK) { + log_error("%s", archive_error_string(ext)); + } + if (r < ARCHIVE_WARN) { + return; + } + } + archive_read_close(arc); + archive_write_close(ext); + + // TODO return errors +} +#else +void extract(const std::string &filename) +{ + +} +#endif + +} diff --git a/src/archive_manager.hh b/src/archive_manager.hh new file mode 100644 index 00000000..9cad0826 --- /dev/null +++ b/src/archive_manager.hh @@ -0,0 +1,51 @@ +/** + * Copyright (c) 2020, Timothy Stack + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of Timothy Stack nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ''AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * @file archive_manager.hh + */ + +#ifndef lnav_archive_manager_hh +#define lnav_archive_manager_hh + +#include +#include + +#include "ghc/filesystem.hpp" + +namespace archive_manager { +bool is_archive(const std::string &filename); + +ghc::filesystem::path filename_to_tmp_path(const std::string &filename); + +void walk_archive_files(const std::string &filename, + const std::function&); + +void extract(const std::string &filename); +} + +#endif diff --git a/src/base/intern_string.hh b/src/base/intern_string.hh index d370111a..c193755e 100644 --- a/src/base/intern_string.hh +++ b/src/base/intern_string.hh @@ -40,6 +40,8 @@ #include "strnatcmp.h" struct string_fragment { + using iterator = const char *; + explicit string_fragment(const char *str, int begin = 0, int end = -1) : sf_string(str), sf_begin(begin), sf_end(end == -1 ? strlen(str) : end) { }; @@ -67,6 +69,14 @@ struct string_fragment { return &this->sf_string[this->sf_begin]; } + iterator begin() const { + return &this->sf_string[this->sf_begin]; + } + + iterator end() const { + return &this->sf_string[this->sf_end]; + } + bool empty() const { return length() == 0; }; @@ -109,7 +119,18 @@ struct string_fragment { strncmp(this->data(), str, this->length()) == 0; }; - const char *to_string(char *buf) { + bool startswith(const char *prefix) const { + auto iter = this->begin(); + + while (*prefix != '\0' && *prefix == *iter && iter < this->end()) { + prefix += 1; + iter += 1; + } + + return *prefix == '\0'; + } + + const char *to_string(char *buf) const { memcpy(buf, this->data(), this->length()); buf[this->length()] = '\0'; @@ -120,10 +141,6 @@ struct string_fragment { return std::string(this->data(), this->length()); } - std::string to_string() { - return std::string(&this->sf_string[this->sf_begin], this->length()); - }; - void clear() { this->sf_begin = 0; this->sf_end = 0; diff --git a/src/lnav.cc b/src/lnav.cc index 19d99eac..6256a92f 100644 --- a/src/lnav.cc +++ b/src/lnav.cc @@ -132,6 +132,10 @@ #include #endif +#if HAVE_ARCHIVE_H +#include +#endif + #include "yajlpp/yajlpp.hh" #include "readline_callbacks.hh" #include "command_executor.hh" @@ -143,6 +147,7 @@ #include "log_search_table.hh" #include "shlex.hh" #include "log_actions.hh" +#include "archive_manager.hh" #ifndef SYSCONFDIR #define SYSCONFDIR "/usr/etc" @@ -967,26 +972,41 @@ static bool watch_logfile(string filename, logfile_open_options &loo, bool requi file_format_t ff = detect_file_format(filename); switch (ff) { - case FF_SQLITE_DB: - lnav_data.ld_other_files.push_back(filename); - attach_sqlite_db(lnav_data.ld_db.in(), filename); - retval = true; - break; + case file_format_t::FF_SQLITE_DB: + lnav_data.ld_other_files.push_back(filename); + attach_sqlite_db(lnav_data.ld_db.in(), filename); + retval = true; + break; - default: - /* It's a new file, load it in. */ - shared_ptr lf = make_shared(filename, loo); + case file_format_t::FF_ARCHIVE: { + archive_manager::walk_archive_files(filename, + [&filename](const auto& entry) { + logfile_open_options loo; - log_info("loading new file: filename=%s", - filename.c_str()); - lf->set_logfile_observer(&obs); - lnav_data.ld_files.push_back(lf); - lnav_data.ld_text_source.push_back(lf); + log_info("adding file from archive: %s/%s", + filename.c_str(), + entry.path().c_str()); + // TODO add some heuristics for hiding files + lnav_data.ld_file_names[entry.path().string()] = loo; + }); + lnav_data.ld_other_files.emplace_back(filename); + break; + } - regenerate_unique_file_names(); + default: + /* It's a new file, load it in. */ + shared_ptr lf = make_shared(filename, loo); - retval = true; - break; + log_info("loading new file: filename=%s", + filename.c_str()); + lf->set_logfile_observer(&obs); + lnav_data.ld_files.push_back(lf); + lnav_data.ld_text_source.push_back(lf); + + regenerate_unique_file_names(); + + retval = true; + break; } } } @@ -2536,6 +2556,9 @@ int main(int argc, char *argv[]) #endif #ifdef HAVE_LIBCURL log_info(" curl=%s (%s)", LIBCURL_VERSION, LIBCURL_TIMESTAMP); +#endif +#ifdef HAVE_ARCHIVE_H + log_info(" libarchive=%d", ARCHIVE_VERSION_NUMBER); #endif log_info(" ncurses=%s", NCURSES_VERSION); log_info(" pcre=%s", pcre_version()); diff --git a/src/lnav_util.cc b/src/lnav_util.cc index e789710e..93f57d00 100644 --- a/src/lnav_util.cc +++ b/src/lnav_util.cc @@ -48,6 +48,7 @@ #include "base/result.h" #include "ansi_scrubber.hh" #include "view_curses.hh" +#include "archive_manager.hh" using namespace std; @@ -304,17 +305,23 @@ std::pair split_path(const char *path, ssize_t len) file_format_t detect_file_format(const std::string &filename) { - file_format_t retval = FF_UNKNOWN; + if (archive_manager::is_archive(filename)) { + return file_format_t::FF_ARCHIVE; + } + + file_format_t retval = file_format_t::FF_UNKNOWN; auto_fd fd; if ((fd = open(filename.c_str(), O_RDONLY)) != -1) { char buffer[32]; - int rc; + ssize_t rc; if ((rc = read(fd, buffer, sizeof(buffer))) > 0) { - if (rc > 16 && - strncmp(buffer, "SQLite format 3", 16) == 0) { - retval = FF_SQLITE_DB; + static auto SQLITE3_HEADER = "SQLite format 3"; + auto header_frag = string_fragment(buffer, 0, rc); + + if (header_frag.startswith(SQLITE3_HEADER)) { + retval = file_format_t::FF_SQLITE_DB; } } } diff --git a/src/lnav_util.hh b/src/lnav_util.hh index 9d7ae9ac..dc9443d1 100644 --- a/src/lnav_util.hh +++ b/src/lnav_util.hh @@ -219,9 +219,10 @@ std::pair split_path(const std::string &path) { return split_path(path.c_str(), path.size()); }; -enum file_format_t { +enum class file_format_t { FF_UNKNOWN, FF_SQLITE_DB, + FF_ARCHIVE, }; file_format_t detect_file_format(const std::string &filename); diff --git a/src/unique_path.hh b/src/unique_path.hh index 75d3e788..2c0ccfae 100644 --- a/src/unique_path.hh +++ b/src/unique_path.hh @@ -71,7 +71,7 @@ public: }; - void add_source(std::shared_ptr path_source) { + void add_source(const std::shared_ptr& path_source) { ghc::filesystem::path path = path_source->get_path(); path_source->set_unique_path(path.filename()); @@ -107,6 +107,9 @@ public: if (common.empty()) { common = path.filename(); + if (common.empty()) { + all_common = false; + } } else if (common != path.filename()) { all_common = false; } @@ -115,8 +118,9 @@ public: if (all_common) { for (auto &src : pair.second) { auto &path = src->get_path_prefix(); + auto par = path.parent_path(); - if (path.empty()) { + if (path.empty() || path == par) { all_common = false; } else { src->set_path_prefix(path.parent_path()); @@ -147,11 +151,11 @@ public: src->set_path_prefix(parent); - if (!parent.empty()) { + if (parent.empty() || parent == prefix) { + src->set_unique_path("[" + src->get_unique_path()); + } else { this->upg_unique_paths[src->get_unique_path()].push_back( src); - } else { - src->set_unique_path("[" + src->get_unique_path()); } } diff --git a/src/yajlpp/Makefile.am b/src/yajlpp/Makefile.am index 13d0246d..ff7f2096 100644 --- a/src/yajlpp/Makefile.am +++ b/src/yajlpp/Makefile.am @@ -4,9 +4,14 @@ LOG_COMPILER = $(SHELL) $(top_builddir)/TESTS_ENVIRONMENT AM_CPPFLAGS = \ -Wall \ + $(LIBARCHIVE_CFLAGS) \ -I$(top_srcdir)/src/ \ -I$(top_srcdir)/src/fmtlib +AM_LDFLAGS = \ + $(LIBARCHIVE_LDFLAGS) \ + $(STATIC_LDFLAGS) + noinst_LIBRARIES = libyajlpp.a noinst_HEADERS = \ @@ -35,6 +40,7 @@ test_json_ptr_SOURCES = test_json_ptr.cc test_yajlpp_SOURCES = test_yajlpp.cc LDADD = \ + $(LIBARCHIVE_LIBS) \ libyajlpp.a \ $(top_builddir)/src/base/libbase.a \ $(top_builddir)/src/fmtlib/libcppfmt.a \ diff --git a/test/Makefile.am b/test/Makefile.am index d018afce..2d3a203a 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -10,6 +10,7 @@ AM_CPPFLAGS = \ -Wall \ -I$(top_srcdir)/src \ -I$(top_srcdir)/src/fmtlib \ + $(LIBARCHIVE_CFLAGS) \ $(READLINE_CFLAGS) \ $(SQLITE3_CFLAGS) @@ -48,6 +49,7 @@ check_PROGRAMS = \ test_top_status AM_LDFLAGS = \ + $(LIBARCHIVE_LDFLAGS) \ $(STATIC_LDFLAGS) \ $(SQLITE3_LDFLAGS) \ $(READLINE_LDFLAGS) \ @@ -76,6 +78,7 @@ LDADD = \ $(top_builddir)/src/yajlpp/libyajlpp.a \ $(top_builddir)/src/base/libbase.a \ $(CURSES_LIB) \ + $(LIBARCHIVE_LIBS) \ $(SQLITE3_LIBS) \ $(PCRE_LIBS) \ $(READLINE_LIBS) \ @@ -361,13 +364,16 @@ DISTCLEANFILES = \ logfile_syslog_test.0 \ logfile_syslog_fr_test.0 \ logfile_syslog_with_mixed_times_test.0 \ + test-logs.tgz \ test_pretty_in.* \ + tmp \ unreadable.log \ empty \ scripts-empty distclean-local: $(RM_V)rm -rf sessions + $(RM_V)rm -rf tmp $(RM_V)rm -rf meta-sessions $(RM_V)rm -rf test-config $(RM_V)rm -rf .lnav diff --git a/test/lnav_doctests.cc b/test/lnav_doctests.cc index 15783931..e7fd9f77 100644 --- a/test/lnav_doctests.cc +++ b/test/lnav_doctests.cc @@ -155,7 +155,7 @@ TEST_CASE("ptime_roundtrip") { class my_path_source : public unique_path_source { public: - explicit my_path_source(const ghc::filesystem::path &p) : mps_path(p) { + explicit my_path_source(ghc::filesystem::path p) : mps_path(std::move(p)) { } diff --git a/test/test_logfile.sh b/test/test_logfile.sh index 6ad0bf0e..704f3f8a 100644 --- a/test/test_logfile.sh +++ b/test/test_logfile.sh @@ -14,6 +14,30 @@ log_time EOF fi +if test x"${LIBARCHIVE_LIBS}" != x""; then + (cd ${srcdir} && tar cfz ${builddir}/test-logs.tgz logfile_access_log.* logfile_empty.0) + + mkdir -p tmp + run_test env TMPDIR=tmp ${lnav_test} -n test-logs.tgz + + check_output "archive not unpacked" <