Merge branch 'master' of ssh://files/git/desktop/standalone-updater

This commit is contained in:
Robert Knight 2011-09-15 19:03:29 +01:00
commit f88e471fa2
7 changed files with 110 additions and 10 deletions

View file

@ -24,28 +24,59 @@
#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;
case ENOSPC:
return DiskFull;
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

View file

@ -21,17 +21,33 @@ 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,
DiskFull
};
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

View file

@ -43,7 +43,7 @@ class UpdateDialogPrivate
{ {
dialog->hadError = true; dialog->hadError = true;
NSMutableString* message = [[NSMutableString alloc] init]; NSMutableString* message = [[NSMutableString alloc] init];
[message appendString:@"There was a problem installing the update:\n"]; [message appendString:@"There was a problem installing the update:\n\n"];
[message appendString:arg]; [message appendString:arg];
NSAlert* alert = [NSAlert NSAlert* alert = [NSAlert

View file

@ -71,6 +71,32 @@ 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;
case FileUtils::IOException::DiskFull:
friendlyError = "The disk is full. Please free up some space and try again.";
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 +170,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 +193,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 +203,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);
revert();
try
{
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);
} }
} }

View file

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

View file

@ -25,7 +25,7 @@
#include <iostream> #include <iostream>
#define UPDATER_VERSION "0.5" #define UPDATER_VERSION "0.6"
void runWithUi(int argc, char** argv, UpdateInstaller* installer); void runWithUi(int argc, char** argv, UpdateInstaller* installer);

View file

@ -47,11 +47,15 @@ def zip_supports_bzip2(zip_tool)
end end
force_elevation = false force_elevation = false
run_in_debugger = false
OptionParser.new do |parser| OptionParser.new do |parser|
parser.on("-f","--force-elevated","Force the updater to elevate itself") do parser.on("-f","--force-elevated","Force the updater to elevate itself") do
force_elevation = true force_elevation = true
end end
parser.on("-d","--debug","Run the updater under GDB") do
run_in_debugger = true
end
end.parse! end.parse!
BZIP2_AVAILABLE = zip_supports_bzip2(ZIP_TOOL) BZIP2_AVAILABLE = zip_supports_bzip2(ZIP_TOOL)
@ -102,7 +106,8 @@ FileUtils.cp("../#{UPDATER_NAME}","#{PACKAGE_DIR}/#{UPDATER_NAME}")
install_path = File.expand_path(INSTALL_DIR) install_path = File.expand_path(INSTALL_DIR)
Dir.chdir(INSTALL_DIR) do Dir.chdir(INSTALL_DIR) do
flags = "--force-elevated" if force_elevation flags = "--force-elevated" if force_elevation
cmd = "#{PACKAGE_DIR}/#{UPDATER_NAME} #{flags} --install-dir \"#{install_path}\" --package-dir \"#{PACKAGE_DIR}\" --script file_list.xml" debug_flags = "gdb --args" if run_in_debugger
cmd = "#{debug_flags} #{PACKAGE_DIR}/#{UPDATER_NAME} #{flags} --install-dir \"#{install_path}\" --package-dir \"#{PACKAGE_DIR}\" --script file_list.xml"
puts "Running '#{cmd}'" puts "Running '#{cmd}'"
system(cmd) system(cmd)
end end