reapack

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

archive_tasks.cpp (2999B)


      1 /* ReaPack: Package manager for REAPER
      2  * Copyright (C) 2015-2025  Christian Fillion
      3  *
      4  * This program is free software: you can redistribute it and/or modify
      5  * it under the terms of the GNU Lesser General Public License as published by
      6  * the Free Software Foundation, either version 3 of the License, or
      7  * (at your option) any later version.
      8  *
      9  * This program is distributed in the hope that it will be useful,
     10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     12  * GNU Lesser General Public License for more details.
     13  *
     14  * You should have received a copy of the GNU Lesser General Public License
     15  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
     16  */
     17 
     18 #include "task.hpp"
     19 
     20 #include "archive.hpp"
     21 #include "config.hpp"
     22 #include "filesystem.hpp"
     23 #include "index.hpp"
     24 #include "reapack.hpp"
     25 #include "remote.hpp"
     26 #include "string.hpp"
     27 #include "transaction.hpp"
     28 
     29 #include <iomanip>
     30 #include <sstream>
     31 
     32 static const Path ARCHIVE_TOC("toc");
     33 
     34 ExportTask::ExportTask(const std::string &path, Transaction *tx)
     35   : Task(tx), m_path(path)
     36 {
     37 }
     38 
     39 bool ExportTask::start()
     40 {
     41   std::stringstream toc;
     42   ArchiveWriterPtr writer;
     43 
     44   try {
     45     writer = std::make_shared<ArchiveWriter>(m_path.temp());
     46   }
     47   catch(const reapack_error &e) {
     48     tx()->receipt()->addError({
     49       String::format("Could not open archive for writing: %s", e.what()),
     50       m_path.temp().join()
     51     });
     52     return false;
     53   }
     54 
     55   std::vector<FileCompressor *> jobs;
     56 
     57   for(const Remote &remote : g_reapack->config()->remotes.getEnabled()) {
     58     bool addedRemote = false;
     59 
     60     for(const Registry::Entry &entry : tx()->registry()->getEntries(remote.name())) {
     61       if(!addedRemote) {
     62         toc << "REPO " << remote.toString() << '\n';
     63         jobs.push_back(new FileCompressor(Index::pathFor(remote.name()), writer));
     64         addedRemote = true;
     65       }
     66 
     67       toc << "PACK "
     68         << quoted(entry.category) << '\x20'
     69         << quoted(entry.package) << '\x20'
     70         << quoted(entry.version.toString()) << '\x20'
     71         << entry.flags << '\n'
     72       ;
     73 
     74       for(const Registry::File &file : tx()->registry()->getFiles(entry))
     75         jobs.push_back(new FileCompressor(file.path, writer));
     76     }
     77   }
     78 
     79   writer->addFile(ARCHIVE_TOC, toc);
     80 
     81   // Start after we've written the table of contents in the main thread
     82   // because we cannot safely write into the zip from more than one
     83   // thread at the same time.
     84   for(FileCompressor *job : jobs) {
     85     job->onFinishAsync >> [=] {
     86       if(job->state() == ThreadTask::Success)
     87         tx()->receipt()->addExport(job->path());
     88     };
     89 
     90     tx()->threadPool()->push(job);
     91   }
     92 
     93   return true;
     94 }
     95 
     96 void ExportTask::commit()
     97 {
     98   if(!FS::rename(m_path)) {
     99     tx()->receipt()->addError({
    100       String::format("Could not move to permanent location: %s", FS::lastError()),
    101       m_path.target().prependRoot().join()
    102     });
    103   }
    104 }
    105 
    106 void ExportTask::rollback()
    107 {
    108   FS::remove(m_path.temp());
    109 }