*: Implement detailed progress reporting when creating
Ditto!
This commit is contained in:
parent
e82d693dfc
commit
cf9d84cb24
|
@ -0,0 +1,51 @@
|
||||||
|
//
|
||||||
|
// EuropaTools
|
||||||
|
//
|
||||||
|
// (C) 2021-2022 modeco80 <lily.modeco80@protonmail.ch>
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef EUROPA_IO_PAKPROGRESSREPORTSINK_H
|
||||||
|
#define EUROPA_IO_PAKPROGRESSREPORTSINK_H
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace europa::io {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface for the writer to output detailed progress information.
|
||||||
|
*/
|
||||||
|
struct PakProgressReportSink {
|
||||||
|
|
||||||
|
struct PakEvent {
|
||||||
|
enum class Type {
|
||||||
|
FillInHeader, ///< Filling in header
|
||||||
|
WritingHeader, ///< Writing header
|
||||||
|
|
||||||
|
WritingToc ///< Writing archive TOC
|
||||||
|
};
|
||||||
|
|
||||||
|
Type type;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct FileEvent {
|
||||||
|
enum class Type {
|
||||||
|
FileBeginWrite, ///< File has began write to package
|
||||||
|
FileEndWrite, ///< File writing finished
|
||||||
|
};
|
||||||
|
|
||||||
|
Type type;
|
||||||
|
std::string filename;
|
||||||
|
};
|
||||||
|
|
||||||
|
virtual ~PakProgressReportSink() = default;
|
||||||
|
|
||||||
|
virtual void OnEvent(const PakEvent& event) = 0;
|
||||||
|
virtual void OnEvent(const FileEvent& event) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace europa::io
|
||||||
|
|
||||||
|
#endif // EUROPA_IO_PAKPROGRESSREPORTSINK_H
|
|
@ -10,6 +10,7 @@
|
||||||
#define EUROPA_IO_PAKWRITER_H
|
#define EUROPA_IO_PAKWRITER_H
|
||||||
|
|
||||||
#include <europa/io/PakFile.hpp>
|
#include <europa/io/PakFile.hpp>
|
||||||
|
#include <europa/io/PakProgressReportSink.hpp>
|
||||||
#include <iosfwd>
|
#include <iosfwd>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
@ -30,7 +31,7 @@ namespace europa::io {
|
||||||
/**
|
/**
|
||||||
* Write the resulting archive to the given output stream.
|
* Write the resulting archive to the given output stream.
|
||||||
*/
|
*/
|
||||||
void Write(std::ostream& os);
|
void Write(std::ostream& os, PakProgressReportSink& sink);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
structs::PakHeader pakHeader {};
|
structs::PakHeader pakHeader {};
|
||||||
|
|
|
@ -65,7 +65,7 @@ namespace europa::io {
|
||||||
// - Composable operations (WriteTOC, WriteFile, WriteHeader)
|
// - Composable operations (WriteTOC, WriteFile, WriteHeader)
|
||||||
// - Add IProgressReportSink reporting
|
// - Add IProgressReportSink reporting
|
||||||
|
|
||||||
void PakWriter::Write(std::ostream& os) {
|
void PakWriter::Write(std::ostream& os, PakProgressReportSink& sink) {
|
||||||
|
|
||||||
// This essentially converts our map we use for faster insertion
|
// This essentially converts our map we use for faster insertion
|
||||||
// into a flat array we can sort easily.
|
// into a flat array we can sort easily.
|
||||||
|
@ -93,15 +93,32 @@ namespace europa::io {
|
||||||
for(auto& [filename, file] : sortedFiles) {
|
for(auto& [filename, file] : sortedFiles) {
|
||||||
//std::cout << "PakWriteFile \"" << filename << "\"\n Size " << file.GetTOCEntry().size << "\n";
|
//std::cout << "PakWriteFile \"" << filename << "\"\n Size " << file.GetTOCEntry().size << "\n";
|
||||||
|
|
||||||
|
|
||||||
|
sink.OnEvent({
|
||||||
|
PakProgressReportSink::FileEvent::Type::FileBeginWrite,
|
||||||
|
filename
|
||||||
|
});
|
||||||
|
|
||||||
file.GetTOCEntry().offset = os.tellp();
|
file.GetTOCEntry().offset = os.tellp();
|
||||||
os.write(reinterpret_cast<const char*>(file.GetData().data()), file.GetData().size());
|
os.write(reinterpret_cast<const char*>(file.GetData().data()), file.GetData().size());
|
||||||
|
|
||||||
// Flush on file writing
|
// Flush on file writing
|
||||||
os.flush();
|
os.flush();
|
||||||
|
|
||||||
|
|
||||||
|
sink.OnEvent({
|
||||||
|
PakProgressReportSink::FileEvent::Type::FileEndWrite,
|
||||||
|
filename
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
pakHeader.tocOffset = os.tellp();
|
pakHeader.tocOffset = os.tellp();
|
||||||
|
|
||||||
|
|
||||||
|
sink.OnEvent({
|
||||||
|
PakProgressReportSink::PakEvent::Type::WritingToc
|
||||||
|
});
|
||||||
|
|
||||||
// Write the TOC
|
// Write the TOC
|
||||||
for(auto& [filename, file] : sortedFiles) {
|
for(auto& [filename, file] : sortedFiles) {
|
||||||
file.FillTOCEntry();
|
file.FillTOCEntry();
|
||||||
|
@ -115,10 +132,21 @@ namespace europa::io {
|
||||||
impl::WriteStreamType(os, file.GetTOCEntry());
|
impl::WriteStreamType(os, file.GetTOCEntry());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
sink.OnEvent({
|
||||||
|
PakProgressReportSink::PakEvent::Type::FillInHeader
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
// Fill out the rest of the header.
|
// Fill out the rest of the header.
|
||||||
pakHeader.fileCount = archiveFiles.size();
|
pakHeader.fileCount = archiveFiles.size();
|
||||||
pakHeader.tocSize = static_cast<std::uint32_t>(os.tellp()) - (pakHeader.tocOffset - 1);
|
pakHeader.tocSize = static_cast<std::uint32_t>(os.tellp()) - (pakHeader.tocOffset - 1);
|
||||||
|
|
||||||
|
|
||||||
|
sink.OnEvent({
|
||||||
|
PakProgressReportSink::PakEvent::Type::WritingHeader
|
||||||
|
});
|
||||||
|
|
||||||
// As the last step, write it.
|
// As the last step, write it.
|
||||||
os.seekp(0, std::ostream::beg);
|
os.seekp(0, std::ostream::beg);
|
||||||
impl::WriteStreamType(os, pakHeader);
|
impl::WriteStreamType(os, pakHeader);
|
||||||
|
|
|
@ -34,7 +34,7 @@ namespace eupak {
|
||||||
|
|
||||||
div *= unit;
|
div *= unit;
|
||||||
|
|
||||||
exp++; // TODO: break if too big
|
exp++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,65 @@
|
||||||
|
|
||||||
namespace eupak::tasks {
|
namespace eupak::tasks {
|
||||||
|
|
||||||
|
struct CreateArchiveReportSink : public europa::io::PakProgressReportSink {
|
||||||
|
|
||||||
|
CreateArchiveReportSink(int fileCount = 0)
|
||||||
|
: europa::io::PakProgressReportSink() {
|
||||||
|
indicators::show_console_cursor(false);
|
||||||
|
progress.set_option(indicators::option::MaxProgress { fileCount });
|
||||||
|
}
|
||||||
|
|
||||||
|
~CreateArchiveReportSink() {
|
||||||
|
indicators::show_console_cursor(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OnEvent(const PakEvent& event) override {
|
||||||
|
using enum PakEvent::Type;
|
||||||
|
switch(event.type) {
|
||||||
|
case WritingHeader:
|
||||||
|
progress.set_option(indicators::option::PostfixText {"Writing header"});
|
||||||
|
progress.print_progress();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FillInHeader:
|
||||||
|
progress.set_option(indicators::option::PostfixText {"Filling in header"});
|
||||||
|
progress.print_progress();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case WritingToc:
|
||||||
|
progress.set_option(indicators::option::PostfixText {"Writing TOC"});
|
||||||
|
progress.print_progress();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void OnEvent(const FileEvent& event) override {
|
||||||
|
using enum FileEvent::Type;
|
||||||
|
switch(event.type) {
|
||||||
|
case FileBeginWrite:
|
||||||
|
progress.set_option(indicators::option::PostfixText {"Writing " + event.filename});
|
||||||
|
progress.print_progress();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FileEndWrite:
|
||||||
|
progress.set_option(indicators::option::PostfixText {"Written " + event.filename});
|
||||||
|
progress.tick();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
indicators::ProgressBar progress {
|
||||||
|
indicators::option::BarWidth { 50 },
|
||||||
|
indicators::option::ForegroundColor { indicators::Color::yellow },
|
||||||
|
indicators::option::ShowPercentage { true },
|
||||||
|
indicators::option::ShowElapsedTime { true },
|
||||||
|
indicators::option::ShowRemainingTime { true },
|
||||||
|
|
||||||
|
indicators::option::PrefixText { "Writing archive " }
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
int CreateTask::Run(Arguments&& args) {
|
int CreateTask::Run(Arguments&& args) {
|
||||||
europa::io::PakWriter writer;
|
europa::io::PakWriter writer;
|
||||||
|
|
||||||
|
@ -41,7 +100,7 @@ namespace eupak::tasks {
|
||||||
indicators::option::ShowElapsedTime { true },
|
indicators::option::ShowElapsedTime { true },
|
||||||
indicators::option::ShowRemainingTime { true },
|
indicators::option::ShowRemainingTime { true },
|
||||||
|
|
||||||
indicators::option::PrefixText { "Creating archive " }
|
indicators::option::PrefixText { "Adding files to archive " }
|
||||||
};
|
};
|
||||||
|
|
||||||
indicators::show_console_cursor(false);
|
indicators::show_console_cursor(false);
|
||||||
|
@ -91,6 +150,8 @@ namespace eupak::tasks {
|
||||||
currFile++;
|
currFile++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
indicators::show_console_cursor(true);
|
||||||
|
|
||||||
std::ofstream ofs(args.outputFile.string(), std::ofstream::binary);
|
std::ofstream ofs(args.outputFile.string(), std::ofstream::binary);
|
||||||
|
|
||||||
if(!ofs) {
|
if(!ofs) {
|
||||||
|
@ -98,8 +159,10 @@ namespace eupak::tasks {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
writer.Write(ofs);
|
|
||||||
indicators::show_console_cursor(true);
|
CreateArchiveReportSink sink(fileCount);
|
||||||
|
|
||||||
|
writer.Write(ofs, sink);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue