From 2ce7f4cfaf83e74b6394e32ce8ec45303a7e5d55 Mon Sep 17 00:00:00 2001 From: King_DuckZ Date: Fri, 26 Mar 2021 20:52:25 +0100 Subject: [PATCH] Convert notebook list to tree Use that tree to build the delete list. I think it's not necessary as files marked as deleted are direct children of root always, but, just in case. Now if an ancestor is marked as deleted the whole subtree gets printed out for deletion. Also support multi root, rubbish bin seems to be its own root in fact. --- main.cpp | 210 +++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 195 insertions(+), 15 deletions(-) diff --git a/main.cpp b/main.cpp index fc6d619..6202475 100644 --- a/main.cpp +++ b/main.cpp @@ -1,3 +1,20 @@ +/* Copyright 2021, Michele Santullo + * This file is part of remarkable_tool. + * + * remarkable_tool is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Remarkable_tool is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with remarkable_tool. If not, see . + */ + #include #include #include @@ -6,6 +23,9 @@ #include #include #include +#include +#include +#include namespace fs = std::filesystem; @@ -23,7 +43,27 @@ struct NotebookInfo { bool deleted = false; }; -std::ostream& operator<< (std::ostream& str, const std::pair& v) { +struct Node { + Node() : + info(nullptr), + parent(nullptr) + { } + + Node (std::string_view name, const NotebookInfo* payload, Node* parent) : + name(name), + info(payload), + parent(parent) + { } + + std::vector children; + std::string_view name; + const NotebookInfo* info; + const Node* parent; +}; + +typedef std::unordered_map NotebookMapType; + +std::ostream& operator<< (std::ostream& str, const NotebookMapType::value_type& v) { auto& key = v.first; auto& val = v.second; str << key << " (\"" << val.visible_name << "\", " << val.type << @@ -43,11 +83,17 @@ std::ostream& operator<< (std::ostream& str, const std::pair build_notebook_infos ( +template +std::vector& operator+= (std::vector& dst, const std::vector& src) { + dst.insert(dst.end(), src.begin(), src.end()); + return dst; +} + +NotebookMapType build_notebook_infos ( const fs::path& from_path ) { simdjson::dom::parser parser; - std::unordered_map retval; + NotebookMapType retval; for (const auto& entry : fs::directory_iterator(from_path)) { NotebookInfo& curr_info = retval[entry.path().stem()]; @@ -76,29 +122,163 @@ std::unordered_map build_notebook_infos ( return retval; } + +std::vector to_tree (const NotebookMapType& nbs) { + std::unordered_map> parents; + for (const auto& nb : nbs) { + auto it_ins = parents.emplace(nb.second.parent, std::make_pair(0U, Node{nb.second.parent, nullptr, nullptr})); + it_ins.first->second.first++; + } + for (const auto& nb : nbs) { + auto it_parent = parents.find(nb.first); + if (parents.cend() != it_parent) { + Node& node = it_parent->second.second; + node.info = &nb.second; + } + } + for (auto& par : parents) { + Node& node = par.second.second; + const unsigned int children_count = par.second.first; + node.children.reserve(children_count); + } + + for (const auto& nb : nbs) { + if (0 == parents.count(nb.first)) { + Node& parent = parents[nb.second.parent].second; + parent.children.emplace_back(nb.first, &nb.second, &parent); + } + } + + std::vector roots; + std::unordered_map grouped_nodes; + for (auto it = parents.begin(), it_end = parents.end(); it != it_end; it = parents.erase(it)) { + auto& node = it->second.second; + if (node.info) { + auto it_parent = parents.find(node.info->parent); + Node* dst_node = (parents.end() == it_parent ? grouped_nodes[node.info->parent] : &it_parent->second.second); + dst_node->children.push_back(std::move(node)); + grouped_nodes[dst_node->children.back().name] = &dst_node->children.back(); + } + else { + roots.push_back(std::move(node)); + grouped_nodes[node.name] = &roots.back(); + } + } + + return roots; +} +void print_tree (const Node& tree, std::string_view desc={}, std::string indent={}) { + std::cout << indent << desc << " (\"" << tree.name << "\")"; + if (tree.info and tree.info->deleted) + std::cout << " DELETED"; + std::cout << '\n'; + + for (const auto& child : tree.children) { + print_tree(child, child.info->visible_name, indent + "\t"); + } +} + +std::uintmax_t recursive_size (const Node& tree) { + std::uintmax_t retval = 0; + if (tree.info) + retval = tree.info->total_size; + + for (const auto& child : tree.children) { + retval += recursive_size(child); + } + return retval; +} + +std::vector to_flat_notebook_list (const Node& tree) { + std::vector retval; + for (const auto& child : tree.children) { + retval += to_flat_notebook_list(child); + } + if (tree.info) + retval.push_back(tree.info); + return retval; +} + +std::vector make_dele_list (const Node& tree) { + if (tree.info and tree.info->deleted) + return to_flat_notebook_list(tree); + + std::vector retval; + for (const auto& child : tree.children) { + retval += make_dele_list(child); + } + return retval; +} } //unnamed namespace int main() { using std::string_view; - rmlab::Notebook doc(BASE_PATH "a4bcfe83-a91d-485b-b27c-2a06aa287641"); + //rmlab::Notebook doc(BASE_PATH "a4bcfe83-a91d-485b-b27c-2a06aa287641"); //rmlab::Notebook doc(BASE_PATH "aa90b0e7-5c1a-42fe-930f-dad9cf3363cc"); - std::cout << "Document version: " << doc.version << '\n'; + //std::cout << "Document version: " << doc.version << '\n'; auto notebooks = build_notebook_infos(BASE_PATH); - int z = 0; - std::uintmax_t total = 0; - for (auto& nb : notebooks) { - std::cout << nb << '\n'; - std::cout << "------ " << z << "-----\n"; - ++z; - total += nb.second.total_size; + //naive linear delete + //std::uintmax_t total = 0; + //std::uintmax_t freed = 0; + //std::set dele_list; + //for (auto& nb : notebooks) { + // if (nb.second.deleted) { + // dele_list.insert(nb.first); + // for (const auto& file : nb.second.files) { + // std::cout << BASE_PATH << file << '\n'; + // } + // freed += nb.second.total_size; + // } + // total += nb.second.total_size; + //} + + //for (auto& nb : notebooks) { + // if (dele_list.count(nb.second.parent) and not nb.second.deleted) { + // std::cerr << "Warning: " << nb.second.parent << " deleted but it's the parent of " << nb.first << "!\n"; + // } + //} + // + //std::cout << "Found " << notebooks.size() << " notebooks\n"; + //std::cout << "Total size " << std::setprecision(2) << + // static_cast(total) / (1024.0 * 1024.0 * 1024.0) << "GiB\n"; + //std::cout << "Would delete " << dele_list.size() << " notebooks\n"; + //std::cout << "Would free " << std::setprecision(2) << + // static_cast(freed) / (1024.0 * 1024.0 * 1024.0) << "GiB\n"; + + std::vector roots = to_tree(notebooks); + //std::cout << "Found " << notebooks.size() << " notebooks\n"; + //std::cout << "Collection has " << roots.size() << " roots\n"; + //std::cout << " ---------\n"; + //for (const auto& root : roots) { + // std::cout << "\tTree \"" << root.name << "\" has " << root.children.size() << " nodes\n\n"; + //} + + //std::uintmax_t total_mem1 = 0; + std::vector dele_list; + for (const auto& root : roots) { + //std::string_view desc; + //if (root.name == "trash") + // desc = "rubbish bin"; + //else if (root.name == "") + // desc = "root"; + + //print_tree(root, desc); + //total_mem1 += recursive_size(root); + dele_list += make_dele_list(root); } - std::cout << "Found " << notebooks.size() << " notebooks\n"; - std::cout << "Total size " << std::setprecision(2) << - static_cast(total) / (1024.0 * 1024.0 * 1024.0) << "GiB\n"; + //std::cout << "Total size 1: " << total_mem1 << " bytes\n"; + //const std::uintmax_t total_mem2 = std::accumulate(notebooks.cbegin(), notebooks.cend(), std::uintmax_t{}, [](std::uintmax_t a, const auto& b) {return a + b.second.total_size;}); + //std::cout << "Total size 2: " << total_mem2 << " bytes\n"; + + for (const NotebookInfo* nb : dele_list) { + for (const auto& f : nb->files) { + std::cout << "/home/root/.local/share/remarkable/xochitl/" << f << '\n'; + } + } return 0; }