1 /*********
2 *
3 * This file is part of BibleTime's source code, http://www.bibletime.info/.
4 *
5 * Copyright 1999-2016 by the BibleTime developers.
6 * The BibleTime source code is licensed under the GNU General Public License version 2.0.
7 *
8 **********/
9
10 #include "btinstallthread.h"
11
12 #include <memory>
13 #include <QDebug>
14 #include <QDir>
15 #include <QString>
16 #include <QThread>
17 #include "btinstallbackend.h"
18 #include "managers/cswordbackend.h"
19
20 // Sword includes:
21 #include <filemgr.h>
22
23
24 namespace {
25
runMkdir(QDir & dir,const QString & dirName)26 inline bool runMkdir(QDir & dir, const QString & dirName) {
27 if (!dir.exists(dirName)) {
28 if (!dir.mkpath(dirName)) {
29 qDebug() << "failed to make directory" << dirName;
30 return false;
31 }
32 qDebug() << "made directory" << dirName;
33 }
34 return true;
35 }
36
37 }
38
run()39 void BtInstallThread::run() {
40 // Make sure target/mods.d and target/modules exist
41 /// \todo move this to some common precondition
42 QDir dir(m_destination);
43 if (!runMkdir(dir, m_destination)
44 || !runMkdir(dir, "modules")
45 || !runMkdir(dir, "mods.d"))
46 {
47 return;
48 }
49
50 for (m_currentModuleIndex = 0;
51 m_currentModuleIndex < m_modules.size();
52 ++m_currentModuleIndex)
53 {
54 installModule();
55 if (m_stopRequested.load(std::memory_order_relaxed))
56 break;
57 }
58 }
59
installModule()60 void BtInstallThread::installModule() {
61 emit preparingInstall(m_currentModuleIndex);
62
63 const CSwordModuleInfo * const module = m_modules.at(m_currentModuleIndex);
64
65 QVariant vModuleName = module->property("installSourceName");
66 QString moduleName = vModuleName.toString();
67 sword::InstallSource installSource = BtInstallBackend::source(moduleName);
68 std::unique_ptr<CSwordBackend> backendForSource(BtInstallBackend::backend(installSource));
69
70 // Check whether it's an update. If yes, remove existing module first:
71 /// \todo silently removing without undo if the user cancels the update is WRONG!!!
72 if (!removeModule() && m_stopRequested.load(std::memory_order_relaxed))
73 return;
74
75 // manager for the destination path
76 sword::SWMgr lMgr(m_destination.toLatin1());
77 if (BtInstallBackend::isRemote(installSource)) {
78 int status = m_iMgr.installModule(&lMgr,
79 nullptr,
80 module->name().toLatin1(),
81 &installSource);
82 if (status == 0) {
83 emit statusUpdated(m_currentModuleIndex, 100);
84 } else {
85 qWarning() << "Error with install: " << status
86 << "module:" << module->name();
87 }
88 emit installCompleted(m_currentModuleIndex, status == 0);
89 } else { // Local source
90 int status = m_iMgr.installModule(&lMgr,
91 installSource.directory.c_str(),
92 module->name().toLatin1());
93 if (status == 0) {
94 emit statusUpdated(m_currentModuleIndex, 100);
95 } else if (status != -1) {
96 qWarning() << "Error with install: " << status
97 << "module:" << module->name();
98 }
99 emit installCompleted(m_currentModuleIndex, status == 0);
100 }
101 }
102
slotManagerStatusUpdated(int totalProgress,int)103 void BtInstallThread::slotManagerStatusUpdated(int totalProgress, int /*fileProgress*/) {
104 emit statusUpdated(m_currentModuleIndex, totalProgress);
105 }
106
slotDownloadStarted()107 void BtInstallThread::slotDownloadStarted() {
108 emit downloadStarted(m_currentModuleIndex);
109 }
110
removeModule()111 bool BtInstallThread::removeModule() {
112 CSwordModuleInfo * const installedModule = m_modules.at(m_currentModuleIndex);
113 CSwordModuleInfo * m = CSwordBackend::instance()->findModuleByName(installedModule->name());
114 if (!m)
115 m = BtInstallBackend::backend(BtInstallBackend::source(m_destination.toLatin1()))->findModuleByName(installedModule->name());
116
117 if (!m)
118 return false;
119
120 qDebug() << "Removing module" << installedModule->name();
121 QString prefixPath = m->config(CSwordModuleInfo::AbsoluteDataPath) + "/";
122 QString dataPath = m->config(CSwordModuleInfo::DataPath);
123 if (dataPath.left(2) == "./")
124 dataPath = dataPath.mid(2);
125
126 if (prefixPath.contains(dataPath)) {
127 prefixPath.remove(prefixPath.indexOf(dataPath), dataPath.length());
128 } else {
129 prefixPath = QString::fromLatin1(CSwordBackend::instance()->prefixPath);
130 }
131
132 sword::SWMgr mgr(prefixPath.toLatin1());
133 BtInstallMgr().removeModule(&mgr, m->name().toLatin1());
134 return true;
135 }
136