pollymc/mmc_updater/src/main.cpp
Petr Mrázek 0dcf694c87 More updater fixage
Preserve --dir parameter after updating
Allow more than one copy of a command line parameter in MultiMC
Linux runner script no longer changes current directory, which allows '--dir .'
Fixed unit tests, removed the obsolete one (for some legacy updater command line params that were also removed)
[fixes 63127704]
2014-01-05 16:47:12 +01:00

207 lines
5.1 KiB
C++

#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)
+ ", finish-cmd: " + options.finishCmd
+ ", finish-dir: " + options.finishDir);
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);
installer.setFinishCmd(options.finishCmd);
installer.setFinishDir(options.finishDir);
installer.setDryRun(options.dryRun);
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