commit 65f18732effc3eef62c8d1014d9a6d6febd839f9
parent fb83614cfebb6a69cb63684c25f114e3ea928659
Author: cfillion <cfillion@users.noreply.github.com>
Date: Sat, 26 Feb 2022 14:19:26 -0500
add a per-package option to enable pre-release updates [#46]
Closes #46
Diffstat:
16 files changed, 113 insertions(+), 81 deletions(-)
diff --git a/src/api_package.cpp b/src/api_package.cpp
@@ -108,8 +108,8 @@ DEFINE_API(bool, GetEntryInfo, ((PackageEntry*, entry))
((char*, pkgOut))((int, pkgOut_sz))((char*, descOut))((int, descOut_sz))
((int*, typeOut))((char*, verOut))((int, verOut_sz))
((char*, authorOut))((int, authorOut_sz))
- ((bool*, pinnedOut))((int*, fileCountOut)),
-R"(Get the repository name, category, package name, package description, package type, the currently installed version, author name, pinned status and how many files are owned by the given package entry.
+ ((int*, flagsOut))((int*, fileCountOut)),
+R"(Get the repository name, category, package name, package description, package type, the currently installed version, author name, flags (&1=Pinned, &2=BleedingEdge) and how many files are owned by the given package entry.
type: 1=script, 2=extension, 3=effect, 4=data, 5=theme, 6=langpack, 7=webinterface)",
{
@@ -132,8 +132,8 @@ type: 1=script, 2=extension, 3=effect, 4=data, 5=theme, 6=langpack, 7=webinterfa
snprintf(verOut, verOut_sz, "%s", regEntry.version.toString().c_str());
if(authorOut)
snprintf(authorOut, authorOut_sz, "%s", regEntry.author.c_str());
- if(pinnedOut)
- *pinnedOut = regEntry.pinned;
+ if(flagsOut)
+ *flagsOut = regEntry.flags;
if(fileCountOut)
*fileCountOut = static_cast<int>(entry->files.size());
diff --git a/src/archive.cpp b/src/archive.cpp
@@ -141,12 +141,12 @@ void ImportArchive::importPackage(const std::string &data)
return;
std::string categoryName, packageName, versionName;
- bool pinned;
+ int flags;
std::istringstream stream(data);
stream
>> quoted(categoryName) >> quoted(packageName) >> quoted(versionName)
- >> pinned;
+ >> flags;
const Package *pkg = m_lastIndex->find(categoryName, packageName);
const Version *ver = pkg ? pkg->findVersion(versionName) : nullptr;
@@ -158,7 +158,7 @@ void ImportArchive::importPackage(const std::string &data)
packageName.c_str(), versionName.c_str()));
}
- m_tx->install(ver, pinned, m_reader);
+ m_tx->install(ver, flags, m_reader);
}
ArchiveReader::ArchiveReader(const Path &path)
diff --git a/src/archive_tasks.cpp b/src/archive_tasks.cpp
@@ -68,7 +68,7 @@ bool ExportTask::start()
<< quoted(entry.category) << '\x20'
<< quoted(entry.package) << '\x20'
<< quoted(entry.version.toString()) << '\x20'
- << entry.pinned << '\n'
+ << entry.flags << '\n'
;
for(const Registry::File &file : tx()->registry()->getFiles(entry))
diff --git a/src/browser.cpp b/src/browser.cpp
@@ -153,7 +153,12 @@ void Browser::onCommand(const int id, const int event)
selectionDo(std::bind(&Browser::uninstall, this, _1, false));
break;
case ACTION_PIN:
- currentDo(std::bind(&Browser::togglePin, this, _1));
+ currentDo(std::bind(&Browser::toggleFlag, this,
+ _1, Registry::Entry::PinnedFlag));
+ break;
+ case ACTION_BLEEDINGEDGE:
+ currentDo(std::bind(&Browser::toggleFlag, this,
+ _1, Registry::Entry::BleedingEdgeFlag));
break;
case ACTION_ABOUT_PKG:
aboutPackage(m_currentIndex);
@@ -528,8 +533,8 @@ void Browser::transferActions()
entryIt->target = target;
}
- if(oldEntry->pin)
- entryIt->pin = *oldEntry->pin;
+ if(oldEntry->flags)
+ entryIt->flags = *oldEntry->flags;
m_actions.push_back(&*entryIt);
}
@@ -705,18 +710,18 @@ void Browser::uninstall(const int index, const bool toggle)
toggleTarget(index, nullptr);
}
-void Browser::togglePin(const int index)
+void Browser::toggleFlag(const int index, const int mask)
{
Entry *entry = getEntry(index);
- if(!entry || !entry->test(Entry::CanTogglePin))
+ if(!entry || !entry->test(Entry::CanToggleFlags))
return;
- const bool newVal = !entry->pin.value_or(entry->regEntry.pinned);
+ const int newVal = mask ^ entry->flags.value_or(entry->regEntry.flags);
- if(newVal == entry->regEntry.pinned)
- entry->pin = std::nullopt;
+ if(newVal == entry->regEntry.flags)
+ entry->flags = std::nullopt;
else
- entry->pin = newVal;
+ entry->flags = newVal;
updateAction(index);
}
@@ -754,8 +759,8 @@ void Browser::resetActions(const int index)
if(entry->target)
entry->target = std::nullopt;
- if(entry->pin)
- entry->pin = std::nullopt;
+ if(entry->flags)
+ entry->flags = std::nullopt;
updateAction(index);
}
@@ -767,7 +772,7 @@ void Browser::updateAction(const int index)
return;
const auto &it = find(m_actions.begin(), m_actions.end(), entry);
- if(!entry->target && (!entry->pin || !entry->test(Entry::CanTogglePin))) {
+ if(!entry->target && (!entry->flags || !entry->test(Entry::CanToggleFlags))) {
if(it != m_actions.end())
m_actions.erase(it);
}
@@ -863,15 +868,15 @@ bool Browser::apply()
const Version *target = *entry->target;
if(target)
- tx->install(target, entry->pin.value_or(false));
+ tx->install(target, entry->flags.value_or(0));
else
tx->uninstall(entry->regEntry);
entry->target = std::nullopt;
}
- else if(entry->pin) {
- tx->setPinned(entry->regEntry, *entry->pin);
- entry->pin = std::nullopt;
+ else if(entry->flags) {
+ tx->setFlags(entry->regEntry, *entry->flags);
+ entry->flags = std::nullopt;
}
}
diff --git a/src/browser.hpp b/src/browser.hpp
@@ -49,6 +49,7 @@ public:
ACTION_UNINSTALL,
ACTION_UNINSTALL_ALL,
ACTION_PIN,
+ ACTION_BLEEDINGEDGE,
ACTION_ABOUT_PKG,
ACTION_ABOUT_REMOTE,
ACTION_RESET_ALL,
@@ -126,7 +127,7 @@ private:
void reinstall(int index, bool toggle);
void installVersion(int index, size_t verIndex);
void uninstall(int index, bool toggle);
- void togglePin(int index);
+ void toggleFlag(int index, int mask);
// these can be called directly because they don't use updateAction()
void aboutRemote(int index, bool focus = true);
diff --git a/src/browser_entry.cpp b/src/browser_entry.cpp
@@ -29,7 +29,8 @@ Browser::Entry::Entry(const Package *pkg, const Registry::Entry &re, const Index
: m_flags(0), regEntry(re), package(pkg), index(i), current(nullptr)
{
const auto &instOpts = g_reapack->config()->install;
- latest = pkg->lastVersion(instOpts.bleedingEdge, regEntry.version);
+ const bool pres = instOpts.bleedingEdge || re.test(Registry::Entry::BleedingEdgeFlag);
+ latest = pkg->lastVersion(pres, regEntry.version);
if(regEntry) {
m_flags |= InstalledFlag;
@@ -69,13 +70,21 @@ std::string Browser::Entry::displayState() const
else
state += '\x20';
- if(regEntry.pinned)
+ if(regEntry.test(Registry::Entry::PinnedFlag))
state += 'p';
+ if(regEntry.test(Registry::Entry::BleedingEdgeFlag))
+ state += 'b';
if(target)
state += *target == nullptr ? 'R' : 'I';
- if(pin && test(CanTogglePin))
- state += 'P';
+
+ if(test(CanToggleFlags) && flags) {
+ const int flagsDiff = regEntry.flags ^ *flags;
+ if(flagsDiff & Registry::Entry::PinnedFlag)
+ state += 'P';
+ if(flagsDiff & Registry::Entry::BleedingEdgeFlag)
+ state += 'B';
+ }
return state;
}
@@ -209,11 +218,17 @@ void Browser::Entry::fillMenu(Menu &menu) const
}
const UINT pinIndex = menu.addAction("&Pin current version", ACTION_PIN);
- if(!test(CanTogglePin))
+ if(!test(CanToggleFlags))
menu.disable(pinIndex);
- if(pin.value_or(regEntry.pinned))
+ if(flags.value_or(regEntry.flags) & Registry::Entry::PinnedFlag)
menu.check(pinIndex);
+ const UINT presIndex = menu.addAction("Enable pre-releases (&bleeding-edge)", ACTION_BLEEDINGEDGE);
+ if(!test(CanToggleFlags))
+ menu.disable(presIndex);
+ if(flags.value_or(regEntry.flags) & Registry::Entry::BleedingEdgeFlag)
+ menu.check(presIndex);
+
const UINT uninstallIndex = menu.addAction("&Uninstall", ACTION_UNINSTALL);
if(!test(InstalledFlag) || test(ProtectedFlag))
menu.disable(uninstallIndex);
@@ -243,8 +258,8 @@ int Browser::Entry::possibleActions(bool allowToggle) const
if(test(InstalledFlag) && !test(ProtectedFlag) && canSetTarget(nullptr))
flags |= CanUninstall;
if(target ? *target != nullptr : test(InstalledFlag))
- flags |= CanTogglePin;
- if(target || pin)
+ flags |= CanToggleFlags;
+ if(target || flags)
flags |= CanClearQueued;
return flags;
diff --git a/src/browser_entry.hpp b/src/browser_entry.hpp
@@ -47,14 +47,14 @@ public:
CanUninstall = 1<<2,
CanClearQueued = 1<<3,
- CanTogglePin = 1<<10,
+ CanToggleFlags = 1<<10,
};
Entry(const Package *, const Registry::Entry &, const IndexPtr &);
Entry(const Registry::Entry &, const IndexPtr &);
std::optional<const Version *> target;
- std::optional<bool> pin;
+ std::optional<int> flags;
std::string displayState() const;
const std::string &indexName() const;
diff --git a/src/install.cpp b/src/install.cpp
@@ -25,9 +25,9 @@
#include "reapack.hpp"
#include "transaction.hpp"
-InstallTask::InstallTask(const Version *ver, const bool pin,
+InstallTask::InstallTask(const Version *ver, const int flags,
const Registry::Entry &re, const ArchiveReaderPtr &reader, Transaction *tx)
- : Task(tx), m_version(ver), m_pin(pin), m_oldEntry(std::move(re)), m_reader(reader),
+ : Task(tx), m_version(ver), m_flags(flags), m_oldEntry(std::move(re)), m_reader(reader),
m_fail(false), m_index(ver->package()->category()->index()->shared_from_this())
{
}
@@ -123,8 +123,8 @@ void InstallTask::commit()
const Registry::Entry newEntry = tx()->registry()->push(m_version);
- if(m_pin)
- tx()->registry()->setPinned(newEntry, true);
+ if(m_flags)
+ tx()->registry()->setFlags(newEntry, m_flags);
tx()->registerAll(true, newEntry);
}
diff --git a/src/registry.cpp b/src/registry.cpp
@@ -43,22 +43,22 @@ Registry::Registry(const Path &path)
"SET desc = ?, type = ?, version = ?, author = ? WHERE id = ?"
);
- m_setPinned = m_db.prepare("UPDATE entries SET pinned = ? WHERE id = ?");
+ m_setFlags = m_db.prepare("UPDATE entries SET flags = ? WHERE id = ?");
m_findEntry = m_db.prepare(
- "SELECT id, remote, category, package, desc, type, version, author, pinned "
+ "SELECT id, remote, category, package, desc, type, version, author, flags "
"FROM entries WHERE remote = ? AND category = ? AND package = ? LIMIT 1"
);
m_allEntries = m_db.prepare(
- "SELECT id, remote, category, package, desc, type, version, author, pinned "
+ "SELECT id, remote, category, package, desc, type, version, author, flags "
"FROM entries WHERE remote = ?"
);
m_forgetEntry = m_db.prepare("DELETE FROM entries WHERE id = ?");
// file queries
m_getOwner = m_db.prepare(
- "SELECT e.id, remote, category, package, desc, e.type, version, author, pinned "
+ "SELECT e.id, remote, category, package, desc, e.type, version, author, flags "
"FROM entries e JOIN files f ON f.entry = e.id WHERE f.path = ? LIMIT 1"
);
m_getFiles = m_db.prepare(
@@ -78,7 +78,7 @@ Registry::Registry(const Path &path)
void Registry::migrate()
{
- const Database::Version version{0, 5};
+ const Database::Version version{0, 6};
const Database::Version ¤t = m_db.version();
if(!current) {
@@ -93,7 +93,7 @@ void Registry::migrate()
" type INTEGER NOT NULL,"
" version TEXT NOT NULL,"
" author TEXT NOT NULL,"
- " pinned INTEGER DEFAULT 0,"
+ " flags INTEGER DEFAULT 0,"
" UNIQUE(remote, category, package)"
");"
@@ -135,6 +135,9 @@ void Registry::migrate()
[[fallthrough]];
case 4:
convertImplicitSections();
+ [[fallthrough]];
+ case 5:
+ m_db.exec("ALTER TABLE entries RENAME COLUMN pinned TO flags;");
break;
}
@@ -217,11 +220,11 @@ auto Registry::push(const Version *ver, std::vector<Path> *conflicts) -> Entry
}
}
-void Registry::setPinned(const Entry &entry, const bool pinned)
+void Registry::setFlags(const Entry &entry, const int flags)
{
- m_setPinned->bind(1, pinned);
- m_setPinned->bind(2, entry.id);
- m_setPinned->exec();
+ m_setFlags->bind(1, flags);
+ m_setFlags->bind(2, entry.id);
+ m_setFlags->exec();
}
auto Registry::getEntry(const Package *pkg) const -> Entry
@@ -354,5 +357,5 @@ void Registry::fillEntry(const Statement *stmt, Entry *entry) const
entry->type = static_cast<Package::Type>(stmt->intColumn(col++));
entry->version.tryParse(stmt->stringColumn(col++));
entry->author = stmt->stringColumn(col++);
- entry->pinned = stmt->boolColumn(col++);
+ entry->flags = static_cast<int>(stmt->intColumn(col++));
}
diff --git a/src/registry.hpp b/src/registry.hpp
@@ -29,6 +29,11 @@
class Registry {
public:
struct Entry {
+ enum Flag {
+ PinnedFlag = 1<<0,
+ BleedingEdgeFlag = 1<<1,
+ };
+
typedef int64_t id_t;
id_t id;
@@ -39,10 +44,11 @@ public:
Package::Type type;
VersionName version;
std::string author;
- bool pinned;
+ int flags;
operator bool() const { return id > 0; }
bool operator==(const Entry &o) const { return id == o.id; }
+ bool test(Flag f) const { return (flags & f) == f; }
};
struct File {
@@ -61,7 +67,7 @@ public:
std::vector<File> getFiles(const Entry &) const;
std::vector<File> getMainFiles(const Entry &) const;
Entry push(const Version *, std::vector<Path> *conflicts = nullptr);
- void setPinned(const Entry &, bool pinned);
+ void setFlags(const Entry &, int flags);
void forget(const Entry &);
void savepoint() { m_db.savepoint(); }
@@ -76,7 +82,7 @@ private:
Database m_db;
Statement *m_insertEntry;
Statement *m_updateEntry;
- Statement *m_setPinned;
+ Statement *m_setFlags;
Statement *m_findEntry;
Statement *m_allEntries;
Statement *m_forgetEntry;
diff --git a/src/synchronize.cpp b/src/synchronize.cpp
@@ -69,7 +69,8 @@ void SynchronizeTask::commit()
if(m_opts.promptObsolete && !m_remote.isProtected()) {
for(const auto &entry : tx()->registry()->getEntries(m_remote.name())) {
- if(!entry.pinned && !index->find(entry.category, entry.package))
+ if(!entry.test(Registry::Entry::PinnedFlag) &&
+ !index->find(entry.category, entry.package))
tx()->addObsolete(entry);
}
}
@@ -82,7 +83,8 @@ void SynchronizeTask::synchronize(const Package *pkg)
if(!entry && !m_opts.autoInstall)
return;
- const Version *latest = pkg->lastVersion(m_opts.bleedingEdge, entry.version);
+ const bool pres = m_opts.bleedingEdge || entry.test(Registry::Entry::BleedingEdgeFlag);
+ const Version *latest = pkg->lastVersion(pres, entry.version);
if(!latest)
return;
@@ -91,7 +93,7 @@ void SynchronizeTask::synchronize(const Package *pkg)
if(FS::allExists(latest->files()))
return; // latest version is really installed, nothing to do here!
}
- else if(entry.pinned || latest->name() < entry.version)
+ else if(entry.test(Registry::Entry::PinnedFlag) || latest->name() < entry.version)
return;
tx()->install(latest, entry);
diff --git a/src/task.cpp b/src/task.cpp
@@ -55,13 +55,13 @@ void UninstallTask::commit()
tx()->registry()->forget(m_entry);
}
-PinTask::PinTask(const Registry::Entry &re, const bool pin, Transaction *tx)
- : Task(tx), m_entry(std::move(re)), m_pin(pin)
+FlagsTask::FlagsTask(const Registry::Entry &re, const int flags, Transaction *tx)
+ : Task(tx), m_entry(std::move(re)), m_flags(flags)
{
}
-void PinTask::commit()
+void FlagsTask::commit()
{
- tx()->registry()->setPinned(m_entry, m_pin);
+ tx()->registry()->setFlags(m_entry, m_flags);
tx()->receipt()->setPackageChanged();
}
diff --git a/src/task.hpp b/src/task.hpp
@@ -80,7 +80,7 @@ private:
class InstallTask : public Task {
public:
- InstallTask(const Version *ver, bool pin, const Registry::Entry &,
+ InstallTask(const Version *ver, int flags, const Registry::Entry &,
const ArchiveReaderPtr &, Transaction *);
bool start() override;
@@ -91,7 +91,7 @@ private:
void push(ThreadTask *, const TempPath &);
const Version *m_version;
- bool m_pin;
+ int m_flags;
Registry::Entry m_oldEntry;
ArchiveReaderPtr m_reader;
@@ -117,16 +117,16 @@ private:
std::set<Path> m_removedFiles;
};
-class PinTask : public Task {
+class FlagsTask : public Task {
public:
- PinTask(const Registry::Entry &, bool pin, Transaction *);
+ FlagsTask(const Registry::Entry &, int flags, Transaction *);
protected:
void commit() override;
private:
Registry::Entry m_entry;
- bool m_pin;
+ int m_flags;
};
class ExportTask : public Task {
diff --git a/src/transaction.cpp b/src/transaction.cpp
@@ -100,21 +100,21 @@ IndexPtr Transaction::loadIndex(const Remote &remote)
}
}
-void Transaction::install(const Version *ver, const bool pin,
+void Transaction::install(const Version *ver, const int flags,
const ArchiveReaderPtr &reader)
{
- install(ver, m_registry.getEntry(ver->package()), pin, reader);
+ install(ver, m_registry.getEntry(ver->package()), flags, reader);
}
void Transaction::install(const Version *ver, const Registry::Entry &oldEntry,
- const bool pin, const ArchiveReaderPtr &reader)
+ const int flags, const ArchiveReaderPtr &reader)
{
- m_nextQueue.push(std::make_shared<InstallTask>(ver, pin, oldEntry, reader, this));
+ m_nextQueue.push(std::make_shared<InstallTask>(ver, flags, oldEntry, reader, this));
}
-void Transaction::setPinned(const Registry::Entry &entry, const bool pinned)
+void Transaction::setFlags(const Registry::Entry &entry, const int flags)
{
- m_nextQueue.push(std::make_shared<PinTask>(entry, pinned, this));
+ m_nextQueue.push(std::make_shared<FlagsTask>(entry, flags, this));
}
void Transaction::uninstall(const Remote &remote)
diff --git a/src/transaction.hpp b/src/transaction.hpp
@@ -55,10 +55,10 @@ public:
std::vector<IndexPtr> getIndexes(const std::vector<Remote> &) const;
void synchronize(const Remote &,
const std::optional<bool> &forceAutoInstall = std::nullopt);
- void install(const Version *, bool pin = false, const ArchiveReaderPtr & = nullptr);
+ void install(const Version *, int flags = 0, const ArchiveReaderPtr & = nullptr);
void install(const Version *, const Registry::Entry &oldEntry,
- bool pin = false, const ArchiveReaderPtr & = nullptr);
- void setPinned(const Registry::Entry &, bool pinned);
+ int flags = false, const ArchiveReaderPtr & = nullptr);
+ void setFlags(const Registry::Entry &, int flags);
void uninstall(const Remote &);
void uninstall(const Registry::Entry &);
void exportArchive(const std::string &path);
diff --git a/test/registry.cpp b/test/registry.cpp
@@ -185,21 +185,21 @@ TEST_CASE("get main files", M) {
REQUIRE(current[0].type == Package::EffectType);
}
-TEST_CASE("pin registry entry", M) {
+TEST_CASE("registry entry flags", M) {
MAKE_PACKAGE
Registry reg;
reg.push(&ver);
const Registry::Entry &entry = reg.getEntry(&pkg);
- REQUIRE_FALSE(entry.pinned);
+ REQUIRE(entry.flags == 0);
- reg.setPinned(entry, true);
- REQUIRE(reg.getEntry(&pkg).pinned);
- REQUIRE(reg.getEntries(ri.name())[0].pinned);
+ reg.setFlags(entry, 2);
+ REQUIRE(reg.getEntry(&pkg).flags == 2);
+ REQUIRE(reg.getEntries(ri.name())[0].flags == 2);
- reg.setPinned(entry, false);
- REQUIRE_FALSE(reg.getEntry(&pkg).pinned);
+ reg.setFlags(entry, 0);
+ REQUIRE(reg.getEntry(&pkg).flags == 0);
}
TEST_CASE("get file owner", M) {