Add the core logic for installing and uninstalling files in UpdateInstaller

This commit is contained in:
Robert Knight 2011-08-19 21:03:10 +01:00
parent e3cec64375
commit 0a6630bc8c
5 changed files with 241 additions and 6 deletions

View file

@ -4,6 +4,10 @@
#include <unistd.h>
FileOps::IOException::~IOException() throw ()
{
}
bool FileOps::fileExists(const char* path) throw (IOException)
{
#ifdef PLATFORM_UNIX
@ -54,3 +58,24 @@ void FileOps::createSymLink(const char* link, const char* target) throw (IOExcep
#endif
}
void FileOps::removeFile(const char* src) throw (IOException)
{
#ifdef PLATFORM_UNIX
#else
#endif
}
std::string FileOps::dirname(const char* path)
{
#ifdef PLATFORM_UNIX
#else
#endif
}
void FileOps::touch(const char* path) throw (IOException)
{
#ifdef PLATFORM_UNIX
#else
#endif
}

View file

@ -9,10 +9,17 @@ class FileOps
class IOException : public std::exception
{
public:
IOException(const std::string& error);
IOException(const std::string& error)
: m_error(error)
{
}
virtual ~IOException() throw ();
virtual const char* what();
virtual const char* what() const throw ()
{
return m_error.c_str();
}
private:
std::string m_error;
@ -21,9 +28,12 @@ class FileOps
static bool fileExists(const char* path) throw (IOException);
static void setPermissions(const char* path, int permissions) throw (IOException);
static void moveFile(const char* src, const char* dest) throw (IOException);
static void removeFile(const char* src) throw (IOException);
static void extractFromZip(const char* zipFile, const char* src, const char* dest) throw (IOException);
static void mkdir(const char* dir) throw (IOException);
static void rmdir(const char* dir) throw (IOException);
static void createSymLink(const char* link, const char* target) throw (IOException);
static void touch(const char* path) throw (IOException);
static std::string dirname(const char* path);
};

View file

@ -1,13 +1,23 @@
#include "UpdateInstaller.h"
#include "FileOps.h"
#include "Log.h"
#include "ProcessUtils.h"
#include "UpdateObserver.h"
UpdateInstaller::UpdateInstaller()
: m_mode(Setup)
, m_script(0)
, m_waitPid(0)
, m_observer(0)
{
}
void UpdateInstaller::setWaitPid(long long pid)
{
m_waitPid = pid;
}
void UpdateInstaller::setInstallDir(const std::string& path)
{
m_installDir = path;
@ -33,18 +43,188 @@ void UpdateInstaller::setScript(UpdateScript* script)
m_script = script;
}
void UpdateInstaller::run()
void UpdateInstaller::run() throw ()
{
LOG(Info,"Starting update installation");
if (m_mode == Setup)
{
ProcessUtils::waitForProcess(m_waitPid);
std::string updaterPath;
std::list<std::string> args;
if (!checkAccess())
{
// start a copy of the updater with admin rights
ProcessUtils::runElevated(updaterPath,args);
}
else
{
// TODO - Change this to run synchronously
ProcessUtils::runAsync(updaterPath,args);
}
}
else if (m_mode == Main)
{
std::string error;
try
{
installFiles();
uninstallFiles();
removeBackups();
}
catch (const FileOps::IOException& exception)
{
error = exception.what();
}
catch (const std::string& genericError)
{
error = genericError;
}
if (!error.empty())
{
LOG(Error,std::string("Error installing update ") + error);
revert();
if (m_observer)
{
m_observer->updateError(error);
}
}
if (m_observer)
{
m_observer->updateFinished();
}
}
else if (m_mode == Cleanup)
{
ProcessUtils::waitForProcess(m_waitPid);
cleanup();
}
}
void UpdateInstaller::cleanup()
{
// TODO - Remove the temp dir which the installer was copied to
}
void UpdateInstaller::revert()
{
std::map<std::string,std::string>::const_iterator iter = m_backups.begin();
for (;iter != m_backups.end();iter++)
{
const std::string& installedFile = iter->first;
const std::string& backupFile = iter->second;
if (FileOps::fileExists(installedFile.c_str()))
{
FileOps::removeFile(installedFile.c_str());
}
FileOps::moveFile(backupFile.c_str(),installedFile.c_str());
}
}
void UpdateInstaller::installFile(const UpdateScriptFile& file)
{
std::string packageFile = m_installDir + '/' + file.package;
std::string destPath = m_installDir + '/' + file.path;
std::string target = file.linkTarget;
if (!FileOps::fileExists(packageFile.c_str()))
{
throw "Package file does not exist: " + packageFile;
}
// backup the existing file if any
backupFile(destPath);
// create the target directory if it does not exist
std::string destDir = FileOps::dirname(destPath.c_str());
if (!FileOps::fileExists(destDir.c_str()))
{
FileOps::mkdir(destDir.c_str());
}
if (target.empty())
{
// extract the file from the package and copy it to
// the destination
FileOps::extractFromZip(packageFile.c_str(),file.path.c_str(),destPath.c_str());
// set the permissions on the newly extracted file
FileOps::setPermissions(destPath.c_str(),file.permissions);
}
else
{
// create the symlink
FileOps::createSymLink(destPath.c_str(),target.c_str());
}
}
void UpdateInstaller::installFiles()
{
std::vector<UpdateScriptFile>::const_iterator iter = m_script->filesToInstall().begin();
int filesInstalled = 0;
for (;iter != m_script->filesToInstall().end();iter++)
{
installFile(*iter);
++filesInstalled;
if (m_observer)
{
m_observer->updateProgress(static_cast<float>(filesInstalled) / m_script->filesToInstall().size() * 100);
}
}
}
void UpdateInstaller::uninstallFiles()
{
std::vector<std::string>::const_iterator iter = m_script->filesToUninstall().begin();
for (;iter != m_script->filesToUninstall().end();iter++)
{
FileOps::removeFile(iter->c_str());
}
}
void UpdateInstaller::backupFile(const std::string& path)
{
if (!FileOps::fileExists(path.c_str()))
{
// no existing file to backup
return;
}
std::string backupPath = path + ".bak";
FileOps::removeFile(backupPath.c_str());
FileOps::moveFile(path.c_str(), backupPath.c_str());
m_backups[path] = backupPath;
}
void UpdateInstaller::removeBackups()
{
std::map<std::string,std::string>::const_iterator iter = m_backups.begin();
for (;iter != m_backups.end();iter++)
{
const std::string& installedFile = iter->first;
const std::string& backupFile = iter->second;
FileOps::removeFile(backupFile.c_str());
}
}
bool UpdateInstaller::checkAccess()
{
std::string testFile = m_installDir + "/update-installer-test-file";
FileOps::removeFile(testFile.c_str());
try
{
FileOps::touch(testFile.c_str());
FileOps::removeFile(testFile.c_str());
return true;
}
catch (const FileOps::IOException& error)
{
return false;
}
}

View file

@ -1,8 +1,11 @@
#pragma once
#include <string>
#include "UpdateScript.h"
class UpdateScript;
#include <string>
#include <map>
class UpdateObserver;
class UpdateInstaller
{
@ -20,14 +23,30 @@ class UpdateInstaller
void setBackupDir(const std::string& path);
void setMode(Mode mode);
void setScript(UpdateScript* script);
void setWaitPid(long long pid);
void run();
void setObserver(UpdateObserver* observer);
void run() throw ();
private:
void cleanup();
void revert();
void removeBackups();
bool checkAccess();
void installFiles();
void uninstallFiles();
void installFile(const UpdateScriptFile& file);
void backupFile(const std::string& path);
Mode m_mode;
std::string m_installDir;
std::string m_packageDir;
std::string m_backupDir;
long long m_waitPid;
UpdateScript* m_script;
UpdateObserver* m_observer;
std::map<std::string,std::string> m_backups;
};

View file

@ -42,6 +42,7 @@ int main(int argc, char** argv)
installer.setInstallDir(options.installDir);
installer.setPackageDir(options.packageDir);
installer.setScript(&script);
installer.setWaitPid(options.waitPid);
installer.run();
return 0;