0dcf694c87
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]
207 lines
5.1 KiB
C++
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
|