mirror of
https://github.com/ultimatepp/ultimatepp.git
synced 2026-07-11 22:03:01 -06:00
Bazaar/Updater : added finer control of updater behaviour
git-svn-id: svn://ultimatepp.org/upp/trunk@3014 f0d560ea-af0d-0410-9eb7-867de7ffcac7
This commit is contained in:
parent
5e1d5ae6c8
commit
777fd2e0ba
2 changed files with 308 additions and 200 deletions
|
|
@ -63,7 +63,7 @@ Updater::Updater()
|
|||
|
||||
// get application name -- either from GetExeTitle() if in normal mode
|
||||
// or from environment if in superuser mode
|
||||
if(state != InsideUpdater)
|
||||
if(state != InsideUpdater && state != UninstallSucceeded)
|
||||
appName = GetExeTitle();
|
||||
else if(environ.Find("UPDATER_APPNAME") >= 0)
|
||||
appName = environ.Get("UPDATER_APPNAME");
|
||||
|
|
@ -122,6 +122,7 @@ void Updater::FailUpdate()
|
|||
break;
|
||||
|
||||
case Uninstall:
|
||||
environ.Add("UPDATER_APPNAME", appName);
|
||||
environ.Add("UPDATER_STATE", "UNINSTALLFAILED");
|
||||
break;
|
||||
|
||||
|
|
@ -144,6 +145,7 @@ void Updater::SucceedUpdate()
|
|||
break;
|
||||
|
||||
case Uninstall:
|
||||
environ.Add("UPDATER_APPNAME", appName);
|
||||
environ.Add("UPDATER_STATE", "UNINSTALLSUCCEEDED");
|
||||
break;
|
||||
|
||||
|
|
@ -159,6 +161,7 @@ void Updater::SucceedUpdate()
|
|||
// main updater proc inside normal mode
|
||||
// prepares environment, copy app in temporary folder
|
||||
// and restarts it in superuser mode
|
||||
// returns true if app must continue execution, false otherwise
|
||||
bool Updater::START_Updater(String const &operation)
|
||||
{
|
||||
// prepare environment for updating
|
||||
|
|
@ -184,63 +187,86 @@ bool Updater::START_Updater(String const &operation)
|
|||
// in temporary folder
|
||||
String tempName = GetTempFileName();
|
||||
if(!FileCopy(exePath, tempName))
|
||||
return false;
|
||||
return true;
|
||||
|
||||
#ifdef PLATFORM_POSIX
|
||||
// for posix, change temp file permission
|
||||
// allowing its execution and executes it as a superuser
|
||||
if(chmod(~tempName, 0755) != 0)
|
||||
return false;
|
||||
return true;
|
||||
|
||||
// note the -k to gksu -- it makes it preserve the environment
|
||||
String params = "-k -u root \"" + tempName + "\"";
|
||||
if(SysStart("gksu", params, environ) == -1)
|
||||
return false;
|
||||
return true;
|
||||
#else
|
||||
// for windows, simply execute the file
|
||||
if(SysStart(tempName, "", environ) == -1)
|
||||
return false;
|
||||
return true;
|
||||
#endif
|
||||
return true;
|
||||
// installer process is spawned correctly
|
||||
// main app must leave
|
||||
return false;
|
||||
}
|
||||
|
||||
// uninstall app
|
||||
void Updater::START_Uninstall(void)
|
||||
// returns true if app must continue execution, false otherwise
|
||||
bool Updater::START_Uninstall(void)
|
||||
{
|
||||
if(!START_Updater("UNINSTALL"))
|
||||
Exclamation(t_("Uninstall failed&Press OK to quit"));
|
||||
if(confirmUninstall && !PromptYesNo(t_("This will remove '") + appName + t_("' application&Continue ?")))
|
||||
{
|
||||
state = UninstallAborted;
|
||||
return true;
|
||||
}
|
||||
if(START_Updater("UNINSTALL"))
|
||||
{
|
||||
state = UninstallFailed;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// install app
|
||||
// returns true if app must continue execution, false otherwise
|
||||
bool Updater::START_Install(void)
|
||||
{
|
||||
if(!START_Updater("INSTALL"))
|
||||
return !PromptYesNo(t_("Install failed&Continue running the application?"));
|
||||
return true;
|
||||
if(confirmInstall && !PromptYesNo(t_("Install '") + appName + t_("' application?")))
|
||||
{
|
||||
state = InstallAborted;
|
||||
return true;
|
||||
}
|
||||
if(START_Updater("INSTALL"))
|
||||
{
|
||||
state = InstallFailed;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// update app
|
||||
// returns true if app must continue execution, false otherwise
|
||||
bool Updater::START_Update(void)
|
||||
{
|
||||
if(!START_Updater("UPDATE"))
|
||||
return !PromptYesNo(t_("Update failed&Continue running the application?"));
|
||||
return true;
|
||||
if(START_Updater("UPDATE"))
|
||||
{
|
||||
state = UpdateFailed;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// app started, must check for update/install requests
|
||||
// returns true if app must continue execution, false otherwise
|
||||
bool Updater::DO_NormalRun(void)
|
||||
{
|
||||
// we now check if we just want to uninstall app
|
||||
// it can be done by command line --UNINSTALL option
|
||||
if(CommandLine().GetCount() && CommandLine()[0] == "--UNINSTALL")
|
||||
{
|
||||
START_Uninstall();
|
||||
return false;
|
||||
}
|
||||
return START_Uninstall();
|
||||
|
||||
// if app not installed, we shall install it
|
||||
if(!appInstalled)
|
||||
return !START_Install();
|
||||
return START_Install();
|
||||
|
||||
// not installing nor uninstalling
|
||||
|
||||
|
|
@ -271,7 +297,7 @@ bool Updater::DO_NormalRun(void)
|
|||
// updater enabled, start it
|
||||
// if update failed, resume normal run, otherwise exit
|
||||
// as the app will be launched again by updater itself
|
||||
return !START_Update();
|
||||
return START_Update();
|
||||
}
|
||||
|
||||
bool Updater::DO_InsideUpdater(void)
|
||||
|
|
@ -415,35 +441,37 @@ void Updater::DO_Update(void)
|
|||
|
||||
bool Updater::DO_UninstallFailed(void)
|
||||
{
|
||||
Exclamation("Uninstall failed!&Aborting....");
|
||||
return false;
|
||||
state = UninstallFailed;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Updater::DO_InstallFailed(void)
|
||||
{
|
||||
return PromptYesNo("Install failed&Do you want to run the app anyways?");
|
||||
state = InstallFailed;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Updater::DO_UpdateFailed(void)
|
||||
{
|
||||
return PromptYesNo("Update failed&Do you want to run the app anyways?");
|
||||
state = UpdateFailed;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Updater::DO_UninstallSucceeded(void)
|
||||
{
|
||||
PromptOK("Uninstall succeeded!");
|
||||
return false;
|
||||
state = UninstallSucceeded;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Updater::DO_InstallSucceeded(void)
|
||||
{
|
||||
PromptOK("Install succeeded!");
|
||||
state = InstallSucceeded;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Updater::DO_UpdateSucceeded(void)
|
||||
{
|
||||
PromptOK("Update succeeded!");
|
||||
state = UpdateSucceeded;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -596,6 +624,7 @@ bool Updater::Run()
|
|||
NEVER();
|
||||
break;
|
||||
}
|
||||
// dummy
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -621,3 +650,46 @@ Updater &Updater::UpdateDisable(void)
|
|||
return *this;
|
||||
}
|
||||
|
||||
// default set of prompts for installer result
|
||||
// just an handy shortcut good for most cases
|
||||
bool Updater::DefaultPrompts(void)
|
||||
{
|
||||
// fine grained behaviour depending on update state
|
||||
switch(GetState())
|
||||
{
|
||||
case UninstallFailed:
|
||||
Exclamation(t_("Uninstall of '") + appName + t_("' failed&Press OK to quit"));
|
||||
return false;
|
||||
|
||||
case UninstallSucceeded:
|
||||
PromptOK(t_("Uninstall of '") + appName + t_("' complete&Press OK to quit"));
|
||||
return false;
|
||||
|
||||
case UninstallAborted:
|
||||
return false ;
|
||||
|
||||
case InstallFailed:
|
||||
if(!PromptYesNo(t_("Install of '") + appName + t_("' failed&Run without installing?")))
|
||||
return false;
|
||||
return true;
|
||||
|
||||
case InstallSucceeded:
|
||||
return true;
|
||||
|
||||
case InstallAborted:
|
||||
return false;
|
||||
|
||||
case UpdateFailed:
|
||||
if(!PromptYesNo(t_("Update of '") + appName + t_("' failed&Run anyways?")))
|
||||
return false;
|
||||
return true;
|
||||
|
||||
case UpdateSucceeded:
|
||||
return true;
|
||||
|
||||
// here we're on normal run, no install/uninstall/update process happened
|
||||
// we should continue normal execution
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,171 +1,207 @@
|
|||
#ifndef _TimberStarter_Updater_h_
|
||||
#define _TimberStarter_Updater_h_
|
||||
|
||||
#include <CtrlLib/CtrlLib.h>
|
||||
|
||||
using namespace Upp;
|
||||
|
||||
#define SELFUPDATE_OK 0
|
||||
#define SELFUPDATE_NO_NETWORK 1
|
||||
#define SELFUPDATE_NO_VERSIONFILE 2
|
||||
#define SELFUPDATE_NO_APPFILE 3
|
||||
#define SELFUPDATE_NO_PERMISSION 4
|
||||
|
||||
extern int SELFUPDATE_RESULT;
|
||||
|
||||
#define SELFUPDATE(remoteRoot, appName, currentVersion, maxVersion) \
|
||||
SELFUPDATE_RESULT = __SelfUpdate(remoteRoot, appName, currentVersion, maxVersion); \
|
||||
if(SELFUPDATE_RESULT == -1) \
|
||||
return;
|
||||
|
||||
// UPDATE HELPER USED BY SELFUPDATE MACRO
|
||||
|
||||
// IF APP STARTED NORMALLY :
|
||||
// stores current command line on a temporary file
|
||||
// restarts current applcation copying to temporary
|
||||
// folder and acting as a superuser
|
||||
// parameters passed to application :
|
||||
// --UPDATE update command
|
||||
// exepath complete path of itself
|
||||
// cmdlinepath path of the command line file
|
||||
// returns 0 if failed, 1 if success
|
||||
// IF APP STARTED BY UPDATER (as a superuser):
|
||||
// fetches the update file in a temporary folder
|
||||
// overwrite the old executable with the new one
|
||||
// restarts as a normal user the executable with original command line
|
||||
// returns 2 if failed, 3 if success
|
||||
// if failed, adds --UPDATEFAILED as last cmdline parameter
|
||||
// if success, adds --UPDATEOK as last cmdline parameter
|
||||
//
|
||||
// IF APP STARTED WITH --UPDATEFAILED AS LAST PARAMETER
|
||||
// returns 4
|
||||
//
|
||||
// IF APP STARTED WITH --INSTALLFAILED AS LAST PARAMETER
|
||||
// returns 5
|
||||
//
|
||||
// IF APP STARTED WITH --UPDATEOK AS LAST PARAMETER
|
||||
// just return 1 and skip further processing
|
||||
int __SelfUpdate(String const &remoteRoot, String const &appName, String const ¤tVersion, String const &maxVersion);
|
||||
|
||||
|
||||
class Updater
|
||||
{
|
||||
private:
|
||||
// state of updater engine
|
||||
typedef enum
|
||||
{
|
||||
NormalRun, InsideUpdater,
|
||||
UninstallFailed, InstallFailed, UpdateFailed,
|
||||
UninstallSucceeded, InstallSucceeded, UpdateSucceeded
|
||||
} UpdaterState;
|
||||
UpdaterState state;
|
||||
|
||||
// requested operation
|
||||
typedef enum { Install, Update, Uninstall } UpdaterOp;
|
||||
UpdaterOp updaterOp;
|
||||
|
||||
// setup environment for failing update/install
|
||||
void FailUpdate(void);
|
||||
|
||||
// setup environment for succeeding update/install
|
||||
void SucceedUpdate(void);
|
||||
|
||||
// main updater proc inside normal mode
|
||||
// prepares environment, copy app in temporary folder
|
||||
// and restarts it in superuser mode
|
||||
bool START_Updater(String const &operation);
|
||||
|
||||
// operations procedures
|
||||
void START_Uninstall(void);
|
||||
void DO_Uninstall(void);
|
||||
bool START_Install(void);
|
||||
void DO_Install(void);
|
||||
bool START_Update(void);
|
||||
void DO_Update(void);
|
||||
|
||||
// installer/updater subfunctions
|
||||
bool DO_NormalRun(void);
|
||||
bool DO_InsideUpdater(void);
|
||||
bool DO_UninstallFailed(void);
|
||||
bool DO_InstallFailed(void);
|
||||
bool DO_UpdateFailed(void);
|
||||
bool DO_UninstallSucceeded(void);
|
||||
bool DO_InstallSucceeded(void);
|
||||
bool DO_UpdateSucceeded(void);
|
||||
|
||||
// gets platform root folder
|
||||
String GetPlatformRoot(void);
|
||||
|
||||
// restarts app in normal mode after updater mode
|
||||
typedef enum { RestartOrig, RestartNew, RestartTemp } RestartModes;
|
||||
void RestartApp(RestartModes restartMode);
|
||||
|
||||
// fetch list of available app versions
|
||||
Vector<double>FetchVersions(void);
|
||||
double FetchMaxValidVersion(void);
|
||||
|
||||
// fetch the new app version from web server
|
||||
// and replaces older one
|
||||
String appBuffer;
|
||||
bool FetchApp(double ver = -1);
|
||||
|
||||
// running copy of environment
|
||||
VectorMap<String, String>environ;
|
||||
|
||||
// user name (which launched app in normal mode
|
||||
String user;
|
||||
|
||||
// user configuration path
|
||||
String userConfigPath;
|
||||
|
||||
// sistem configuration path (to keep installed version number)
|
||||
String systemConfigPath;
|
||||
|
||||
// flag stating if app is installed
|
||||
bool appInstalled;
|
||||
|
||||
// current installed version, if any
|
||||
double installedVersion;
|
||||
|
||||
// copy of starting command line -- needed to restart app correctly
|
||||
String commandLine;
|
||||
|
||||
// running application name
|
||||
String appName;
|
||||
|
||||
// copy of running executable path
|
||||
// when app was first launched in normal mode
|
||||
String exePath;
|
||||
|
||||
// user variables
|
||||
double maxVersion;
|
||||
String webRoot;
|
||||
|
||||
protected:
|
||||
|
||||
public:
|
||||
|
||||
Updater();
|
||||
|
||||
Updater &SetMaxVersion(double mv) { maxVersion = mv; return *this; }
|
||||
Updater &SetWebRoot(String const &wr) { webRoot = wr; return *this; }
|
||||
|
||||
// sets updater to manual mode -- if update is available, asks user
|
||||
Updater &UpdateManual(void);
|
||||
|
||||
// sets updater to auto -- updates app on launch without asking user
|
||||
Updater &UpdateAuto(void);
|
||||
|
||||
// disable updater -- app will not update on launch
|
||||
// re-enable it to restart updating system on next run
|
||||
Updater &UpdateDisable(void);
|
||||
|
||||
bool IsAppInstalled(void) { return appInstalled; }
|
||||
double GetInstalledVersion(void) { return installedVersion; }
|
||||
double GetMaxVersion(void) { return maxVersion; }
|
||||
String const &GetWebRoot(void) { return webRoot; }
|
||||
|
||||
bool Run(void);
|
||||
};
|
||||
|
||||
#endif
|
||||
#ifndef _TimberStarter_Updater_h_
|
||||
#define _TimberStarter_Updater_h_
|
||||
|
||||
#include <CtrlLib/CtrlLib.h>
|
||||
|
||||
using namespace Upp;
|
||||
|
||||
#define SELFUPDATE_OK 0
|
||||
#define SELFUPDATE_NO_NETWORK 1
|
||||
#define SELFUPDATE_NO_VERSIONFILE 2
|
||||
#define SELFUPDATE_NO_APPFILE 3
|
||||
#define SELFUPDATE_NO_PERMISSION 4
|
||||
|
||||
extern int SELFUPDATE_RESULT;
|
||||
|
||||
#define SELFUPDATE(remoteRoot, appName, currentVersion, maxVersion) \
|
||||
SELFUPDATE_RESULT = __SelfUpdate(remoteRoot, appName, currentVersion, maxVersion); \
|
||||
if(SELFUPDATE_RESULT == -1) \
|
||||
return;
|
||||
|
||||
// UPDATE HELPER USED BY SELFUPDATE MACRO
|
||||
|
||||
// IF APP STARTED NORMALLY :
|
||||
// stores current command line on a temporary file
|
||||
// restarts current applcation copying to temporary
|
||||
// folder and acting as a superuser
|
||||
// parameters passed to application :
|
||||
// --UPDATE update command
|
||||
// exepath complete path of itself
|
||||
// cmdlinepath path of the command line file
|
||||
// returns 0 if failed, 1 if success
|
||||
// IF APP STARTED BY UPDATER (as a superuser):
|
||||
// fetches the update file in a temporary folder
|
||||
// overwrite the old executable with the new one
|
||||
// restarts as a normal user the executable with original command line
|
||||
// returns 2 if failed, 3 if success
|
||||
// if failed, adds --UPDATEFAILED as last cmdline parameter
|
||||
// if success, adds --UPDATEOK as last cmdline parameter
|
||||
//
|
||||
// IF APP STARTED WITH --UPDATEFAILED AS LAST PARAMETER
|
||||
// returns 4
|
||||
//
|
||||
// IF APP STARTED WITH --INSTALLFAILED AS LAST PARAMETER
|
||||
// returns 5
|
||||
//
|
||||
// IF APP STARTED WITH --UPDATEOK AS LAST PARAMETER
|
||||
// just return 1 and skip further processing
|
||||
int __SelfUpdate(String const &remoteRoot, String const &appName, String const ¤tVersion, String const &maxVersion);
|
||||
|
||||
|
||||
class Updater
|
||||
{
|
||||
public:
|
||||
// state of updater engine
|
||||
typedef enum
|
||||
{
|
||||
// internal states
|
||||
NormalRun, InsideUpdater,
|
||||
|
||||
// public states
|
||||
UninstallFailed, InstallFailed, UpdateFailed,
|
||||
UninstallSucceeded, InstallSucceeded, UpdateSucceeded,
|
||||
UninstallAborted, InstallAborted
|
||||
} UpdaterState;
|
||||
|
||||
private:
|
||||
// state of updater engine
|
||||
UpdaterState state;
|
||||
|
||||
// requested operation
|
||||
typedef enum { Install, Update, Uninstall } UpdaterOp;
|
||||
UpdaterOp updaterOp;
|
||||
|
||||
// setup environment for failing update/install
|
||||
void FailUpdate(void);
|
||||
|
||||
// setup environment for succeeding update/install
|
||||
void SucceedUpdate(void);
|
||||
|
||||
// main updater proc inside normal mode
|
||||
// prepares environment, copy app in temporary folder
|
||||
// and restarts it in superuser mode
|
||||
bool START_Updater(String const &operation);
|
||||
|
||||
// operations procedures
|
||||
bool START_Uninstall(void);
|
||||
void DO_Uninstall(void);
|
||||
bool START_Install(void);
|
||||
void DO_Install(void);
|
||||
bool START_Update(void);
|
||||
void DO_Update(void);
|
||||
|
||||
// installer/updater subfunctions
|
||||
bool DO_NormalRun(void);
|
||||
bool DO_InsideUpdater(void);
|
||||
bool DO_UninstallFailed(void);
|
||||
bool DO_InstallFailed(void);
|
||||
bool DO_UpdateFailed(void);
|
||||
bool DO_UninstallSucceeded(void);
|
||||
bool DO_InstallSucceeded(void);
|
||||
bool DO_UpdateSucceeded(void);
|
||||
|
||||
// gets platform root folder
|
||||
String GetPlatformRoot(void);
|
||||
|
||||
// restarts app in normal mode after updater mode
|
||||
typedef enum { RestartOrig, RestartNew, RestartTemp } RestartModes;
|
||||
void RestartApp(RestartModes restartMode);
|
||||
|
||||
// fetch list of available app versions
|
||||
Vector<double>FetchVersions(void);
|
||||
double FetchMaxValidVersion(void);
|
||||
|
||||
// fetch the new app version from web server
|
||||
// and replaces older one
|
||||
String appBuffer;
|
||||
bool FetchApp(double ver = -1);
|
||||
|
||||
// running copy of environment
|
||||
VectorMap<String, String>environ;
|
||||
|
||||
// user name (which launched app in normal mode
|
||||
String user;
|
||||
|
||||
// user configuration path
|
||||
String userConfigPath;
|
||||
|
||||
// sistem configuration path (to keep installed version number)
|
||||
String systemConfigPath;
|
||||
|
||||
// flag stating if app is installed
|
||||
bool appInstalled;
|
||||
|
||||
// current installed version, if any
|
||||
double installedVersion;
|
||||
|
||||
// copy of starting command line -- needed to restart app correctly
|
||||
String commandLine;
|
||||
|
||||
// running application name
|
||||
String appName;
|
||||
|
||||
// copy of running executable path
|
||||
// when app was first launched in normal mode
|
||||
String exePath;
|
||||
|
||||
// user variables
|
||||
double maxVersion;
|
||||
String webRoot;
|
||||
|
||||
// install mode -- manual (true) or auto (false)
|
||||
bool confirmInstall;
|
||||
|
||||
// uninstall mode -- manual (true) or auto (false)
|
||||
bool confirmUninstall;
|
||||
|
||||
protected:
|
||||
|
||||
public:
|
||||
|
||||
Updater();
|
||||
|
||||
Updater &SetMaxVersion(double mv) { maxVersion = mv; return *this; }
|
||||
Updater &SetWebRoot(String const &wr) { webRoot = wr; return *this; }
|
||||
|
||||
// sets updater to manual mode -- if update is available, asks user
|
||||
Updater &UpdateManual(void);
|
||||
|
||||
// sets updater to auto -- updates app on launch without asking user
|
||||
Updater &UpdateAuto(void);
|
||||
|
||||
// disable updater -- app will not update on launch
|
||||
// re-enable it to restart updating system on next run
|
||||
Updater &UpdateDisable(void);
|
||||
|
||||
// sets installer to auto mode (don't ask user)
|
||||
Updater &NoConfirmInstall(void) { confirmInstall = false; return *this; }
|
||||
|
||||
// sets installer to manual mode (ask user)
|
||||
Updater &ConfirmInstall(void) { confirmInstall = true; return *this; }
|
||||
|
||||
// sets uninstaller to auto mode (don't ask user)
|
||||
Updater &NoConfirmUninstall(void) { confirmUninstall = false; return *this; }
|
||||
|
||||
// sets uninstaller to manual mode (ask user)
|
||||
Updater &ConfirmUninstall(void) { confirmUninstall = true; return *this; }
|
||||
|
||||
bool IsAppInstalled(void) { return appInstalled; }
|
||||
double GetInstalledVersion(void) { return installedVersion; }
|
||||
double GetMaxVersion(void) { return maxVersion; }
|
||||
String const &GetWebRoot(void) { return webRoot; }
|
||||
|
||||
// executes updater
|
||||
// return true if app should continue execution
|
||||
// return false if app should exit
|
||||
// BEWARE -- you NEED to test this and leave application if false !
|
||||
bool Run(void);
|
||||
|
||||
// get updater result status
|
||||
UpdaterState GetState(void) { return state; }
|
||||
|
||||
// default set of prompts for installer result
|
||||
// just an handy shortcut good for most cases
|
||||
bool DefaultPrompts(void);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue