summaryrefslogtreecommitdiff
path: root/utilities/installmgr.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'utilities/installmgr.cpp')
-rw-r--r--utilities/installmgr.cpp412
1 files changed, 412 insertions, 0 deletions
diff --git a/utilities/installmgr.cpp b/utilities/installmgr.cpp
new file mode 100644
index 0000000..37c15c7
--- /dev/null
+++ b/utilities/installmgr.cpp
@@ -0,0 +1,412 @@
+/******************************************************************************
+ *
+ * installmgr.cpp - commandline InstallMgr utility
+ *
+ * $Id: installmgr.cpp 2932 2013-07-31 14:07:01Z scribe $
+ *
+ * Copyright 2003-2013 CrossWire Bible Society (http://www.crosswire.org)
+ * CrossWire Bible Society
+ * P. O. Box 2528
+ * Tempe, AZ 85280-2528
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ */
+
+#ifdef _MSC_VER
+ #pragma warning( disable: 4251 )
+#endif
+
+#include <swmgr.h>
+#include <installmgr.h>
+#include <remotetrans.h>
+#include <filemgr.h>
+#include <iostream>
+#include <map>
+#include <swmodule.h>
+#include <stdio.h>
+#include <swlog.h>
+
+using namespace sword;
+using std::cout;
+using std::cerr;
+using std::cin;
+using std::map;
+
+
+SWMgr *mgr = 0;
+InstallMgr *installMgr = 0;
+StatusReporter *statusReporter = 0;
+SWBuf baseDir;
+SWBuf confPath;
+
+void usage(const char *progName = 0, const char *error = 0);
+
+class MyInstallMgr : public InstallMgr {
+public:
+ MyInstallMgr(const char *privatePath = "./", StatusReporter *sr = 0) : InstallMgr(privatePath, sr) {}
+
+virtual bool isUserDisclaimerConfirmed() const {
+ static bool confirmed = false;
+ if (!confirmed) {
+ cout << "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n";
+ cout << " -=+* WARNING *+=- -=+* WARNING *+=-\n\n\n";
+ cout << "Although Install Manager provides a convenient way for installing\n";
+ cout << "and upgrading SWORD components, it also uses a systematic method\n";
+ cout << "for accessing sites which gives packet sniffers a target to lock\n";
+ cout << "into for singling out users. \n\n\n";
+ cout << "IF YOU LIVE IN A PERSECUTED COUNTRY AND DO NOT WISH TO RISK DETECTION,\n";
+ cout << "YOU SHOULD *NOT* USE INSTALL MANAGER'S REMOTE SOURCE FEATURES.\n\n\n";
+ cout << "Also, Remote Sources other than CrossWire may contain less than\n";
+ cout << "quality modules, modules with unorthodox content, or even modules\n";
+ cout << "which are not legitimately distributable. Many repositories\n";
+ cout << "contain wonderfully useful content. These repositories simply\n";
+ cout << "are not reviewed or maintained by CrossWire and CrossWire\n";
+ cout << "cannot be held responsible for their content. CAVEAT EMPTOR.\n\n\n";
+ cout << "If you understand this and are willing to enable remote source features\n";
+ cout << "then type yes at the prompt\n\n";
+ cout << "enable? [no] ";
+
+ char prompt[10], *c;
+ c = fgets(prompt, 9, stdin);
+ if (c == NULL)
+ std::cerr <<"ERROR: fgets failed in isUserDisclaimerConfirmed\n";
+ confirmed = (!strcmp(prompt, "yes\n"));
+ cout << "\n";
+ }
+ return confirmed;
+}
+
+};
+
+class MyStatusReporter : public StatusReporter {
+ int last;
+ virtual void update(unsigned long totalBytes, unsigned long completedBytes) {
+ int p = (totalBytes > 0) ? (int)(74.0 * ((double)completedBytes / (double)totalBytes)) : 0;
+ for (;last < p; ++last) {
+ if (!last) {
+ SWBuf output;
+ output.setFormatted("[ File Bytes: %ld", totalBytes);
+ while (output.size() < 75) output += " ";
+ output += "]";
+ cout << output.c_str() << "\n ";
+ }
+ cout << "-";
+ }
+ cout.flush();
+ }
+ virtual void preStatus(long totalBytes, long completedBytes, const char *message) {
+ SWBuf output;
+ output.setFormatted("[ Total Bytes: %ld; Completed Bytes: %ld", totalBytes, completedBytes);
+ while (output.size() < 75) output += " ";
+ output += "]";
+ cout << "\n" << output.c_str() << "\n ";
+ int p = (int)(74.0 * (double)completedBytes/totalBytes);
+ for (int i = 0; i < p; ++i) { cout << "="; }
+ cout << "\n\n" << message << "\n";
+ last = 0;
+ }
+};
+
+
+void init() {
+ if (!mgr) {
+ mgr = new SWMgr();
+
+ if (!mgr->config)
+ usage(0, "ERROR: SWORD configuration not found. Please configure SWORD before using this program.");
+
+ SWBuf baseDir = mgr->getHomeDir();
+ if (baseDir.length() < 1) baseDir = ".";
+ baseDir += "/.sword/InstallMgr";
+ confPath = baseDir + "/InstallMgr.conf";
+ statusReporter = new MyStatusReporter();
+ installMgr = new MyInstallMgr(baseDir, statusReporter);
+ }
+}
+
+
+// clean up and exit if status is 0 or negative error code
+void finish(int status) {
+ delete statusReporter;
+ delete installMgr;
+ delete mgr;
+
+ installMgr = 0;
+ mgr = 0;
+
+ if (status < 1) {
+ cout << "\n";
+ exit(status);
+ }
+}
+
+
+void createBasicConfig(bool enableRemote, bool addCrossWire) {
+
+ FileMgr::createParent(confPath.c_str());
+ remove(confPath.c_str());
+
+ InstallSource is("FTP");
+ is.caption = "CrossWire";
+ is.source = "ftp.crosswire.org";
+ is.directory = "/pub/sword/raw";
+
+ SWConfig config(confPath.c_str());
+ config["General"]["PassiveFTP"] = "true";
+ if (enableRemote) {
+ config["Sources"]["FTPSource"] = is.getConfEnt();
+ }
+ config.Save();
+}
+
+
+void initConfig() {
+ init();
+
+ bool enable = installMgr->isUserDisclaimerConfirmed();
+
+ createBasicConfig(enable, true);
+
+ cout << "\n\nInitialized basic config file at [" << confPath << "]\n";
+ cout << "with remote source features " << ((enable) ? "ENABLED" : "DISABLED") << "\n";
+}
+
+
+void syncConfig() {
+ init();
+
+ if (!installMgr->isUserDisclaimerConfirmed()) { // assert disclaimer is accepted
+ cout << "\n\nDisclaimer not accepted. Aborting.";
+ return;
+ }
+
+ // be sure we have at least some config file already out there
+ if (!FileMgr::existsFile(confPath.c_str())) {
+ createBasicConfig(true, false);
+ finish(1); // cleanup and don't exit
+ init(); // re-init with InstallMgr which uses our new config
+ }
+
+ if (!installMgr->refreshRemoteSourceConfiguration())
+ cout << "\nSync'd config file with master remote source list.\n";
+ else cout << "\nFailed to sync config file with master remote source list.\n";
+}
+
+
+void uninstallModule(const char *modName) {
+ init();
+ SWModule *module;
+ ModMap::iterator it = mgr->Modules.find(modName);
+ if (it == mgr->Modules.end()) {
+ fprintf(stderr, "Couldn't find module [%s] to remove\n", modName);
+ finish(-2);
+ }
+ module = it->second;
+ installMgr->removeModule(mgr, module->getName());
+ cout << "Removed module: [" << modName << "]\n";
+}
+
+
+void listRemoteSources() {
+ init();
+ cout << "Remote Sources:\n\n";
+ for (InstallSourceMap::iterator it = installMgr->sources.begin(); it != installMgr->sources.end(); it++) {
+ cout << "[" << it->second->caption << "]\n";
+ cout << "\tType : " << it->second->type << "\n";
+ cout << "\tSource : " << it->second->source << "\n";
+ cout << "\tDirectory: " << it->second->directory << "\n";
+ }
+}
+
+
+void refreshRemoteSource(const char *sourceName) {
+ init();
+ InstallSourceMap::iterator source = installMgr->sources.find(sourceName);
+ if (source == installMgr->sources.end()) {
+ fprintf(stderr, "Couldn't find remote source [%s]\n", sourceName);
+ finish(-3);
+ }
+
+ if (!installMgr->refreshRemoteSource(source->second))
+ cout << "\nRemote Source Refreshed\n";
+ else cerr << "\nError Refreshing Remote Source\n";
+}
+
+
+void listModules(SWMgr *otherMgr = 0, bool onlyNewAndUpdates = false) {
+ init();
+ SWModule *module;
+ if (!otherMgr) otherMgr = mgr;
+ std::map<SWModule *, int> mods = InstallMgr::getModuleStatus(*mgr, *otherMgr);
+ for (std::map<SWModule *, int>::iterator it = mods.begin(); it != mods.end(); it++) {
+ module = it->first;
+ SWBuf version = module->getConfigEntry("Version");
+ SWBuf status = " ";
+ if (it->second & InstallMgr::MODSTAT_NEW) status = "*";
+ if (it->second & InstallMgr::MODSTAT_OLDER) status = "-";
+ if (it->second & InstallMgr::MODSTAT_UPDATED) status = "+";
+
+ if (!onlyNewAndUpdates || status == "*" || status == "+") {
+ cout << status << "[" << module->getName() << "] \t(" << version << ") \t- " << module->getDescription() << "\n";
+ }
+ }
+}
+
+
+void remoteListModules(const char *sourceName, bool onlyNewAndUpdated = false) {
+ init();
+ cout << "Available Modules:\n(be sure to refresh remote source (-r) first for most current list)\n\n";
+ InstallSourceMap::iterator source = installMgr->sources.find(sourceName);
+ if (source == installMgr->sources.end()) {
+ fprintf(stderr, "Couldn't find remote source [%s]\n", sourceName);
+ finish(-3);
+ }
+ listModules(source->second->getMgr(), onlyNewAndUpdated);
+}
+
+
+void localDirListModules(const char *dir) {
+ cout << "Available Modules:\n\n";
+ SWMgr mgr(dir);
+ listModules(&mgr);
+}
+
+
+void remoteInstallModule(const char *sourceName, const char *modName) {
+ init();
+ InstallSourceMap::iterator source = installMgr->sources.find(sourceName);
+ if (source == installMgr->sources.end()) {
+ fprintf(stderr, "Couldn't find remote source [%s]\n", sourceName);
+ finish(-3);
+ }
+ InstallSource *is = source->second;
+ SWMgr *rmgr = is->getMgr();
+ SWModule *module;
+ ModMap::iterator it = rmgr->Modules.find(modName);
+ if (it == rmgr->Modules.end()) {
+ fprintf(stderr, "Remote source [%s] does not make available module [%s]\n", sourceName, modName);
+ finish(-4);
+ }
+ module = it->second;
+
+ int error = installMgr->installModule(mgr, 0, module->getName(), is);
+ if (error) {
+ cout << "\nError installing module: [" << module->getName() << "] (write permissions?)\n";
+ } else cout << "\nInstalled module: [" << module->getName() << "]\n";
+}
+
+
+void localDirInstallModule(const char *dir, const char *modName) {
+ init();
+ SWMgr lmgr(dir);
+ SWModule *module;
+ ModMap::iterator it = lmgr.Modules.find(modName);
+ if (it == lmgr.Modules.end()) {
+ fprintf(stderr, "Module [%s] not available at path [%s]\n", modName, dir);
+ finish(-4);
+ }
+ module = it->second;
+ int error = installMgr->installModule(mgr, dir, module->getName());
+ if (error) {
+ cout << "\nError installing module: [" << module->getName() << "] (write permissions?)\n";
+ } else cout << "\nInstalled module: [" << module->getName() << "]\n";
+}
+
+
+void usage(const char *progName, const char *error) {
+
+ if (error) fprintf(stderr, "\n%s: %s\n", (progName ? progName : "installmgr"), error);
+
+ fprintf(stderr, "\nusage: %s <command> [command ...]\n"
+ "\n Commands (run in order they are passed):\n\n"
+ "\t-init\t\t\t\tcreate a basic user config file.\n"
+ "\t\t\t\t\t\tWARNING: overwrites existing.\n"
+ "\t-sc\t\t\t\tsync config with known remote repo list\n"
+ "\t\t\t\t\t\tNOTE: also creates if none exists\n"
+ "\t-s\t\t\t\tlist remote sources\n"
+ "\t-r <remoteSrcName>\t\trefresh remote source\n"
+ "\t-rl <remoteSrcName>\t\tlist available modules from remote source\n"
+ "\t-rd <remoteSrcName>\t\tlist new/updated modules from remote source\n"
+ "\t-ri <remoteSrcName> <modName>\tinstall module from remote source\n"
+ "\t-l\t\t\t\tlist installed modules\n"
+ "\t-u <modName>\t\t\tuninstall module\n"
+ "\t-ll <path>\t\t\tlist available modules at local path\n"
+ "\t-li <path> <modName>\t\tinstall module from local path\n"
+ "\t-d\t\t\t\tturn debug output on\n"
+ , (progName ? progName : "installmgr"));
+ finish(-1);
+}
+
+
+int main(int argc, char **argv) {
+
+ if (argc < 2) usage(*argv);
+
+ for (int i = 1; i < argc; i++) {
+ if (!strcmp(argv[i], "-d")) {
+ SWLog::getSystemLog()->setLogLevel(SWLog::LOG_DEBUG);
+ }
+ else if (!strcmp(argv[i], "-init")) {
+ initConfig();
+ }
+ else if (!strcmp(argv[i], "-l")) { // list installed modules
+ cout << "Installed Modules:\n\n";
+ listModules();
+ }
+ else if (!strcmp(argv[i], "-ll")) { // list from local directory
+ if (i+1 < argc) localDirListModules(argv[++i]);
+ else usage(*argv, "-ll requires <path>");
+ }
+ else if (!strcmp(argv[i], "-li")) { // install from local directory
+ if (i+2 < argc) {
+ const char *path = argv[++i];
+ const char *modName = argv[++i];
+ localDirInstallModule(path, modName);
+ }
+ else usage(*argv, "-li requires <path> <modName>");
+ }
+ else if (!strcmp(argv[i], "-u")) { // uninstall module
+ if (i+1 < argc) uninstallModule(argv[++i]);
+ else usage(*argv, "-u requires <modName>");
+ }
+ else if (!strcmp(argv[i], "-s")) { // list sources
+ listRemoteSources();
+ }
+ else if (!strcmp(argv[i], "-sc")) { // sync config with master
+ syncConfig();
+ }
+ else if (!strcmp(argv[i], "-r")) { // refresh remote source
+ if (i+1 < argc) refreshRemoteSource(argv[++i]);
+ else usage(*argv, "-r requires <remoteSrcName>");
+ }
+ else if (!strcmp(argv[i], "-rl")) { // list remote modules
+ if (i+1 < argc) remoteListModules(argv[++i]);
+ else usage(*argv, "-rl requires <remoteSrcName>");
+ }
+ else if (!strcmp(argv[i], "-rd")) { // list differences between remote source and installed modules
+ if (i+1 < argc) remoteListModules(argv[++i], true);
+ else usage(*argv, "-rd requires <remoteSrcName>");
+ }
+ else if (!strcmp(argv[i], "-ri")) { // install from remote directory
+ if (i+2 < argc) {
+ const char *source = argv[++i];
+ const char *modName = argv[++i];
+ remoteInstallModule(source, modName);
+ }
+ else usage(*argv, "-ri requires <remoteSrcName> <modName>");
+ }
+ else usage(*argv, (((SWBuf)"Unknown argument: ")+ argv[i]).c_str());
+ }
+
+ finish(0);
+
+ return 0;
+}