commit 2156cf690ae00e165bd063811432055005b79912
parent 14ccc6444ec29e73469e98b7477e2a30198b9751
Author: cfillion <cfillion@users.noreply.github.com>
Date: Sat, 12 Dec 2015 20:19:17 -0500
save downloaded files under a temporary name first
Diffstat:
5 files changed, 101 insertions(+), 9 deletions(-)
diff --git a/src/path.cpp b/src/path.cpp
@@ -20,6 +20,11 @@ void Path::append(const string &part)
m_parts.push_back(part);
}
+void Path::clear()
+{
+ m_parts.clear();
+}
+
string Path::basename() const
{
if(m_parts.empty())
@@ -74,3 +79,13 @@ Path Path::operator+(const Path &o) const
return path;
}
+
+string &Path::operator[](const size_t index)
+{
+ auto it = m_parts.begin();
+
+ for(size_t i = 0; i < index; i++)
+ it++;
+
+ return *it;
+}
diff --git a/src/path.hpp b/src/path.hpp
@@ -8,6 +8,7 @@ class Path {
public:
void prepend(const std::string &part);
void append(const std::string &part);
+ void clear();
bool empty() const { return m_parts.empty(); }
size_t size() const { return m_parts.size(); }
@@ -20,6 +21,7 @@ public:
bool operator!=(const Path &) const;
Path operator+(const std::string &) const;
Path operator+(const Path &) const;
+ std::string &operator[](const size_t index);
private:
std::string join(const bool) const;
diff --git a/src/transaction.cpp b/src/transaction.cpp
@@ -2,6 +2,7 @@
#include "errors.hpp"
+#include <cstdio>
#include <fstream>
#include <reaper_plugin_functions.h>
@@ -12,6 +13,7 @@ Transaction::Transaction(Registry *reg, const Path &root)
: m_registry(reg), m_root(root), m_isCancelled(false)
{
m_dbPath = m_root + "ReaPack";
+
RecursiveCreateDirectory(m_dbPath.join().c_str(), 0);
}
@@ -116,6 +118,10 @@ void Transaction::run()
void Transaction::cancel()
{
m_isCancelled = true;
+
+ for(PackageTransaction *tr : m_transactions)
+ tr->cancel();
+
m_queue.abort();
}
@@ -147,6 +153,11 @@ void Transaction::finish()
if(!m_queue.idle())
return;
+ if(!m_isCancelled) {
+ for(PackageTransaction *tr : m_transactions)
+ tr->apply();
+ }
+
m_onFinish();
}
@@ -155,6 +166,11 @@ void Transaction::addError(const string &message, const string &title)
m_errors.push_back({message, title});
}
+Path Transaction::prefixPath(const Path &input) const
+{
+ return m_root + input;
+}
+
bool PackageTransaction::isInstalled(Version *ver, const Path &root)
{
// TODO
@@ -163,7 +179,7 @@ bool PackageTransaction::isInstalled(Version *ver, const Path &root)
}
PackageTransaction::PackageTransaction(Transaction *transaction)
- : m_transaction(transaction), m_remaining(0)
+ : m_transaction(transaction), m_isCancelled(false)
{
}
@@ -190,10 +206,19 @@ void PackageTransaction::saveSource(Download *dl, Source *src)
{
m_remaining.erase(remove(m_remaining.begin(), m_remaining.end(), dl));
- const Path path = installPath(src);
+ if(m_isCancelled)
+ return;
+
+ const Path targetPath = src->targetPath();
+ Path tmpPath = targetPath;
+ tmpPath[tmpPath.size() - 1] += ".new";
+
+ m_files.push({tmpPath, targetPath});
+
+ const Path path = m_transaction->prefixPath(tmpPath);
if(!m_transaction->saveFile(dl, path)) {
- abort();
+ cancel();
return;
}
}
@@ -206,13 +231,39 @@ void PackageTransaction::finish()
m_onFinish();
}
-void PackageTransaction::abort()
+void PackageTransaction::cancel()
{
+ m_isCancelled = true;
+
for(Download *dl : m_remaining)
dl->abort();
+
+ rollback();
+}
+
+void PackageTransaction::apply()
+{
+ while(!m_files.empty()) {
+ const PathPair paths = m_files.front();
+ m_files.pop();
+
+ const string tempPath = m_transaction->prefixPath(paths.first).join();
+ const string targetPath = m_transaction->prefixPath(paths.second).join();
+
+ if(rename(tempPath.c_str(), targetPath.c_str()))
+ m_transaction->addError(strerror(errno), targetPath);
+ }
}
-Path PackageTransaction::installPath(Source *src) const
+void PackageTransaction::rollback()
{
- return m_transaction->m_root + src->targetPath();
+ while(!m_files.empty()) {
+ const PathPair paths = m_files.front();
+ m_files.pop();
+
+ const string tempPath = m_transaction->prefixPath(paths.first).join();
+
+ if(remove(tempPath.c_str()))
+ m_transaction->addError(strerror(errno), tempPath);
+ }
}
diff --git a/src/transaction.hpp b/src/transaction.hpp
@@ -8,6 +8,7 @@
#include "remote.hpp"
#include <boost/signals2.hpp>
+#include <queue>
class PackageTransaction;
@@ -53,6 +54,7 @@ private:
void saveDatabase(Download *);
bool saveFile(Download *, const Path &);
void addError(const std::string &msg, const std::string &title);
+ Path prefixPath(const Path &) const;
Registry *m_registry;
@@ -85,16 +87,21 @@ public:
void onFinish(const Callback &callback) { m_onFinish.connect(callback); }
void install(Version *ver);
- void abort();
+ void apply();
+ void cancel();
private:
- void saveSource(Download *, Source *);
- Path installPath(Source *) const;
+ typedef std::pair<Path, Path> PathPair;
void finish();
+ void rollback();
+
+ void saveSource(Download *, Source *);
Transaction *m_transaction;
+ bool m_isCancelled;
std::vector<Download *> m_remaining;
+ std::queue<PathPair> m_files;
Signal m_onFinish;
};
diff --git a/test/path.cpp b/test/path.cpp
@@ -78,3 +78,20 @@ TEST_CASE("empty components", M) {
REQUIRE(a.size() == 0);
}
+
+TEST_CASE("clear path", M) {
+ Path a;
+ a.append("test");
+
+ CHECK(a.size() == 1);
+ a.clear();
+ REQUIRE(a.size() == 0);
+}
+
+TEST_CASE("modify path", M) {
+ Path a;
+ a.append("hello");
+
+ a[0] = "world";
+ REQUIRE(a.join() == "world");
+}