mirror of
https://github.com/etlegacy/Update-Installer.git
synced 2025-02-02 04:11:23 +00:00
Display a more helpful message to the user if an update cannot be installed because the application was run from a read-only file system.
On Mac, this can happen if the user runs the app directly from a disk image. On all platforms, this can happen if the app is run from any kind of read-only media or network share. * Intercept IO errors during installation and try to find a more friendly alternative to the OS error string. * Catch any IO exceptions throw whilst reverting a partial update and log details.
This commit is contained in:
parent
972811de23
commit
1bad51e3dc
4 changed files with 96 additions and 7 deletions
|
@ -24,28 +24,57 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
FileUtils::IOException::IOException(const std::string& error)
|
FileUtils::IOException::IOException(const std::string& error)
|
||||||
: m_errno(0)
|
{
|
||||||
|
init(errno,error);
|
||||||
|
}
|
||||||
|
|
||||||
|
FileUtils::IOException::IOException(int errorCode, const std::string& error)
|
||||||
|
{
|
||||||
|
init(errorCode,error);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FileUtils::IOException::init(int errorCode, const std::string& error)
|
||||||
{
|
{
|
||||||
m_error = error;
|
m_error = error;
|
||||||
|
|
||||||
#ifdef PLATFORM_UNIX
|
#ifdef PLATFORM_UNIX
|
||||||
m_errno = errno;
|
m_errorCode = errorCode;
|
||||||
|
|
||||||
if (m_errno > 0)
|
if (m_errorCode > 0)
|
||||||
{
|
{
|
||||||
m_error += " details: " + std::string(strerror(m_errno));
|
m_error += " details: " + std::string(strerror(m_errorCode));
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef PLATFORM_WINDOWS
|
#ifdef PLATFORM_WINDOWS
|
||||||
|
m_errorCode = 0;
|
||||||
m_error += " GetLastError returned: " + intToStr(GetLastError());
|
m_error += " GetLastError returned: " + intToStr(GetLastError());
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
LOG(Info,"created IOException with errno " + intToStr(m_errorCode) + " rofs " + intToStr(EROFS));
|
||||||
}
|
}
|
||||||
|
|
||||||
FileUtils::IOException::~IOException() throw ()
|
FileUtils::IOException::~IOException() throw ()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FileUtils::IOException::Type FileUtils::IOException::type() const
|
||||||
|
{
|
||||||
|
#ifdef PLATFORM_UNIX
|
||||||
|
switch (m_errorCode)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
return NoError;
|
||||||
|
case EROFS:
|
||||||
|
return ReadOnlyFileSystem;
|
||||||
|
default:
|
||||||
|
return Unknown;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
return Unknown;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
bool FileUtils::fileExists(const char* path) throw (IOException)
|
bool FileUtils::fileExists(const char* path) throw (IOException)
|
||||||
{
|
{
|
||||||
#ifdef PLATFORM_UNIX
|
#ifdef PLATFORM_UNIX
|
||||||
|
|
|
@ -21,17 +21,32 @@ class FileUtils
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
IOException(const std::string& error);
|
IOException(const std::string& error);
|
||||||
|
IOException(int errno, const std::string& error);
|
||||||
|
|
||||||
virtual ~IOException() throw ();
|
virtual ~IOException() throw ();
|
||||||
|
|
||||||
|
enum Type
|
||||||
|
{
|
||||||
|
NoError,
|
||||||
|
/** Unknown error type. Call what() to get the description
|
||||||
|
* provided by the OS.
|
||||||
|
*/
|
||||||
|
Unknown,
|
||||||
|
ReadOnlyFileSystem
|
||||||
|
};
|
||||||
|
|
||||||
virtual const char* what() const throw ()
|
virtual const char* what() const throw ()
|
||||||
{
|
{
|
||||||
return m_error.c_str();
|
return m_error.c_str();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Type type() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void init(int errorCode, const std::string& error);
|
||||||
|
|
||||||
std::string m_error;
|
std::string m_error;
|
||||||
int m_errno;
|
int m_errorCode;
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Remove a file. Throws an exception if the file
|
/** Remove a file. Throws an exception if the file
|
||||||
|
|
|
@ -71,6 +71,29 @@ void UpdateInstaller::reportError(const std::string& error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string UpdateInstaller::friendlyErrorForError(const FileUtils::IOException& exception) const
|
||||||
|
{
|
||||||
|
std::string friendlyError;
|
||||||
|
|
||||||
|
switch (exception.type())
|
||||||
|
{
|
||||||
|
case FileUtils::IOException::ReadOnlyFileSystem:
|
||||||
|
#ifdef PLATFORM_MAC
|
||||||
|
friendlyError = AppInfo::appName() + " was started from a read-only location. "
|
||||||
|
"Copy it to the Applications folder on your Mac and run "
|
||||||
|
"it from there.";
|
||||||
|
#else
|
||||||
|
friendlyError = AppInfo::appName() + " was started from a read-only location. "
|
||||||
|
"Re-install it to a location that can be updated and run it from there.";
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return friendlyError;
|
||||||
|
}
|
||||||
|
|
||||||
void UpdateInstaller::run() throw ()
|
void UpdateInstaller::run() throw ()
|
||||||
{
|
{
|
||||||
if (!m_script || !m_script->isValid())
|
if (!m_script || !m_script->isValid())
|
||||||
|
@ -144,7 +167,13 @@ void UpdateInstaller::run() throw ()
|
||||||
{
|
{
|
||||||
LOG(Info,"Starting update installation");
|
LOG(Info,"Starting update installation");
|
||||||
|
|
||||||
|
// the detailed error string returned by the OS
|
||||||
std::string error;
|
std::string error;
|
||||||
|
// the message to present to the user. This may be the same
|
||||||
|
// as 'error' or may be different if a more helpful suggestion
|
||||||
|
// can be made for a particular problem
|
||||||
|
std::string friendlyError;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
LOG(Info,"Installing new and updated files");
|
LOG(Info,"Installing new and updated files");
|
||||||
|
@ -161,6 +190,7 @@ void UpdateInstaller::run() throw ()
|
||||||
catch (const FileUtils::IOException& exception)
|
catch (const FileUtils::IOException& exception)
|
||||||
{
|
{
|
||||||
error = exception.what();
|
error = exception.what();
|
||||||
|
friendlyError = friendlyErrorForError(exception);
|
||||||
}
|
}
|
||||||
catch (const std::string& genericError)
|
catch (const std::string& genericError)
|
||||||
{
|
{
|
||||||
|
@ -170,10 +200,23 @@ void UpdateInstaller::run() throw ()
|
||||||
if (!error.empty())
|
if (!error.empty())
|
||||||
{
|
{
|
||||||
LOG(Error,std::string("Error installing update ") + error);
|
LOG(Error,std::string("Error installing update ") + error);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
revert();
|
revert();
|
||||||
|
}
|
||||||
|
catch (const FileUtils::IOException& exception)
|
||||||
|
{
|
||||||
|
LOG(Error,"Error reverting partial update " + std::string(exception.what()));
|
||||||
|
}
|
||||||
|
|
||||||
if (m_observer)
|
if (m_observer)
|
||||||
{
|
{
|
||||||
m_observer->updateError(error);
|
if (friendlyError.empty())
|
||||||
|
{
|
||||||
|
friendlyError = error;
|
||||||
|
}
|
||||||
|
m_observer->updateError(friendlyError);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "Platform.h"
|
#include "Platform.h"
|
||||||
|
#include "FileUtils.h"
|
||||||
#include "UpdateScript.h"
|
#include "UpdateScript.h"
|
||||||
|
|
||||||
#include <list>
|
#include <list>
|
||||||
|
@ -52,6 +53,7 @@ class UpdateInstaller
|
||||||
void postInstallUpdate();
|
void postInstallUpdate();
|
||||||
|
|
||||||
std::list<std::string> updaterArgs() const;
|
std::list<std::string> updaterArgs() const;
|
||||||
|
std::string friendlyErrorForError(const FileUtils::IOException& ex) const;
|
||||||
|
|
||||||
Mode m_mode;
|
Mode m_mode;
|
||||||
std::string m_installDir;
|
std::string m_installDir;
|
||||||
|
|
Loading…
Reference in a new issue