mirror of
https://github.com/etlegacy/Update-Installer.git
synced 2025-02-01 20:10:42 +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
|
||||
|
||||
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;
|
||||
|
||||
#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
|
||||
|
||||
#ifdef PLATFORM_WINDOWS
|
||||
m_errorCode = 0;
|
||||
m_error += " GetLastError returned: " + intToStr(GetLastError());
|
||||
#endif
|
||||
|
||||
LOG(Info,"created IOException with errno " + intToStr(m_errorCode) + " rofs " + intToStr(EROFS));
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
#ifdef PLATFORM_UNIX
|
||||
|
|
|
@ -21,17 +21,32 @@ class FileUtils
|
|||
{
|
||||
public:
|
||||
IOException(const std::string& error);
|
||||
IOException(int errno, const std::string& error);
|
||||
|
||||
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 ()
|
||||
{
|
||||
return m_error.c_str();
|
||||
}
|
||||
|
||||
Type type() const;
|
||||
|
||||
private:
|
||||
void init(int errorCode, const std::string& error);
|
||||
|
||||
std::string m_error;
|
||||
int m_errno;
|
||||
int m_errorCode;
|
||||
};
|
||||
|
||||
/** 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 ()
|
||||
{
|
||||
if (!m_script || !m_script->isValid())
|
||||
|
@ -144,7 +167,13 @@ void UpdateInstaller::run() throw ()
|
|||
{
|
||||
LOG(Info,"Starting update installation");
|
||||
|
||||
// the detailed error string returned by the OS
|
||||
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
|
||||
{
|
||||
LOG(Info,"Installing new and updated files");
|
||||
|
@ -161,6 +190,7 @@ void UpdateInstaller::run() throw ()
|
|||
catch (const FileUtils::IOException& exception)
|
||||
{
|
||||
error = exception.what();
|
||||
friendlyError = friendlyErrorForError(exception);
|
||||
}
|
||||
catch (const std::string& genericError)
|
||||
{
|
||||
|
@ -170,10 +200,23 @@ void UpdateInstaller::run() throw ()
|
|||
if (!error.empty())
|
||||
{
|
||||
LOG(Error,std::string("Error installing update ") + error);
|
||||
revert();
|
||||
|
||||
try
|
||||
{
|
||||
revert();
|
||||
}
|
||||
catch (const FileUtils::IOException& exception)
|
||||
{
|
||||
LOG(Error,"Error reverting partial update " + std::string(exception.what()));
|
||||
}
|
||||
|
||||
if (m_observer)
|
||||
{
|
||||
m_observer->updateError(error);
|
||||
if (friendlyError.empty())
|
||||
{
|
||||
friendlyError = error;
|
||||
}
|
||||
m_observer->updateError(friendlyError);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include "Platform.h"
|
||||
#include "FileUtils.h"
|
||||
#include "UpdateScript.h"
|
||||
|
||||
#include <list>
|
||||
|
@ -52,6 +53,7 @@ class UpdateInstaller
|
|||
void postInstallUpdate();
|
||||
|
||||
std::list<std::string> updaterArgs() const;
|
||||
std::string friendlyErrorForError(const FileUtils::IOException& ex) const;
|
||||
|
||||
Mode m_mode;
|
||||
std::string m_installDir;
|
||||
|
|
Loading…
Reference in a new issue