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:
micio 2011-01-15 23:46:01 +00:00
parent 5e1d5ae6c8
commit 777fd2e0ba
2 changed files with 308 additions and 200 deletions

View file

@ -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;
}
}

View file

@ -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 &currentVersion, 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 &currentVersion, 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