summaryrefslogtreecommitdiffstats
path: root/mmc_updater/src/main.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'mmc_updater/src/main.cpp')
-rw-r--r--mmc_updater/src/main.cpp201
1 files changed, 201 insertions, 0 deletions
diff --git a/mmc_updater/src/main.cpp b/mmc_updater/src/main.cpp
new file mode 100644
index 00000000..e23cf16d
--- /dev/null
+++ b/mmc_updater/src/main.cpp
@@ -0,0 +1,201 @@
+#include "AppInfo.h"
+#include "FileUtils.h"
+#include "Log.h"
+#include "Platform.h"
+#include "ProcessUtils.h"
+#include "StringUtils.h"
+#include "UpdateScript.h"
+#include "UpdaterOptions.h"
+
+#include <thread>
+
+#if defined(PLATFORM_LINUX)
+ #include "UpdateDialogGtkFactory.h"
+ #include "UpdateDialogAscii.h"
+#endif
+
+#if defined(PLATFORM_MAC)
+ #include "MacBundle.h"
+ #include "UpdateDialogCocoa.h"
+#endif
+
+#if defined(PLATFORM_WINDOWS)
+ #include "UpdateDialogWin32.h"
+#endif
+
+#include <iostream>
+#include <memory>
+
+#define UPDATER_VERSION "0.16"
+
+UpdateDialog* createUpdateDialog();
+
+void runUpdaterThread(void* arg)
+{
+#ifdef PLATFORM_MAC
+ // create an autorelease pool to free any temporary objects
+ // created by Cocoa whilst handling notifications from the UpdateInstaller
+ void* pool = UpdateDialogCocoa::createAutoreleasePool();
+#endif
+
+ try
+ {
+ UpdateInstaller* installer = static_cast<UpdateInstaller*>(arg);
+ installer->run();
+ }
+ catch (const std::exception& ex)
+ {
+ LOG(Error,"Unexpected exception " + std::string(ex.what()));
+ }
+
+#ifdef PLATFORM_MAC
+ UpdateDialogCocoa::releaseAutoreleasePool(pool);
+#endif
+}
+
+#ifdef PLATFORM_MAC
+extern unsigned char Info_plist[];
+extern unsigned int Info_plist_len;
+
+extern unsigned char mac_icns[];
+extern unsigned int mac_icns_len;
+
+bool unpackBundle(int argc, char** argv)
+{
+ MacBundle bundle(FileUtils::tempPath(),AppInfo::name());
+ std::string currentExePath = ProcessUtils::currentProcessPath();
+
+ if (currentExePath.find(bundle.bundlePath()) != std::string::npos)
+ {
+ // already running from a bundle
+ return false;
+ }
+ LOG(Info,"Creating bundle " + bundle.bundlePath());
+
+ // create a Mac app bundle
+ std::string plistContent(reinterpret_cast<const char*>(Info_plist),Info_plist_len);
+ std::string iconContent(reinterpret_cast<const char*>(mac_icns),mac_icns_len);
+ bundle.create(plistContent,iconContent,ProcessUtils::currentProcessPath());
+
+ std::list<std::string> args;
+ for (int i = 1; i < argc; i++)
+ {
+ args.push_back(argv[i]);
+ }
+ ProcessUtils::runSync(bundle.executablePath(),args);
+ return true;
+}
+#endif
+
+void setupConsole()
+{
+#ifdef PLATFORM_WINDOWS
+ // see http://stackoverflow.com/questions/587767/how-to-output-to-console-in-c-windows
+ // and http://www.libsdl.org/cgi/docwiki.cgi/FAQ_Console
+ AttachConsole(ATTACH_PARENT_PROCESS);
+ freopen( "CON", "w", stdout );
+ freopen( "CON", "w", stderr );
+#endif
+}
+
+int main(int argc, char** argv)
+{
+#ifdef PLATFORM_MAC
+ void* pool = UpdateDialogCocoa::createAutoreleasePool();
+#endif
+
+ Log::instance()->open(AppInfo::logFilePath());
+
+#ifdef PLATFORM_MAC
+ // when the updater is run for the first time, create a Mac app bundle
+ // and re-launch the application from the bundle. This permits
+ // setting up bundle properties (such as application icon)
+ if (unpackBundle(argc,argv))
+ {
+ return 0;
+ }
+#endif
+
+ UpdaterOptions options;
+ options.parse(argc,argv);
+ if (options.showVersion)
+ {
+ setupConsole();
+ std::cout << "Update installer version " << UPDATER_VERSION << std::endl;
+ return 0;
+ }
+
+ UpdateInstaller installer;
+ UpdateScript script;
+
+ if (!options.scriptPath.empty())
+ {
+ script.parse(FileUtils::makeAbsolute(options.scriptPath.c_str(),options.packageDir.c_str()));
+ }
+
+ LOG(Info,"started updater. install-dir: " + options.installDir
+ + ", package-dir: " + options.packageDir
+ + ", wait-pid: " + intToStr(options.waitPid)
+ + ", script-path: " + options.scriptPath
+ + ", mode: " + intToStr(options.mode));
+
+ installer.setMode(options.mode);
+ installer.setInstallDir(options.installDir);
+ installer.setPackageDir(options.packageDir);
+ installer.setScript(&script);
+ installer.setWaitPid(options.waitPid);
+ installer.setForceElevated(options.forceElevated);
+ installer.setAutoClose(options.autoClose);
+
+ if (options.mode == UpdateInstaller::Main)
+ {
+ LOG(Info, "Showing updater UI - auto close? " + intToStr(options.autoClose));
+ std::auto_ptr<UpdateDialog> dialog(createUpdateDialog());
+ dialog->setAutoClose(options.autoClose);
+ dialog->init(argc, argv);
+ installer.setObserver(dialog.get());
+ std::thread updaterThread(runUpdaterThread, &installer);
+ dialog->exec();
+ updaterThread.join();
+ }
+ else
+ {
+ installer.run();
+ }
+
+#ifdef PLATFORM_MAC
+ UpdateDialogCocoa::releaseAutoreleasePool(pool);
+#endif
+
+ return 0;
+}
+
+UpdateDialog* createUpdateDialog()
+{
+#if defined(PLATFORM_WINDOWS)
+ return new UpdateDialogWin32();
+#elif defined(PLATFORM_MAC)
+ return new UpdateDialogCocoa();
+#elif defined(PLATFORM_LINUX)
+ UpdateDialog* dialog = UpdateDialogGtkFactory::createDialog();
+ if (!dialog)
+ {
+ dialog = new UpdateDialogAscii();
+ }
+ return dialog;
+#endif
+}
+
+#ifdef PLATFORM_WINDOWS
+// application entry point under Windows
+int CALLBACK WinMain(HINSTANCE hInstance,
+ HINSTANCE hPrevInstance,
+ LPSTR lpCmdLine,
+ int nCmdShow)
+{
+ int argc = 0;
+ char** argv;
+ ProcessUtils::convertWindowsCommandLine(GetCommandLineW(),argc,argv);
+ return main(argc,argv);
+}
+#endif