diff options
Diffstat (limited to 'mmc_updater/src/main.cpp')
-rw-r--r-- | mmc_updater/src/main.cpp | 201 |
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 |