reapack

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

commit 5ad2d8c42d1acaba443744584f157c8f4f397e8d
parent 83cda34af336ea2bb2bf4ca2a9a04f6609045769
Author: cfillion <cfillion@users.noreply.github.com>
Date:   Wed,  4 May 2016 21:16:42 -0400

implement pinning packages to current version (aka ignore updates)

Diffstat:
Msrc/browser.cpp | 109+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------------------
Msrc/browser.hpp | 8+++++++-
Msrc/receipt.hpp | 11++++++++++-
Msrc/registry.cpp | 19+++++++++++++++----
Msrc/registry.hpp | 5++++-
Msrc/task.hpp | 10++++++++++
Msrc/transaction.cpp | 39++++++++++++++++++++++-----------------
Msrc/transaction.hpp | 11+----------
Mtest/registry.cpp | 17+++++++++++++++++
9 files changed, 168 insertions(+), 61 deletions(-)

diff --git a/src/browser.cpp b/src/browser.cpp @@ -43,6 +43,7 @@ enum Action { ACTION_REINSTALL_ALL, ACTION_UNINSTALL, ACTION_UNINSTALL_ALL, + ACTION_PIN, ACTION_CONTENTS, ACTION_HISTORY, ACTION_ABOUT, @@ -138,6 +139,9 @@ void Browser::onCommand(const int id, const int event) case ACTION_UNINSTALL_ALL: selectionDo(bind(&Browser::uninstall, this, arg::_1, false)); break; + case ACTION_PIN: + togglePin(m_currentIndex); + break; case ACTION_CONTENTS: contents(m_currentIndex); break; @@ -148,7 +152,7 @@ void Browser::onCommand(const int id, const int event) about(m_currentIndex); break; case ACTION_RESET_ALL: - selectionDo(bind(&Browser::resetAction, this, arg::_1)); + selectionDo(bind(&Browser::resetTarget, this, arg::_1)); break; case ACTION_REFRESH: refresh(true); @@ -201,7 +205,7 @@ void Browser::onContextMenu(HWND target, const int x, const int y) menu.addAction(AUTO_STR("&Install/update selection"), ACTION_LATEST_ALL); menu.addAction(AUTO_STR("&Reinstall selection"), ACTION_REINSTALL_ALL); menu.addAction(AUTO_STR("&Uninstall selection"), ACTION_UNINSTALL_ALL); - menu.addAction(AUTO_STR("&Clear queued action"), ACTION_RESET_ALL); + menu.addAction(AUTO_STR("&Clear queued actions"), ACTION_RESET_ALL); menu.addSeparator(); } @@ -275,6 +279,16 @@ void Browser::onContextMenu(HWND target, const int x, const int y) menu.addSeparator(); + const UINT pinIndex = menu.addAction( + AUTO_STR("&Pin current version"), ACTION_PIN); + + if(!entry->canPin()) + menu.disable(pinIndex); + if(entry->pin.value_or(entry->regEntry.pinned)) + menu.check(pinIndex); + + menu.addSeparator(); + menu.setEnabled(!entry->test(ObsoleteFlag), menu.addAction(AUTO_STR("Package &Contents"), ACTION_CONTENTS)); @@ -487,6 +501,8 @@ void Browser::transferActions() entryIt->target = target; } + if(oldEntry->pin) + entryIt->pin = *oldEntry->pin; m_actions.insert(&*entryIt); } @@ -584,6 +600,8 @@ string Browser::getValue(const Column col, const Entry &entry) const case StateColumn: { if(entry.test(ObsoleteFlag)) display += 'o'; + else if(entry.regEntry.pinned) + display += 'p'; else if(entry.test(OutOfDateFlag)) display += 'u'; else if(entry.test(InstalledFlag)) @@ -593,6 +611,8 @@ string Browser::getValue(const Column col, const Entry &entry) const if(entry.target) display += *entry.target == nullptr ? 'U' : 'I'; + if(entry.pin && entry.canPin()) + display += 'P'; return display; } @@ -629,7 +649,7 @@ bool Browser::match(const Entry &entry) const case All: break; case Queued: - if(!entry.target) + if(!m_actions.count(const_cast<Entry *>(&entry))) return false; break; case Installed: @@ -723,7 +743,7 @@ void Browser::installVersion(const int index, const size_t verIndex) const Version *target = entry->package->version(verIndex); if(target == entry->current) - resetAction(index); + resetTarget(index); else setTarget(index, target); } @@ -736,25 +756,25 @@ void Browser::uninstall(const int index, const bool toggle) setTarget(index, nullptr, toggle); } -void Browser::resetAction(const int index) +void Browser::togglePin(const int index) { Entry *entry = getEntry(index); - if(!entry->target) + if(!entry) return; - entry->target = boost::none; - m_actions.erase(entry); + const bool newVal = !entry->pin.value_or(entry->regEntry.pinned); - if(currentTab() == Queued) { - m_list->removeRow(index); - m_visibleEntries.erase(m_visibleEntries.begin() + index); - updateDisplayLabel(); + if(newVal == entry->regEntry.pinned) { + entry->pin = boost::none; + if(!entry->target) + m_actions.erase(entry); + } + else { + entry->pin = newVal; + m_actions.insert(entry); } - else - m_list->replaceRow(index, makeRow(*entry)); - if(m_actions.empty()) - disable(m_apply); + updateAction(index); } void Browser::setTarget(const int index, const Version *target, const bool toggle) @@ -762,13 +782,45 @@ void Browser::setTarget(const int index, const Version *target, const bool toggl Entry *entry = getEntry(index); if(toggle && entry->target && *entry->target == target) - resetAction(index); + resetTarget(index); else if(entry) { entry->target = target; m_actions.insert(entry); + updateAction(index); + } +} + +void Browser::resetTarget(const int index) +{ + Entry *entry = getEntry(index); + if(!entry->target) + return; + + entry->target = boost::none; + if(!entry->pin || !entry->canPin()) + m_actions.erase(entry); + + updateAction(index); +} + +void Browser::updateAction(const int index) +{ + Entry *entry = getEntry(index); + if(!entry) + return; + + if(currentTab() == Queued && !m_actions.count(entry)) { + m_list->removeRow(index); + m_visibleEntries.erase(m_visibleEntries.begin() + index); + updateDisplayLabel(); + } + else m_list->replaceRow(index, makeRow(*entry)); + + if(m_actions.empty()) + disable(m_apply); + else enable(m_apply); - } } void Browser::selectionDo(const function<void (int)> &func) @@ -823,18 +875,21 @@ bool Browser::apply() return false; for(Entry *entry : m_actions) { - if(!entry->target) - continue; + if(entry->target) { + const Version *target = *entry->target; - const Version *target = *entry->target; + if(target) + tx->install(target); + else + tx->uninstall(entry->regEntry); - if(target) - tx->install(target); - else - tx->uninstall(entry->regEntry); + entry->target = boost::none; + } - // clear queued actions - entry->target = boost::none; + if(entry->pin) { + tx->setPinned(entry->package, *entry->pin); + entry->pin = boost::none; + } } m_actions.clear(); diff --git a/src/browser.hpp b/src/browser.hpp @@ -61,15 +61,19 @@ private: struct Entry { typedef std::tuple<std::string, std::string, std::string> Hash; + int flags; Registry::Entry regEntry; const Package *package; const Version *latest; const Version *current; + boost::optional<const Version *> target; + boost::optional<bool> pin; Hash hash() const; bool test(Flag f) const { return (flags & f) != 0; } + bool canPin() const { return target ? *target != nullptr : test(InstalledFlag); } bool operator==(const Entry &o) const { return hash() == o.hash(); } }; @@ -107,6 +111,8 @@ private: bool isFiltered(Package::Type) const; void toggleFiltered(Package::Type); void setTarget(const int index, const Version *, bool toggle = true); + void resetTarget(int index); + void updateAction(const int index); void selectionDo(const std::function<void (int)> &); Tab currentTab() const; bool confirm() const; @@ -116,7 +122,7 @@ private: void reinstall(int index, bool toggle = true); void installVersion(int index, size_t verIndex); void uninstall(int index, bool toggle = true); - void resetAction(int index); + void togglePin(int index); void history(int index); void contents(int index); void about(int index); diff --git a/src/receipt.hpp b/src/receipt.hpp @@ -22,8 +22,17 @@ #include <string> #include <vector> +#include "registry.hpp" + class Path; -struct InstallTicket; + +struct InstallTicket { + enum Type { Install, Upgrade }; + + Type type; + const Version *version; + Registry::Entry regEntry; +}; class Receipt { public: diff --git a/src/registry.cpp b/src/registry.cpp @@ -42,14 +42,15 @@ Registry::Registry(const Path &path) "UPDATE entries SET type = ?, version = ?, author = ? WHERE id = ?" ); + m_setPinned = m_db.prepare("UPDATE entries SET pinned = ? WHERE id = ?"); + m_findEntry = m_db.prepare( - "SELECT id, remote, category, package, type, version, author FROM entries " - "WHERE remote = ? AND category = ? AND package = ? " - "LIMIT 1" + "SELECT id, remote, category, package, type, version, author, pinned " + "FROM entries WHERE remote = ? AND category = ? AND package = ? LIMIT 1" ); m_allEntries = m_db.prepare( - "SELECT id, category, package, type, version, author " + "SELECT id, category, package, type, version, author, pinned " "FROM entries WHERE remote = ?" ); m_forgetEntry = m_db.prepare("DELETE FROM entries WHERE id = ?"); @@ -92,6 +93,7 @@ void Registry::migrate() " type INTEGER NOT NULL," " version TEXT NOT NULL," " author TEXT NOT NULL," + " pinned INTEGER DEFAULT 0," " UNIQUE(remote, category, package)" ");" @@ -188,6 +190,13 @@ auto Registry::push(const Version *ver, vector<Path> *conflicts) -> Entry } } +void Registry::setPinned(const Entry &entry, const bool pinned) +{ + m_setPinned->bind(1, pinned); + m_setPinned->bind(2, entry.id); + m_setPinned->exec(); +} + auto Registry::getEntry(const Package *pkg) const -> Entry { Entry entry{}; @@ -209,6 +218,7 @@ auto Registry::getEntry(const Package *pkg) const -> Entry entry.type = static_cast<Package::Type>(m_findEntry->intColumn(col++)); entry.version.tryParse(m_findEntry->stringColumn(col++)); entry.version.setAuthor(m_findEntry->stringColumn(col++)); + entry.pinned = m_findEntry->intColumn(col++) != 0; return false; }); @@ -232,6 +242,7 @@ auto Registry::getEntries(const string &remoteName) const -> vector<Entry> entry.type = static_cast<Package::Type>(m_allEntries->intColumn(col++)); entry.version.tryParse(m_allEntries->stringColumn(col++)); entry.version.setAuthor(m_allEntries->stringColumn(col++)); + entry.pinned = m_allEntries->intColumn(col++) != 0; list.push_back(entry); diff --git a/src/registry.hpp b/src/registry.hpp @@ -39,6 +39,7 @@ public: std::string package; Package::Type type; Version version; + bool pinned; operator bool() const { return id != 0; } }; @@ -50,6 +51,7 @@ public: std::set<Path> getFiles(const Entry &) const; std::string getMainFile(const Entry &) const; Entry push(const Version *, std::vector<Path> *conflicts = nullptr); + void setPinned(const Entry &, bool pinned); void forget(const Entry &); void savepoint(); void restore(); @@ -62,13 +64,14 @@ private: Database m_db; Statement *m_insertEntry; Statement *m_updateEntry; + Statement *m_setPinned; Statement *m_findEntry; Statement *m_allEntries; Statement *m_forgetEntry; - Statement *m_setMainFile; Statement *m_getFiles; Statement *m_getMainFile; + Statement *m_setMainFile; Statement *m_insertFile; Statement *m_clearFiles; Statement *m_forgetFiles; diff --git a/src/task.hpp b/src/task.hpp @@ -95,4 +95,14 @@ private: std::set<Path> m_removedFiles; }; +class DummyTask : public Task { +public: + DummyTask(Transaction *t) : Task(t) {} + +protected: + void doStart() override {} + bool doCommit() override { return true; } + void doRollback() override {} +}; + #endif diff --git a/src/transaction.cpp b/src/transaction.cpp @@ -49,8 +49,9 @@ Transaction::Transaction() finish(); }); + // run tasks after fetching indexes m_downloadQueue.onDone([=] { - if(m_installQueue.empty()) + if(m_tasks.empty()) finish(); else runTasks(); @@ -105,7 +106,7 @@ void Transaction::synchronize(const Package *pkg, const InstallOpts &opts) if(allFilesExists(latest->files())) return; // latest version is really installed, nothing to do here! } - else if(regEntry.version > *latest) + else if(regEntry.pinned || *latest < regEntry.version) return; install(latest, regEntry); @@ -186,18 +187,12 @@ void Transaction::install(const Version *ver, if(!m_indexes.count(ri)) m_indexes.insert(ri); - m_installQueue.push({type, ver, regEntry}); -} - -void Transaction::installTicket(const InstallTicket &ticket) -{ - const Version *ver = ticket.version; - const set<Path> &currentFiles = m_registry->getFiles(ticket.regEntry); + const set<Path> &currentFiles = m_registry->getFiles(regEntry); InstallTask *task = new InstallTask(ver, currentFiles, this); task->onCommit([=] { - m_receipt.addTicket(ticket); + m_receipt.addTicket({type, ver, regEntry}); m_receipt.addRemovals(task->removedFiles()); const Registry::Entry newEntry = m_registry->push(ver); @@ -209,6 +204,7 @@ void Transaction::installTicket(const InstallTicket &ticket) }); addTask(task); + m_receipt.setEnabled(true); } void Transaction::registerAll(const Remote &remote) @@ -222,6 +218,21 @@ void Transaction::registerAll(const Remote &remote) inhibit(remote); } +void Transaction::setPinned(const Package *pkg, const bool pinned) +{ + // pkg may or may not be installed yet at this point, + // waiting for the install task to be commited before querying the registry + + DummyTask *task = new DummyTask(this); + task->onCommit([=] { + const Registry::Entry &entry = m_registry->getEntry(pkg); + if(entry) + m_registry->setPinned(entry, pinned); + }); + + addTask(task); +} + void Transaction::uninstall(const Remote &remote) { inhibit(remote); @@ -261,6 +272,7 @@ void Transaction::uninstall(const Registry::Entry &entry) task->onCommit([=] { m_receipt.addRemovals(task->removedFiles()); }); addTask(task); + m_receipt.setEnabled(true); } bool Transaction::saveFile(Download *dl, const Path &path) @@ -315,8 +327,6 @@ void Transaction::addTask(Task *task) { m_tasks.push_back(task); m_taskQueue.push(task); - - m_receipt.setEnabled(true); } bool Transaction::runTasks() @@ -327,11 +337,6 @@ bool Transaction::runTasks() m_onRun(); m_onRun.disconnect_all_slots(); - while(!m_installQueue.empty()) { - installTicket(m_installQueue.front()); - m_installQueue.pop(); - } - while(!m_taskQueue.empty()) { m_taskQueue.front()->start(); m_taskQueue.pop(); diff --git a/src/transaction.hpp b/src/transaction.hpp @@ -36,14 +36,6 @@ struct InstallOpts; typedef std::shared_ptr<const Index> IndexPtr; -struct InstallTicket { - enum Type { Install, Upgrade }; - - Type type; - const Version *version; - const Registry::Entry regEntry; -}; - struct HostTicket { bool add; Registry::Entry entry; std::string file; }; class Transaction { @@ -59,6 +51,7 @@ public: void synchronize(const Remote &, const InstallOpts &); void install(const Version *); + void setPinned(const Package *, bool pinned); void uninstall(const Remote &); void uninstall(const Registry::Entry &); void registerAll(const Remote &); @@ -81,7 +74,6 @@ private: void synchronize(const Package *, const InstallOpts &); void install(const Version *, const Registry::Entry &); - void installTicket(const InstallTicket &); void addTask(Task *); bool allFilesExists(const std::set<Path> &) const; @@ -104,7 +96,6 @@ private: DownloadQueue m_downloadQueue; std::queue<Task *> m_taskQueue; - std::queue<InstallTicket> m_installQueue; std::queue<HostTicket> m_regQueue; VoidSignal m_onRun; diff --git a/test/registry.cpp b/test/registry.cpp @@ -174,3 +174,20 @@ TEST_CASE("get main file", M) { const Registry::Entry &entry = reg.push(ver); REQUIRE(reg.getMainFile(entry) == main->targetPath().join('/')); } + +TEST_CASE("pin registry entry", M) { + MAKE_PACKAGE + + Registry reg; + reg.push(ver); + + const Registry::Entry &entry = reg.getEntry(&pkg); + REQUIRE_FALSE(entry.pinned); + + reg.setPinned(entry, true); + REQUIRE(reg.getEntry(&pkg).pinned); + REQUIRE(reg.getEntries(ri.name())[0].pinned); + + reg.setPinned(entry, false); + REQUIRE_FALSE(reg.getEntry(&pkg).pinned); +}