#include #include #include #include #include #include #include "indicators/terminal_size.hpp" #include "threadpool.hpp" #include "tree.hpp" #include "vxheaven_parse.hpp" namespace ind = indicators; int main(int argc, char** argv) { if(argc != 4) { std::fprintf(stderr, "usage: %s [path to list] [source path] [destination path]\n", argv[0]); return 1; } vxorg::VxHeavenTree sample_tree; // used for os filesystem ops ThreadPool filesystem_threadpool(4); // Parse into the sample tree std::ifstream ifs(argv[1]); if(!ifs) { char err[256]{}; strerror_r(errno, &err[0], sizeof(err)-1); std::fprintf(stderr, "Could not open sample list \"%s\": %s", argv[1], err); return 1; } vxorg::parse_into_tree(sample_tree, ifs); std::filesystem::path unorganized_source_path = argv[2]; std::filesystem::path organized_destination_path = argv[3]; if(!std::filesystem::exists(unorganized_source_path)) { std::fprintf(stderr, "Source path \"%s\" does not exist", argv[2]); return 1; } if(!std::filesystem::exists(organized_destination_path)) std::filesystem::create_directories(organized_destination_path); std::size_t sampleCount = 0; // Walk the tree to get the amount of sample nodes sample_tree.walk([&](auto* node) { if(node->data().is_sample) sampleCount++; }); ind::ProgressBar bar { ind::option::BarWidth { indicators::terminal_width() - 64 }, ind::option::Start { "[" }, ind::option::Fill { "■" }, ind::option::Lead { "■" }, ind::option::Remainder { "-" }, ind::option::End { " ]" }, ind::option::ForegroundColor { ind::Color::red }, ind::option::FontStyles { std::vector { ind::FontStyle::bold } }, ind::option::MaxProgress { sampleCount } }; // Walk the tree to perform the operation sample_tree.walk([&](auto* node) { auto& data = node->data(); #if 0 auto tabulation_level = node->parent_count(); if(tabulation_level != 0) { for(auto i = 0; i < tabulation_level; ++i) { std::printf("\t"); } } if(node->is_root()) { std::printf("(root)\n"); } else { if(data.is_sample) { std::string sample_name = vxorg::get_sample_name(node); std::printf("%s (sample %s)\n", data.name.c_str(), sample_name.c_str()); } else { std::printf("%s\n", data.name.c_str()); } } #endif #if 1 if(!node->is_root()) { if(data.is_sample) { std::string sample_name = vxorg::get_sample_name(node); // paths auto path = organized_destination_path / vxorg::get_sample_path(node); auto source_path = unorganized_source_path / vxorg::get_sample_name(node); if(!std::filesystem::exists(source_path)) { std::printf("WARNING: sample %s in tree (source disk file %s) does not exist\n", sample_name.c_str(), source_path.string().c_str()); } else { filesystem_threadpool.add_task([path, source_path, sample_name, &bar]() { bar.set_option(ind::option::PostfixText { std::format("Moving {}", sample_name) }); auto dest_path = path / sample_name; // possibly TOCTOUable but it should:tm: be fine? if(!std::filesystem::exists(path)) { std::filesystem::create_directories(path); } if(std::filesystem::exists(dest_path)) { std::filesystem::remove(dest_path); } std::filesystem::rename(source_path, dest_path); bar.tick(); }); } } } #endif }); filesystem_threadpool.shutdown(); bar.mark_as_completed(); std::printf("Done.\n"); return 0; }