reapack

Package manager for REAPER
Log | Files | Refs | Submodules | README | LICENSE

commit 53efc0fd91ac7f277c61e24fb7de7cfa5a83af69
parent dc88a6998363dffce5c11f92bc80d3485fd06234
Author: cfillion <cfillion@users.noreply.github.com>
Date:   Mon, 27 Feb 2017 15:12:39 -0500

archive: compress files in worker thread when exporting

Diffstat:
Msrc/archive.cpp | 116+++++++++++++++++++++++++++++++++++++++++++++++++++----------------------------
Msrc/archive.hpp | 19+++++++++++++++++--
Msrc/manager.cpp | 32++++++++++++++++++++++++++------
3 files changed, 118 insertions(+), 49 deletions(-)

diff --git a/src/archive.cpp b/src/archive.cpp @@ -157,47 +157,6 @@ void ImportArchive::importPackage(const string &data) m_tx->install(ver, pinned, m_reader); } -size_t Archive::create(const auto_string &path, ReaPack *reapack) -{ - size_t count = 0; - - stringstream toc; - Registry reg(Path::prefixRoot(Path::REGISTRY)); - - ArchiveWriter writer(path); - - for(const Remote &remote : reapack->config()->remotes.getEnabled()) { - bool addedRemote = false; - - for(const Registry::Entry &entry : reg.getEntries(remote.name())) { - ++count; - - if(!addedRemote) { - toc << "REPO " << remote.toString() << '\n'; - if(writer.addFile(Index::pathFor(remote.name()))) - continue; // TODO: report error - addedRemote = true; - } - - toc << "PACK " - << quoted(entry.category) << '\x20' - << quoted(entry.package) << '\x20' - << quoted(entry.version.toString()) << '\x20' - << entry.pinned << '\n' - ; - - for(const Registry::File &file : reg.getFiles(entry)) { - if(writer.addFile(file.path)) - break; // TODO: report error - } - } - } - - writer.addFile(ARCHIVE_TOC, toc); - - return count; -} - ArchiveReader::ArchiveReader(const auto_string &path) { zlib_filefunc64_def filefunc; @@ -285,6 +244,49 @@ void FileExtractor::run(DownloadContext *) finish(Success); } +size_t Archive::create(const auto_string &path, ThreadPool *pool, ReaPack *reapack) +{ + size_t count = 0; + vector<ThreadTask *> jobs; + + stringstream toc; + Registry reg(Path::prefixRoot(Path::REGISTRY)); + + ArchiveWriterPtr writer = make_shared<ArchiveWriter>(path); + + for(const Remote &remote : reapack->config()->remotes.getEnabled()) { + bool addedRemote = false; + + for(const Registry::Entry &entry : reg.getEntries(remote.name())) { + ++count; + + if(!addedRemote) { + toc << "REPO " << remote.toString() << '\n'; + jobs.push_back(new FileCompressor(Index::pathFor(remote.name()), writer)); + addedRemote = true; + } + + toc << "PACK " + << quoted(entry.category) << '\x20' + << quoted(entry.package) << '\x20' + << quoted(entry.version.toString()) << '\x20' + << entry.pinned << '\n' + ; + + for(const Registry::File &file : reg.getFiles(entry)) + jobs.push_back(new FileCompressor(file.path, writer)); + } + } + + writer->addFile(ARCHIVE_TOC, toc); + + // start after we've written the table of contents in the main thread + for(ThreadTask *job : jobs) + pool->push(job); + + return count; +} + ArchiveWriter::ArchiveWriter(const auto_string &path) { zlib_filefunc64_def filefunc; @@ -339,3 +341,35 @@ int ArchiveWriter::addFile(const Path &path, istream &stream) noexcept return zipCloseFileInZip(m_zip); } + +FileCompressor::FileCompressor(const Path &target, const ArchiveWriterPtr &writer) + : m_path(target), m_writer(writer) +{ + setSummary("Compressing %s: " + target.join()); +} + +void FileCompressor::run(DownloadContext *) +{ + if(aborted()) { + finish(Aborted, {"cancelled", m_path.join()}); + return; + } + + ThreadNotifier::get()->notify({this, Running}); + + ifstream stream; + if(!FS::open(stream, m_path)) { + finish(Failure, {FS::lastError(), m_path.join()}); + return; + } + + const int error = m_writer->addFile(m_path, stream); + stream.close(); + + if(error) { + const format &msg = format("Failed to compress file (%d)") % error; + finish(Failure, {msg.str(), m_path.join()}); + } + else + finish(Success); +} diff --git a/src/archive.hpp b/src/archive.hpp @@ -23,12 +23,13 @@ #include "thread.hpp" class ReaPack; +class ThreadPool; typedef void *zipFile; namespace Archive { void import(const auto_string &path, ReaPack *); - size_t create(const auto_string &path, ReaPack *); + size_t create(const auto_string &path, ThreadPool *pool, ReaPack *); }; class ArchiveReader { @@ -42,6 +43,8 @@ private: zipFile m_zip; }; +typedef std::shared_ptr<ArchiveReader> ArchiveReaderPtr; + class ArchiveWriter { public: ArchiveWriter(const auto_string &path); @@ -53,7 +56,7 @@ private: zipFile m_zip; }; -typedef std::shared_ptr<ArchiveReader> ArchiveReaderPtr; +typedef std::shared_ptr<ArchiveWriter> ArchiveWriterPtr; class FileExtractor : public ThreadTask { public: @@ -68,4 +71,16 @@ private: ArchiveReaderPtr m_reader; }; +class FileCompressor : public ThreadTask { +public: + FileCompressor(const Path &target, const ArchiveWriterPtr &); + + bool concurrent() const override { return false; } + void run(DownloadContext *) override; + +private: + Path m_path; + ArchiveWriterPtr m_writer; +}; + #endif diff --git a/src/manager.cpp b/src/manager.cpp @@ -25,6 +25,7 @@ #include "filedialog.hpp" #include "import.hpp" #include "menu.hpp" +#include "progress.hpp" #include "reapack.hpp" #include "remote.hpp" #include "resource.hpp" @@ -524,24 +525,43 @@ void Manager::exportArchive() if(path.empty()) return; - auto_char msg[512]; + ThreadPool *pool = new ThreadPool; + Dialog *progress = Dialog::Create<Progress>(instance(), parent(), pool); try { - const size_t count = Archive::create(path, m_reapack); + const size_t count = Archive::create(path, pool, m_reapack); - auto_snprintf(msg, auto_size(msg), - AUTO_STR("Done! %zu packages were exported in the archive."), count); + const auto finish = [=] { + Dialog::Destroy(progress); + + auto_char msg[255]; + auto_snprintf(msg, auto_size(msg), + AUTO_STR("Done! %zu package%s were exported in the archive."), + count, count == 1 ? AUTO_STR("") : AUTO_STR("s")); + MessageBox(handle(), msg, title, MB_OK); + + delete pool; + }; + + pool->onDone(finish); + + if(pool->idle()) + finish(); } catch(const reapack_error &e) { + Dialog::Destroy(progress); + delete pool; + const auto_string &desc = make_autostring(e.what()); + auto_char msg[512]; auto_snprintf(msg, auto_size(msg), - AUTO_STR("ReaPack could not write into %s (%s)."), + AUTO_STR("An error occured while writing into %s.\r\n\r\n%s."), path.c_str(), desc.c_str() ); + MessageBox(handle(), msg, title, MB_OK); } - MessageBox(handle(), msg, title, MB_OK); } void Manager::launchBrowser()