commit f94f80c7bcc5e7db9dba8ae590f7dd87a12365a9
parent 0e6a47df9bbb962e0bcf65ad49fe477bce1c51c7
Author: cfillion <cfillion@users.noreply.github.com>
Date: Mon, 5 Jun 2017 23:43:23 -0400
Merge branch 'multi-import'
Diffstat:
12 files changed, 196 insertions(+), 143 deletions(-)
diff --git a/src/api.cpp b/src/api.cpp
@@ -327,8 +327,8 @@ autoInstall: usually set to 2 (obey user setting).)",
reapack->setRemoteEnabled(enable, existing);
}
-
- reapack->config()->remotes.add(remote);
+ else
+ reapack->config()->remotes.add(remote);
}
catch(const reapack_error &e) {
if(errorOut)
@@ -341,16 +341,8 @@ autoInstall: usually set to 2 (obey user setting).)",
return false;
}
- if(commit) {
- if(reapack->hasTransaction())
- reapack->setupTransaction()->runTasks();
- else {
- reapack->refreshManager();
- reapack->refreshBrowser();
- }
-
- reapack->config()->write();
- }
+ if(commit)
+ reapack->commitConfig();
return true;
});
diff --git a/src/archive.cpp b/src/archive.cpp
@@ -222,8 +222,6 @@ FileExtractor::FileExtractor(const Path &target, const ArchiveReaderPtr &reader)
bool FileExtractor::run()
{
- ThreadNotifier::get()->notify({this, Running});
-
ofstream stream;
if(!FS::open(stream, m_path.temp())) {
setError({FS::lastError(), m_path.temp().join()});
@@ -360,8 +358,6 @@ FileCompressor::FileCompressor(const Path &target, const ArchiveWriterPtr &write
bool FileCompressor::run()
{
- ThreadNotifier::get()->notify({this, Running});
-
ifstream stream;
if(!FS::open(stream, m_path)) {
setError({FS::lastError(), m_path.join()});
diff --git a/src/download.cpp b/src/download.cpp
@@ -115,8 +115,6 @@ void Download::setName(const string &name)
bool Download::run()
{
- ThreadNotifier::get()->notify({this, Running});
-
ostream *stream = openStream();
if(!stream)
return false;
diff --git a/src/encoding.hpp b/src/encoding.hpp
@@ -47,9 +47,9 @@ typedef std::string auto_string;
#define AUTO_STR(text) text
#define to_autostring std::to_string
#define auto_snprintf snprintf
-#define make_autostring(string) string
+#define make_autostring(string) (string)
#define make_autocstring(cstr) cstr
-#define from_autostring(string) string
+#define from_autostring(string) (string)
#endif
diff --git a/src/import.cpp b/src/import.cpp
@@ -31,11 +31,11 @@
using namespace std;
-static const auto_char *TITLE = AUTO_STR("ReaPack: Import a repository");
+static const auto_char *TITLE = AUTO_STR("ReaPack: Import repositories");
static const string DISCOVER_URL = "https://reapack.com/repos";
Import::Import(ReaPack *reapack)
- : Dialog(IDD_IMPORT_DIALOG), m_reapack(reapack), m_download(nullptr)
+ : Dialog(IDD_IMPORT_DIALOG), m_reapack(reapack), m_pool(nullptr), m_state(OK)
{
}
@@ -48,7 +48,6 @@ void Import::onInit()
m_url = getControl(IDC_URL);
m_progress = getControl(IDC_PROGRESS);
m_discover = getControl(IDC_DISCOVER);
- m_ok = getControl(IDOK);
#ifdef PBM_SETMARQUEE
SendMessage(m_progress, PBM_SETMARQUEE, 1, 0);
@@ -65,10 +64,14 @@ void Import::onCommand(const int id, int)
openURL(DISCOVER_URL);
break;
case IDCANCEL:
- if(m_download)
- m_download->abort();
-
- close();
+ if(m_pool) {
+ disable(getControl(IDOK));
+ disable(getControl(IDCANCEL));
+ m_pool->abort();
+ m_state = Close;
+ }
+ else
+ close();
break;
}
}
@@ -81,133 +84,170 @@ void Import::onTimer(int)
#endif
}
-void Import::fetch()
+ThreadPool *Import::setupPool()
{
- if(m_download)
- return;
+ if(!m_pool) {
+ m_state = OK;
+ m_pool = new ThreadPool;
- string url = getText(m_url);
- boost::algorithm::trim(url);
+ m_pool->onAbort([=] { if(!m_state) m_state = Aborted; });
+ m_pool->onDone([=] {
+ setWaiting(false);
- if(url.empty()) {
- close();
- return;
- }
+ if(m_state == OK)
+ processQueue();
- setWaiting(true);
+ queue<ImportData> clear;
+ m_queue.swap(clear);
- const auto &opts = m_reapack->config()->network;
- MemoryDownload *dl = m_download = new MemoryDownload(url, opts);
-
- dl->onFinish([=] {
- const ThreadTask::State state = dl->state();
- if(state == ThreadTask::Aborted) {
- // at this point `this` is deleted, so there is nothing else
- // we can do without crashing
- return;
- }
+ delete m_pool;
+ m_pool = nullptr;
- setWaiting(false);
+ if(m_state == Close)
+ close();
+ else
+ SetFocus(m_url);
+ });
+ }
- if(state != ThreadTask::Success) {
- const string msg = "Download failed: " + dl->error().message;
- MessageBox(handle(), make_autostring(msg).c_str(), TITLE, MB_OK);
- SetFocus(m_url);
- return;
- }
+ return m_pool;
+}
- read();
- });
+void Import::fetch()
+{
+ if(m_pool) // ignore repeated presses on OK
+ return;
- dl->setCleanupHandler([=] {
- // if we are still alive
- if(dl->state() != ThreadTask::Aborted)
- m_download = nullptr;
+ const auto &opts = m_reapack->config()->network;
- delete dl;
- });
+ stringstream stream(getText(m_url));
+ string url;
+ while(getline(stream, url)) {
+ boost::algorithm::trim(url);
+
+ if(url.empty())
+ continue;
+
+ MemoryDownload *dl = new MemoryDownload(url, opts);
+
+ dl->onFinish([=] {
+ switch(dl->state()) {
+ case ThreadTask::Success:
+ // copy for later use, as `dl` won't be around after this callback
+ if(!read(dl))
+ m_pool->abort();
+ break;
+ case ThreadTask::Failure: {
+ auto_char msg[1024];
+ auto_snprintf(msg, auto_size(msg),
+ AUTO_STR("Download failed: %s\r\n\r\nURL: %s"),
+ make_autostring(dl->error().message).c_str(), make_autostring(url).c_str());
+ MessageBox(handle(), msg, TITLE, MB_OK);
+ m_pool->abort();
+ break;
+ }
+ default:
+ break;
+ }
+ });
+
+ setupPool()->push(dl);
+ }
- dl->start();
+ if(m_pool)
+ setWaiting(true);
+ else
+ close();
}
-void Import::read()
+bool Import::read(MemoryDownload *dl)
{
- assert(m_download);
+ auto_char msg[1024];
try {
- IndexPtr index = Index::load({}, m_download->contents().c_str());
- close(import({index->name(), m_download->url()}));
+ IndexPtr index = Index::load({}, dl->contents().c_str());
+ Remote remote = m_reapack->remote(index->name());
+ const bool exists = !remote.isNull();
+
+ if(exists && remote.url() != dl->url()) {
+ if(remote.isProtected()) {
+ auto_snprintf(msg, auto_size(msg),
+ AUTO_STR("The repository %s is protected and cannot be overwritten."),
+ make_autostring(index->name()).c_str());
+ MessageBox(handle(), msg, TITLE, MB_OK);
+ return false;
+ }
+ else {
+ auto_snprintf(msg, auto_size(msg),
+ AUTO_STR("%s is already configured with a different URL.\r\n")
+ AUTO_STR("Do you want to overwrite it?"),
+ make_autostring(index->name()).c_str());
+
+ const auto answer = MessageBox(handle(), msg, TITLE, MB_YESNO);
+
+ if(answer != IDYES)
+ return true;
+ }
+ }
+ else if(exists && remote.isEnabled()) // url is also the same
+ return true; // nothing to do
+
+ remote.setName(index->name());
+ remote.setUrl(dl->url());
+ m_queue.push({remote, dl->contents()});
+
+ return true;
}
catch(const reapack_error &e) {
- const string msg = "The received file is invalid: " + string(e.what());
- MessageBox(handle(), make_autostring(msg).c_str(), TITLE, MB_OK);
- SetFocus(m_url);
+ auto_snprintf(msg, auto_size(msg),
+ AUTO_STR("The received file is invalid: %s\r\n%s"),
+ make_autostring(string(e.what())).c_str(),
+ make_autostring(dl->url()).c_str());
+ MessageBox(handle(), msg, TITLE, MB_OK);
+ return false;
}
}
-bool Import::import(const Remote &remote)
+void Import::processQueue()
{
- auto_char msg[1024];
+ bool ok = true;
- if(const Remote &existing = m_reapack->remote(remote.name())) {
- if(existing.isProtected()) {
- MessageBox(handle(),
- AUTO_STR("This repository is protected and cannot be overwritten."),
- TITLE, MB_OK);
+ while(!m_queue.empty()) {
+ if(!import(m_queue.front()))
+ ok = false;
- return true;
- }
- else if(existing.url() != remote.url()) {
- auto_snprintf(msg, auto_size(msg),
- AUTO_STR("%s is already configured with a different URL.\r\n")
- AUTO_STR("Do you want to overwrite it?"),
- make_autostring(remote.name()).c_str());
+ m_queue.pop();
+ }
- const auto answer = MessageBox(handle(), msg, TITLE, MB_YESNO);
+ if(ok)
+ m_state = Close;
- if(answer != IDYES)
- return false;
- }
- else if(existing.isEnabled()) {
- auto_snprintf(msg, auto_size(msg),
- AUTO_STR("%s is already configured.\r\nNothing to do!"),
- make_autostring(remote.name()).c_str());
- MessageBox(handle(), msg, TITLE, MB_OK);
+ m_reapack->commitConfig();
+}
+bool Import::import(const ImportData &data)
+{
+ if(!data.remote.isEnabled()) {
+ if(Transaction *tx = m_reapack->setupTransaction()) {
+ m_reapack->enable(data.remote);
+ tx->synchronize(data.remote);
return true;
}
- else {
- Transaction *tx = m_reapack->setupTransaction();
-
- if(!tx)
- return true;
-
- m_reapack->enable(existing);
- tx->runTasks();
-
- m_reapack->config()->write();
+ else
+ return false;
+ }
- auto_snprintf(msg, auto_size(msg), AUTO_STR("%s has been enabled."),
- make_autostring(remote.name()).c_str());
- MessageBox(handle(), msg, TITLE, MB_OK);
+ Config *config = m_reapack->config();
+ config->remotes.add(data.remote);
+ if(config->install.autoInstall) {
+ if(Transaction *tx = m_reapack->setupTransaction()) {
+ tx->synchronize(data.remote);
return true;
}
}
- Config *config = m_reapack->config();
- config->remotes.add(remote);
- config->write();
-
- FS::write(Index::pathFor(remote.name()), m_download->contents());
-
- auto_snprintf(msg, auto_size(msg),
- AUTO_STR("%s has been successfully imported into your repository list."),
- make_autostring(remote.name()).c_str());
- MessageBox(handle(), msg, TITLE, MB_OK);
-
- m_reapack->refreshManager();
- m_reapack->refreshBrowser();
+ FS::write(Index::pathFor(data.remote.name()), data.contents);
return true;
}
diff --git a/src/import.hpp b/src/import.hpp
@@ -20,13 +20,14 @@
#include "dialog.hpp"
-#include "encoding.hpp"
+#include "remote.hpp"
+#include <queue>
#include <string>
class MemoryDownload;
class ReaPack;
-class Remote;
+class ThreadPool;
class Import : public Dialog
{
@@ -39,19 +40,30 @@ protected:
void onTimer(int) override;
private:
+ enum State {
+ OK,
+ Aborted,
+ Close,
+ };
+
+ struct ImportData { Remote remote; std::string contents; };
+
+ ThreadPool *setupPool();
void fetch();
- void read();
- bool import(const Remote &);
+ bool read(MemoryDownload *);
+ void processQueue();
+ bool import(const ImportData &);
void setWaiting(bool);
ReaPack *m_reapack;
- MemoryDownload *m_download;
+ ThreadPool *m_pool;
+ State m_state;
+ std::queue<ImportData> m_queue;
short m_fakePos;
HWND m_url;
HWND m_progress;
HWND m_discover;
- HWND m_ok;
};
#endif
diff --git a/src/main.cpp b/src/main.cpp
@@ -92,7 +92,7 @@ static void menuHook(const char *name, HMENU handle, int f)
menu.addAction(AUTO_STR("&Browse packages..."),
NamedCommandLookup("_REAPACK_BROWSE"));
- menu.addAction(AUTO_STR("&Import a repository..."),
+ menu.addAction(AUTO_STR("&Import repositories..."),
NamedCommandLookup("_REAPACK_IMPORT"));
menu.addAction(AUTO_STR("&Manage repositories..."),
@@ -149,7 +149,7 @@ static void setupActions()
reapack->setupAction("REAPACK_BROWSE", "ReaPack: Browse packages...",
&reapack->browseAction, bind(&ReaPack::browsePackages, reapack));
- reapack->setupAction("REAPACK_IMPORT", "ReaPack: Import a repository...",
+ reapack->setupAction("REAPACK_IMPORT", "ReaPack: Import repositories...",
&reapack->importAction, bind(&ReaPack::importRemote, reapack));
reapack->setupAction("REAPACK_MANAGE", "ReaPack: Manage repositories...",
diff --git a/src/manager.cpp b/src/manager.cpp
@@ -466,7 +466,7 @@ void Manager::copyUrl()
void Manager::importExport()
{
Menu menu;
- menu.addAction(AUTO_STR("Import a &repository..."), ACTION_IMPORT_REPO);
+ menu.addAction(AUTO_STR("Import &repositories..."), ACTION_IMPORT_REPO);
menu.addSeparator();
menu.addAction(AUTO_STR("Import offline archive..."), ACTION_IMPORT_ARCHIVE);
menu.addAction(AUTO_STR("&Export offline archive..."), ACTION_EXPORT_ARCHIVE);
@@ -692,8 +692,8 @@ bool Manager::apply()
if(syncAll)
m_reapack->synchronizeAll();
+ tx->onFinish(bind(&Config::write, m_config));
tx->runTasks();
- m_config->write();
reset();
return true;
diff --git a/src/reapack.cpp b/src/reapack.cpp
@@ -182,7 +182,6 @@ void ReaPack::setRemoteEnabled(const bool enable, const Remote &remote)
return;
m_config->remotes.add(copy);
- refreshManager();
});
}
@@ -331,7 +330,6 @@ Transaction *ReaPack::setupTransaction()
Dialog::Show<Report>(m_instance, m_mainWindow, *m_tx->receipt());
}
-
});
m_tx->setObsoleteHandler([=] (vector<Registry::Entry> &entries) {
@@ -358,6 +356,20 @@ void ReaPack::teardownTransaction()
refreshBrowser();
}
+void ReaPack::commitConfig()
+{
+ if(m_tx) {
+ m_tx->onFinish(bind(&ReaPack::refreshManager, this));
+ m_tx->onFinish(bind(&Config::write, m_config));
+ m_tx->runTasks();
+ }
+ else {
+ refreshManager();
+ refreshBrowser();
+ m_config->write();
+ }
+}
+
void ReaPack::refreshManager()
{
if(m_manager)
diff --git a/src/reapack.hpp b/src/reapack.hpp
@@ -77,8 +77,8 @@ public:
Remote remote(const std::string &name) const;
- bool hasTransaction() const { return m_tx != nullptr; }
Transaction *setupTransaction();
+ void commitConfig();
Config *config() const { return m_config; }
private:
diff --git a/src/resource.rc b/src/resource.rc
@@ -69,19 +69,20 @@ BEGIN
DEFPUSHBUTTON "&Close", IDOK, 409, 248, 45, 14
END
-IDD_IMPORT_DIALOG DIALOGEX 0, 0, 290, 69
+IDD_IMPORT_DIALOG DIALOGEX 0, 0, 290, 83
STYLE DIALOG_STYLE
FONT DIALOG_FONT
BEGIN
- GROUPBOX "Repository settings", IDC_GROUPBOX, 2, 4, 287, 41
- RTEXT "Index URL:", IDC_LABEL, 5, 19, 50, 10
- EDITTEXT IDC_URL, 60, 16, 220, 14, ES_AUTOHSCROLL
- LTEXT "Type or paste the URL to a repository index in the box above.",
- IDC_LABEL2, 60, 33, 220, 10
- CONTROL "", IDC_PROGRESS, PROGRESS_CLASS, PBS_MARQUEE | NOT WS_VISIBLE, 10, 54, 150, 5
- PUSHBUTTON "&Discover repositories...", IDC_DISCOVER, 5, 50, 90, 14
- DEFPUSHBUTTON "&OK", IDOK, 201, 50, 40, 14
- PUSHBUTTON "&Cancel", IDCANCEL, 244, 50, 40, 14
+ LTEXT "Type or paste one or more repository index URLs (one per line):",
+ IDC_LABEL, 5, 5, 280, 10
+#ifdef __APPLE__
+ GROUPBOX "", IDC_GROUPBOX, 3, 9, 284, 51
+#endif
+ EDITTEXT IDC_URL, 5, 18, 278, 40, WS_VSCROLL | ES_MULTILINE | ES_WANTRETURN
+ CONTROL "", IDC_PROGRESS, PROGRESS_CLASS, PBS_MARQUEE | NOT WS_VISIBLE, 10, 68, 150, 5
+ PUSHBUTTON "&Discover repositories...", IDC_DISCOVER, 5, 64, 90, 14
+ DEFPUSHBUTTON "&OK", IDOK, 201, 64, 40, 14
+ PUSHBUTTON "&Cancel", IDCANCEL, 244, 64, 40, 14
END
IDD_BROWSER_DIALOG DIALOGEX 0, 0, 500, 250
diff --git a/src/thread.cpp b/src/thread.cpp
@@ -68,8 +68,10 @@ void ThreadTask::exec()
{
State state = Aborted;
- if(!aborted())
+ if(!aborted()) {
+ ThreadNotifier::get()->notify({this, Running});
state = run() ? Success : Failure;
+ }
ThreadNotifier::get()->notify({this, state});
};