Merge pull request #3186 from atom/auto-updater-fix
Clean up the code of auto-updater
This commit is contained in:
commit
0e3e1be85c
16 changed files with 247 additions and 332 deletions
|
@ -5,12 +5,31 @@
|
|||
#include "atom/browser/api/atom_api_auto_updater.h"
|
||||
|
||||
#include "base/time/time.h"
|
||||
#include "atom/browser/auto_updater.h"
|
||||
#include "atom/browser/browser.h"
|
||||
#include "atom/browser/native_window.h"
|
||||
#include "atom/browser/window_list.h"
|
||||
#include "atom/common/native_mate_converters/callback.h"
|
||||
#include "atom/common/node_includes.h"
|
||||
#include "native_mate/dictionary.h"
|
||||
#include "native_mate/object_template_builder.h"
|
||||
|
||||
namespace mate {
|
||||
|
||||
template<>
|
||||
struct Converter<base::Time> {
|
||||
static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
|
||||
const base::Time& val) {
|
||||
v8::MaybeLocal<v8::Value> date = v8::Date::New(
|
||||
isolate->GetCurrentContext(), val.ToJsTime());
|
||||
if (date.IsEmpty())
|
||||
return v8::Null(isolate);
|
||||
else
|
||||
return date.ToLocalChecked();
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace mate
|
||||
|
||||
namespace atom {
|
||||
|
||||
namespace api {
|
||||
|
@ -20,11 +39,18 @@ AutoUpdater::AutoUpdater() {
|
|||
}
|
||||
|
||||
AutoUpdater::~AutoUpdater() {
|
||||
auto_updater::AutoUpdater::SetDelegate(NULL);
|
||||
auto_updater::AutoUpdater::SetDelegate(nullptr);
|
||||
}
|
||||
|
||||
void AutoUpdater::OnError(const std::string& error) {
|
||||
Emit("error", error);
|
||||
void AutoUpdater::OnError(const std::string& message) {
|
||||
v8::Locker locker(isolate());
|
||||
v8::HandleScope handle_scope(isolate());
|
||||
auto error = v8::Exception::Error(mate::StringToV8(isolate(), message));
|
||||
EmitCustomEvent(
|
||||
"error",
|
||||
error->ToObject(isolate()->GetCurrentContext()).ToLocalChecked(),
|
||||
// Message is also emitted to keep compatibility with old code.
|
||||
message);
|
||||
}
|
||||
|
||||
void AutoUpdater::OnCheckingForUpdate() {
|
||||
|
@ -42,11 +68,14 @@ void AutoUpdater::OnUpdateNotAvailable() {
|
|||
void AutoUpdater::OnUpdateDownloaded(const std::string& release_notes,
|
||||
const std::string& release_name,
|
||||
const base::Time& release_date,
|
||||
const std::string& update_url,
|
||||
const base::Closure& quit_and_install) {
|
||||
quit_and_install_ = quit_and_install;
|
||||
Emit("update-downloaded-raw", release_notes, release_name,
|
||||
release_date.ToJsTime(), update_url);
|
||||
const std::string& url) {
|
||||
Emit("update-downloaded", release_notes, release_name, release_date, url,
|
||||
// Keep compatibility with old APIs.
|
||||
base::Bind(&AutoUpdater::QuitAndInstall, base::Unretained(this)));
|
||||
}
|
||||
|
||||
void AutoUpdater::OnWindowAllClosed() {
|
||||
QuitAndInstall();
|
||||
}
|
||||
|
||||
mate::ObjectTemplateBuilder AutoUpdater::GetObjectTemplateBuilder(
|
||||
|
@ -54,14 +83,21 @@ mate::ObjectTemplateBuilder AutoUpdater::GetObjectTemplateBuilder(
|
|||
return mate::ObjectTemplateBuilder(isolate)
|
||||
.SetMethod("setFeedUrl", &auto_updater::AutoUpdater::SetFeedURL)
|
||||
.SetMethod("checkForUpdates", &auto_updater::AutoUpdater::CheckForUpdates)
|
||||
.SetMethod("_quitAndInstall", &AutoUpdater::QuitAndInstall);
|
||||
.SetMethod("quitAndInstall", &AutoUpdater::QuitAndInstall);
|
||||
}
|
||||
|
||||
void AutoUpdater::QuitAndInstall() {
|
||||
if (quit_and_install_.is_null())
|
||||
Browser::Get()->Shutdown();
|
||||
else
|
||||
quit_and_install_.Run();
|
||||
// If we don't have any window then quitAndInstall immediately.
|
||||
WindowList* window_list = WindowList::GetInstance();
|
||||
if (window_list->size() == 0) {
|
||||
auto_updater::AutoUpdater::QuitAndInstall();
|
||||
return;
|
||||
}
|
||||
|
||||
// Otherwise do the restart after all windows have been closed.
|
||||
window_list->AddObserver(this);
|
||||
for (NativeWindow* window : *window_list)
|
||||
window->Close();
|
||||
}
|
||||
|
||||
// static
|
||||
|
|
|
@ -7,9 +7,9 @@
|
|||
|
||||
#include <string>
|
||||
|
||||
#include "base/callback.h"
|
||||
#include "atom/browser/api/event_emitter.h"
|
||||
#include "atom/browser/auto_updater_delegate.h"
|
||||
#include "atom/browser/auto_updater.h"
|
||||
#include "atom/browser/window_list_observer.h"
|
||||
#include "native_mate/handle.h"
|
||||
|
||||
namespace atom {
|
||||
|
@ -17,7 +17,8 @@ namespace atom {
|
|||
namespace api {
|
||||
|
||||
class AutoUpdater : public mate::EventEmitter,
|
||||
public auto_updater::AutoUpdaterDelegate {
|
||||
public auto_updater::Delegate,
|
||||
public WindowListObserver {
|
||||
public:
|
||||
static mate::Handle<AutoUpdater> Create(v8::Isolate* isolate);
|
||||
|
||||
|
@ -25,17 +26,18 @@ class AutoUpdater : public mate::EventEmitter,
|
|||
AutoUpdater();
|
||||
virtual ~AutoUpdater();
|
||||
|
||||
// AutoUpdaterDelegate implementations.
|
||||
// Delegate implementations.
|
||||
void OnError(const std::string& error) override;
|
||||
void OnCheckingForUpdate() override;
|
||||
void OnUpdateAvailable() override;
|
||||
void OnUpdateNotAvailable() override;
|
||||
void OnUpdateDownloaded(
|
||||
const std::string& release_notes,
|
||||
const std::string& release_name,
|
||||
const base::Time& release_date,
|
||||
const std::string& update_url,
|
||||
const base::Closure& quit_and_install) override;
|
||||
void OnUpdateDownloaded(const std::string& release_notes,
|
||||
const std::string& release_name,
|
||||
const base::Time& release_date,
|
||||
const std::string& update_url) override;
|
||||
|
||||
// WindowListObserver:
|
||||
void OnWindowAllClosed() override;
|
||||
|
||||
// mate::Wrappable implementations:
|
||||
mate::ObjectTemplateBuilder GetObjectTemplateBuilder(
|
||||
|
@ -44,8 +46,6 @@ class AutoUpdater : public mate::EventEmitter,
|
|||
private:
|
||||
void QuitAndInstall();
|
||||
|
||||
base::Closure quit_and_install_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(AutoUpdater);
|
||||
};
|
||||
|
||||
|
|
|
@ -1,28 +1,7 @@
|
|||
switch process.platform
|
||||
when 'win32'
|
||||
autoUpdater = require './auto-updater/auto-updater-win'
|
||||
module.exports = require './auto-updater/auto-updater-win'
|
||||
when 'darwin'
|
||||
module.exports = require './auto-updater/auto-updater-mac'
|
||||
else
|
||||
# take the default binding for the current platform
|
||||
autoUpdater = process.atomBinding('auto_updater').autoUpdater
|
||||
EventEmitter = require('events').EventEmitter
|
||||
autoUpdater.__proto__ = EventEmitter.prototype
|
||||
|
||||
autoUpdater.on 'update-downloaded-raw', (args...) ->
|
||||
args[3] = new Date(args[3]) # releaseDate
|
||||
@emit 'update-downloaded', args..., => @quitAndInstall()
|
||||
|
||||
autoUpdater.quitAndInstall = ->
|
||||
# If we don't have any window then quitAndInstall immediately.
|
||||
BrowserWindow = require 'browser-window'
|
||||
windows = BrowserWindow.getAllWindows()
|
||||
if windows.length is 0
|
||||
@_quitAndInstall()
|
||||
return
|
||||
|
||||
# Do the restart after all windows have been closed.
|
||||
app = require 'app'
|
||||
app.removeAllListeners 'window-all-closed'
|
||||
app.once 'window-all-closed', @_quitAndInstall.bind(this)
|
||||
win.close() for win in windows
|
||||
|
||||
module.exports = autoUpdater
|
||||
throw new Error('auto-updater is not implemented on this platform')
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
{EventEmitter} = require 'events'
|
||||
{autoUpdater} = process.atomBinding 'auto_updater'
|
||||
|
||||
autoUpdater.__proto__ = EventEmitter.prototype
|
||||
|
||||
module.exports = autoUpdater
|
|
@ -1,45 +1,42 @@
|
|||
app = require 'app'
|
||||
url = require 'url'
|
||||
{EventEmitter} = require 'events'
|
||||
SquirrelUpdate = require './auto-updater/squirrel-update-win'
|
||||
app = require 'app'
|
||||
url = require 'url'
|
||||
|
||||
squirrelUpdate = require './squirrel-update-win'
|
||||
|
||||
class AutoUpdater extends EventEmitter
|
||||
|
||||
quitAndInstall: ->
|
||||
SquirrelUpdate.processStart ->
|
||||
app.quit()
|
||||
squirrelUpdate.processStart()
|
||||
app.quit()
|
||||
|
||||
setFeedUrl: (updateUrl) ->
|
||||
# set feed URL only when it hasn't been set before
|
||||
unless @updateUrl
|
||||
@updateUrl = updateUrl
|
||||
@updateUrl = updateUrl
|
||||
|
||||
checkForUpdates: ->
|
||||
throw new Error('Update URL is not set') unless @updateUrl
|
||||
return @emitError 'Update URL is not set' unless @updateUrl
|
||||
return @emitError 'Can not find Squirrel' unless squirrelUpdate.supported()
|
||||
|
||||
@emit 'checking-for-update'
|
||||
|
||||
unless SquirrelUpdate.supported()
|
||||
@emit 'update-not-available'
|
||||
return
|
||||
|
||||
SquirrelUpdate.download (error, update) =>
|
||||
if error?
|
||||
@emit 'update-not-available'
|
||||
return
|
||||
|
||||
unless update?
|
||||
@emit 'update-not-available'
|
||||
return
|
||||
squirrelUpdate.download @updateUrl, (error, update) =>
|
||||
return @emitError error if error?
|
||||
return @emit 'update-not-available' unless update?
|
||||
|
||||
@emit 'update-available'
|
||||
|
||||
SquirrelUpdate.update @updateUrl, (error) =>
|
||||
if error?
|
||||
@emit 'update-not-available'
|
||||
return
|
||||
squirrelUpdate.update @updateUrl, (error) =>
|
||||
return @emitError error if error?
|
||||
|
||||
# info about the newly installed version and a function any of the event listeners can call to restart the application
|
||||
@emit 'update-downloaded', {}, update.releaseNotes, update.version, new Date(), @updateUrl, => @quitAndInstall()
|
||||
{releaseNotes, version} = update
|
||||
# Following information is not available on Windows, so fake them.
|
||||
date = new Date
|
||||
url = @updateUrl
|
||||
|
||||
module.exports = new AutoUpdater()
|
||||
@emit 'update-downloaded', {}, releaseNotes, version, date, url, => @quitAndInstall()
|
||||
|
||||
# Private: Emit both error object and message, this is to keep compatibility
|
||||
# with Old APIs.
|
||||
emitError: (message) ->
|
||||
@emit 'error', new Error(message), message
|
||||
|
||||
module.exports = new AutoUpdater
|
||||
|
|
|
@ -1,57 +1,67 @@
|
|||
ChildProcess = require 'child_process'
|
||||
fs = require 'fs'
|
||||
path = require 'path'
|
||||
fs = require 'fs'
|
||||
path = require 'path'
|
||||
{spawn} = require 'child_process'
|
||||
|
||||
appFolder = path.dirname process.execPath # i.e. my-app/app-0.1.13/
|
||||
rootApplicationFolder = path.resolve appFolder, '..' # i.e. my-app/
|
||||
updateDotExe = path.join rootApplicationFolder, 'Update.exe'
|
||||
exeName = path.basename process.execPath
|
||||
appFolder = path.dirname process.execPath # i.e. my-app/app-0.1.13/
|
||||
updateExe = path.resolve appFolder, '..', 'Update.exe' # i.e. my-app/Update.exe
|
||||
exeName = path.basename process.execPath
|
||||
|
||||
# Spawn a command and invoke the callback when it completes with an error
|
||||
# and the output from standard out.
|
||||
spawnUpdate = (args, callback) ->
|
||||
stdout = ''
|
||||
|
||||
spawnUpdate = (args, detached, callback) ->
|
||||
try
|
||||
spawnedProcess = ChildProcess.spawn(updateDotExe, args)
|
||||
spawnedProcess = spawn updateExe, args, {detached}
|
||||
catch error
|
||||
# Spawn can throw an error
|
||||
process.nextTick -> callback?(error, stdout)
|
||||
# Shouldn't happen, but still guard it.
|
||||
process.nextTick -> callback error
|
||||
return
|
||||
|
||||
stdout = ''
|
||||
stderr = ''
|
||||
spawnedProcess.stdout.on 'data', (data) -> stdout += data
|
||||
spawnedProcess.stderr.on 'data', (data) -> stderr += data
|
||||
|
||||
error = null
|
||||
spawnedProcess.on 'error', (processError) -> error ?= processError
|
||||
spawnedProcess.on 'close', (code, signal) ->
|
||||
error ?= new Error("Command failed: #{signal ? code}") if code isnt 0
|
||||
error?.code ?= code
|
||||
error?.stdout ?= stdout
|
||||
callback?(error, stdout)
|
||||
errorEmitted = false
|
||||
spawnedProcess.on 'error', (error) ->
|
||||
errorEmitted = true
|
||||
callback error
|
||||
spawnedProcess.on 'exit', (code, signal) ->
|
||||
# We may have already emitted an error.
|
||||
return if errorEmitted
|
||||
|
||||
processStart = (callback) ->
|
||||
spawnUpdate(['--processStart', exeName], callback)
|
||||
# Process terminated with error.
|
||||
if code isnt 0
|
||||
return callback "Command failed: #{signal ? code}\n#{stderr}"
|
||||
|
||||
download = (callback) ->
|
||||
spawnUpdate ['--download', @updateUrl], (error, stdout) ->
|
||||
# Success.
|
||||
callback null, stdout
|
||||
|
||||
# Start an instance of the installed app.
|
||||
exports.processStart = (callback) ->
|
||||
spawnUpdate ['--processStart', exeName], true, ->
|
||||
|
||||
# Download the releases specified by the URL and write new results to stdout.
|
||||
exports.download = (updateUrl, callback) ->
|
||||
spawnUpdate ['--download', updateUrl], false, (error, stdout) ->
|
||||
return callback(error) if error?
|
||||
|
||||
try
|
||||
# Last line of output is the JSON details about the releases
|
||||
json = stdout.trim().split('\n').pop()
|
||||
json = stdout.trim().split('\n').pop()
|
||||
update = JSON.parse(json)?.releasesToApply?.pop?()
|
||||
catch error
|
||||
error.stdout = stdout
|
||||
return callback(error)
|
||||
catch
|
||||
return callback "Invalid result:\n#{stdout}"
|
||||
|
||||
callback(null, update)
|
||||
callback null, update
|
||||
|
||||
update = (updateUrl, callback) ->
|
||||
spawnUpdate ['--update', updateUrl], callback
|
||||
# Update the application to the latest remote version specified by URL.
|
||||
exports.update = (updateUrl, callback) ->
|
||||
spawnUpdate ['--update', updateUrl], false, callback
|
||||
|
||||
# Is the Update.exe installed with the current application?
|
||||
exports.supported = ->
|
||||
fs.accessSync(updateDotExe, fs.R_OK)
|
||||
exports.processStart = processStart
|
||||
exports.download = download
|
||||
exports.update = update
|
||||
try
|
||||
fs.accessSync updateExe, fs.R_OK
|
||||
return true
|
||||
catch
|
||||
return false
|
||||
|
|
|
@ -6,22 +6,25 @@
|
|||
|
||||
namespace auto_updater {
|
||||
|
||||
AutoUpdaterDelegate* AutoUpdater::delegate_ = NULL;
|
||||
Delegate* AutoUpdater::delegate_ = nullptr;
|
||||
|
||||
AutoUpdaterDelegate* AutoUpdater::GetDelegate() {
|
||||
Delegate* AutoUpdater::GetDelegate() {
|
||||
return delegate_;
|
||||
}
|
||||
|
||||
void AutoUpdater::SetDelegate(AutoUpdaterDelegate* delegate) {
|
||||
void AutoUpdater::SetDelegate(Delegate* delegate) {
|
||||
delegate_ = delegate;
|
||||
}
|
||||
|
||||
#if defined(OS_MACOSX) && defined(MAS_BUILD)
|
||||
#if !defined(OS_MACOSX) || defined(MAS_BUILD)
|
||||
void AutoUpdater::SetFeedURL(const std::string& url) {
|
||||
}
|
||||
|
||||
void AutoUpdater::CheckForUpdates() {
|
||||
}
|
||||
|
||||
void AutoUpdater::QuitAndInstall() {
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace auto_updater
|
||||
|
|
|
@ -9,21 +9,48 @@
|
|||
|
||||
#include "base/basictypes.h"
|
||||
|
||||
namespace base {
|
||||
class Time;
|
||||
}
|
||||
|
||||
namespace auto_updater {
|
||||
|
||||
class AutoUpdaterDelegate;
|
||||
class Delegate {
|
||||
public:
|
||||
// An error happened.
|
||||
virtual void OnError(const std::string& error) {}
|
||||
|
||||
// Checking to see if there is an update
|
||||
virtual void OnCheckingForUpdate() {}
|
||||
|
||||
// There is an update available and it is being downloaded
|
||||
virtual void OnUpdateAvailable() {}
|
||||
|
||||
// There is no available update.
|
||||
virtual void OnUpdateNotAvailable() {}
|
||||
|
||||
// There is a new update which has been downloaded.
|
||||
virtual void OnUpdateDownloaded(const std::string& release_notes,
|
||||
const std::string& release_name,
|
||||
const base::Time& release_date,
|
||||
const std::string& update_url) {}
|
||||
|
||||
protected:
|
||||
virtual ~Delegate() {}
|
||||
};
|
||||
|
||||
class AutoUpdater {
|
||||
public:
|
||||
// Gets/Sets the delegate.
|
||||
static AutoUpdaterDelegate* GetDelegate();
|
||||
static void SetDelegate(AutoUpdaterDelegate* delegate);
|
||||
static Delegate* GetDelegate();
|
||||
static void SetDelegate(Delegate* delegate);
|
||||
|
||||
static void SetFeedURL(const std::string& url);
|
||||
static void CheckForUpdates();
|
||||
static void QuitAndInstall();
|
||||
|
||||
private:
|
||||
static AutoUpdaterDelegate* delegate_;
|
||||
static Delegate* delegate_;
|
||||
|
||||
DISALLOW_IMPLICIT_CONSTRUCTORS(AutoUpdater);
|
||||
};
|
||||
|
|
|
@ -1,45 +0,0 @@
|
|||
// Copyright (c) 2013 GitHub, Inc.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef ATOM_BROWSER_AUTO_UPDATER_DELEGATE_H_
|
||||
#define ATOM_BROWSER_AUTO_UPDATER_DELEGATE_H_
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "base/callback_forward.h"
|
||||
|
||||
namespace base {
|
||||
class Time;
|
||||
}
|
||||
|
||||
namespace auto_updater {
|
||||
|
||||
class AutoUpdaterDelegate {
|
||||
public:
|
||||
// An error happened.
|
||||
virtual void OnError(const std::string& error) {}
|
||||
|
||||
// Checking to see if there is an update
|
||||
virtual void OnCheckingForUpdate() {}
|
||||
|
||||
// There is an update available and it is being downloaded
|
||||
virtual void OnUpdateAvailable() {}
|
||||
|
||||
// There is no available update.
|
||||
virtual void OnUpdateNotAvailable() {}
|
||||
|
||||
// There is a new update which has been downloaded.
|
||||
virtual void OnUpdateDownloaded(const std::string& release_notes,
|
||||
const std::string& release_name,
|
||||
const base::Time& release_date,
|
||||
const std::string& update_url,
|
||||
const base::Closure& quit_and_install) {}
|
||||
|
||||
protected:
|
||||
virtual ~AutoUpdaterDelegate() {}
|
||||
};
|
||||
|
||||
} // namespace auto_updater
|
||||
|
||||
#endif // ATOM_BROWSER_AUTO_UPDATER_DELEGATE_H_
|
|
@ -1,17 +0,0 @@
|
|||
// Copyright (c) 2013 GitHub, Inc.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "atom/browser/auto_updater.h"
|
||||
|
||||
namespace auto_updater {
|
||||
|
||||
// static
|
||||
void AutoUpdater::SetFeedURL(const std::string& url) {
|
||||
}
|
||||
|
||||
// static
|
||||
void AutoUpdater::CheckForUpdates() {
|
||||
}
|
||||
|
||||
} // namespace auto_updater
|
|
@ -12,9 +12,6 @@
|
|||
#include "base/bind.h"
|
||||
#include "base/time/time.h"
|
||||
#include "base/strings/sys_string_conversions.h"
|
||||
#include "atom/browser/auto_updater_delegate.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
namespace auto_updater {
|
||||
|
||||
|
@ -23,20 +20,12 @@ namespace {
|
|||
// The gloal SQRLUpdater object.
|
||||
SQRLUpdater* g_updater = nil;
|
||||
|
||||
void RelaunchToInstallUpdate() {
|
||||
[[g_updater relaunchToInstallUpdate] subscribeError:^(NSError* error) {
|
||||
AutoUpdaterDelegate* delegate = AutoUpdater::GetDelegate();
|
||||
if (delegate)
|
||||
delegate->OnError(base::SysNSStringToUTF8(error.localizedDescription));
|
||||
}];
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
// static
|
||||
void AutoUpdater::SetFeedURL(const std::string& feed) {
|
||||
if (g_updater == nil) {
|
||||
AutoUpdaterDelegate* delegate = GetDelegate();
|
||||
Delegate* delegate = GetDelegate();
|
||||
if (!delegate)
|
||||
return;
|
||||
|
||||
|
@ -67,7 +56,7 @@ void AutoUpdater::SetFeedURL(const std::string& feed) {
|
|||
|
||||
// static
|
||||
void AutoUpdater::CheckForUpdates() {
|
||||
AutoUpdaterDelegate* delegate = GetDelegate();
|
||||
Delegate* delegate = GetDelegate();
|
||||
if (!delegate)
|
||||
return;
|
||||
|
||||
|
@ -86,8 +75,7 @@ void AutoUpdater::CheckForUpdates() {
|
|||
base::SysNSStringToUTF8(update.releaseNotes),
|
||||
base::SysNSStringToUTF8(update.releaseName),
|
||||
base::Time::FromDoubleT(update.releaseDate.timeIntervalSince1970),
|
||||
base::SysNSStringToUTF8(update.updateURL.absoluteString),
|
||||
base::Bind(RelaunchToInstallUpdate));
|
||||
base::SysNSStringToUTF8(update.updateURL.absoluteString));
|
||||
} else {
|
||||
// When the completed event is sent with no update, then we know there
|
||||
// is no update available.
|
||||
|
@ -100,4 +88,12 @@ void AutoUpdater::CheckForUpdates() {
|
|||
}];
|
||||
}
|
||||
|
||||
void AutoUpdater::QuitAndInstall() {
|
||||
[[g_updater relaunchToInstallUpdate] subscribeError:^(NSError* error) {
|
||||
Delegate* delegate = AutoUpdater::GetDelegate();
|
||||
if (delegate)
|
||||
delegate->OnError(base::SysNSStringToUTF8(error.localizedDescription));
|
||||
}];
|
||||
}
|
||||
|
||||
} // namespace auto_updater
|
||||
|
|
|
@ -1,17 +0,0 @@
|
|||
// Copyright (c) 2013 GitHub, Inc.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "atom/browser/auto_updater.h"
|
||||
|
||||
namespace auto_updater {
|
||||
|
||||
// static
|
||||
void AutoUpdater::SetFeedURL(const std::string& url) {
|
||||
}
|
||||
|
||||
// static
|
||||
void AutoUpdater::CheckForUpdates() {
|
||||
}
|
||||
|
||||
} // namespace auto_updater
|
|
@ -10,6 +10,8 @@ valueToMeta = (sender, value, optimizeSimpleObject=false) ->
|
|||
meta.type = 'buffer' if Buffer.isBuffer value
|
||||
meta.type = 'value' if value is null
|
||||
meta.type = 'array' if Array.isArray value
|
||||
meta.type = 'error' if value instanceof Error
|
||||
meta.type = 'date' if value instanceof Date
|
||||
meta.type = 'promise' if value? and value.constructor.name is 'Promise'
|
||||
|
||||
# Treat simple objects as value.
|
||||
|
@ -36,6 +38,10 @@ valueToMeta = (sender, value, optimizeSimpleObject=false) ->
|
|||
meta.value = Array::slice.call value, 0
|
||||
else if meta.type is 'promise'
|
||||
meta.then = valueToMeta(sender, value.then.bind(value))
|
||||
else if meta.type is 'error'
|
||||
meta.message = value.message
|
||||
else if meta.type is 'date'
|
||||
meta.value = value.getTime()
|
||||
else
|
||||
meta.type = 'value'
|
||||
meta.value = value
|
||||
|
@ -43,8 +49,8 @@ valueToMeta = (sender, value, optimizeSimpleObject=false) ->
|
|||
meta
|
||||
|
||||
# Convert Error into meta data.
|
||||
errorToMeta = (error) ->
|
||||
type: 'error', message: error.message, stack: (error.stack || error)
|
||||
exceptionToMeta = (error) ->
|
||||
type: 'exception', message: error.message, stack: (error.stack || error)
|
||||
|
||||
# Convert array of meta data from renderer into array of real values.
|
||||
unwrapArgs = (sender, args) ->
|
||||
|
@ -100,19 +106,19 @@ ipc.on 'ATOM_BROWSER_REQUIRE', (event, module) ->
|
|||
try
|
||||
event.returnValue = valueToMeta event.sender, process.mainModule.require(module)
|
||||
catch e
|
||||
event.returnValue = errorToMeta e
|
||||
event.returnValue = exceptionToMeta e
|
||||
|
||||
ipc.on 'ATOM_BROWSER_GLOBAL', (event, name) ->
|
||||
try
|
||||
event.returnValue = valueToMeta event.sender, global[name]
|
||||
catch e
|
||||
event.returnValue = errorToMeta e
|
||||
event.returnValue = exceptionToMeta e
|
||||
|
||||
ipc.on 'ATOM_BROWSER_CURRENT_WINDOW', (event) ->
|
||||
try
|
||||
event.returnValue = valueToMeta event.sender, event.sender.getOwnerBrowserWindow()
|
||||
catch e
|
||||
event.returnValue = errorToMeta e
|
||||
event.returnValue = exceptionToMeta e
|
||||
|
||||
ipc.on 'ATOM_BROWSER_CURRENT_WEB_CONTENTS', (event) ->
|
||||
event.returnValue = valueToMeta event.sender, event.sender
|
||||
|
@ -126,7 +132,7 @@ ipc.on 'ATOM_BROWSER_CONSTRUCTOR', (event, id, args) ->
|
|||
obj = new (Function::bind.apply(constructor, [null].concat(args)))
|
||||
event.returnValue = valueToMeta event.sender, obj
|
||||
catch e
|
||||
event.returnValue = errorToMeta e
|
||||
event.returnValue = exceptionToMeta e
|
||||
|
||||
ipc.on 'ATOM_BROWSER_FUNCTION_CALL', (event, id, args) ->
|
||||
try
|
||||
|
@ -134,7 +140,7 @@ ipc.on 'ATOM_BROWSER_FUNCTION_CALL', (event, id, args) ->
|
|||
func = objectsRegistry.get id
|
||||
callFunction event, func, global, args
|
||||
catch e
|
||||
event.returnValue = errorToMeta e
|
||||
event.returnValue = exceptionToMeta e
|
||||
|
||||
ipc.on 'ATOM_BROWSER_MEMBER_CONSTRUCTOR', (event, id, method, args) ->
|
||||
try
|
||||
|
@ -144,7 +150,7 @@ ipc.on 'ATOM_BROWSER_MEMBER_CONSTRUCTOR', (event, id, method, args) ->
|
|||
obj = new (Function::bind.apply(constructor, [null].concat(args)))
|
||||
event.returnValue = valueToMeta event.sender, obj
|
||||
catch e
|
||||
event.returnValue = errorToMeta e
|
||||
event.returnValue = exceptionToMeta e
|
||||
|
||||
ipc.on 'ATOM_BROWSER_MEMBER_CALL', (event, id, method, args) ->
|
||||
try
|
||||
|
@ -152,7 +158,7 @@ ipc.on 'ATOM_BROWSER_MEMBER_CALL', (event, id, method, args) ->
|
|||
obj = objectsRegistry.get id
|
||||
callFunction event, obj[method], obj, args
|
||||
catch e
|
||||
event.returnValue = errorToMeta e
|
||||
event.returnValue = exceptionToMeta e
|
||||
|
||||
ipc.on 'ATOM_BROWSER_MEMBER_SET', (event, id, name, value) ->
|
||||
try
|
||||
|
@ -160,14 +166,14 @@ ipc.on 'ATOM_BROWSER_MEMBER_SET', (event, id, name, value) ->
|
|||
obj[name] = value
|
||||
event.returnValue = null
|
||||
catch e
|
||||
event.returnValue = errorToMeta e
|
||||
event.returnValue = exceptionToMeta e
|
||||
|
||||
ipc.on 'ATOM_BROWSER_MEMBER_GET', (event, id, name) ->
|
||||
try
|
||||
obj = objectsRegistry.get id
|
||||
event.returnValue = valueToMeta event.sender, obj[name]
|
||||
catch e
|
||||
event.returnValue = errorToMeta e
|
||||
event.returnValue = exceptionToMeta e
|
||||
|
||||
ipc.on 'ATOM_BROWSER_DEREFERENCE', (event, id) ->
|
||||
objectsRegistry.remove event.sender.getId(), id
|
||||
|
@ -177,4 +183,4 @@ ipc.on 'ATOM_BROWSER_GUEST_WEB_CONTENTS', (event, guestInstanceId) ->
|
|||
guestViewManager = require './guest-view-manager'
|
||||
event.returnValue = valueToMeta event.sender, guestViewManager.getGuest(guestInstanceId)
|
||||
catch e
|
||||
event.returnValue = errorToMeta e
|
||||
event.returnValue = exceptionToMeta e
|
||||
|
|
|
@ -46,7 +46,9 @@ metaToValue = (meta) ->
|
|||
when 'array' then (metaToValue(el) for el in meta.members)
|
||||
when 'buffer' then new Buffer(meta.value)
|
||||
when 'promise' then Promise.resolve(then: metaToValue(meta.then))
|
||||
when 'error'
|
||||
when 'error' then new Error(meta.message)
|
||||
when 'date' then new Date(meta.value)
|
||||
when 'exception'
|
||||
throw new Error("#{meta.message}\n#{meta.stack}")
|
||||
else
|
||||
if meta.type is 'function'
|
||||
|
|
|
@ -1,106 +1,31 @@
|
|||
# autoUpdater
|
||||
|
||||
**This module has only been implemented for OS X.**
|
||||
This module provides an interface for the `Squirrel` auto-updater framework.
|
||||
|
||||
Check out [atom/grunt-electron-installer](https://github.com/atom/grunt-electron-installer)
|
||||
to build a Windows installer for your app.
|
||||
## Platform notices
|
||||
|
||||
The `auto-updater` module is a simple wrapper around the
|
||||
[Squirrel.Mac](https://github.com/Squirrel/Squirrel.Mac) framework.
|
||||
Though `autoUpdater` provides an uniform API for different platforms, there are
|
||||
still some subtle differences on each platform.
|
||||
|
||||
Squirrel.Mac requires that your `.app` folder is signed using the
|
||||
[codesign](https://developer.apple.com/library/mac/documentation/Darwin/Reference/ManPages/man1/codesign.1.html)
|
||||
utility for updates to be installed.
|
||||
### OS X
|
||||
|
||||
## Squirrel
|
||||
On OS X the `autoUpdater` module is built upon [Squirrel.Mac][squirrel-mac], you
|
||||
don't need any special setup to make it work. For server-side requirements, you
|
||||
can read [Server Support][server-support].
|
||||
|
||||
Squirrel is an OS X framework focused on making application updates **as safe
|
||||
and transparent as updates to a website**.
|
||||
### Windows
|
||||
|
||||
Instead of publishing a feed of versions from which your app must select,
|
||||
Squirrel updates to the version your server tells it to. This allows you to
|
||||
intelligently update your clients based on the request you give to Squirrel.
|
||||
On Windows you have to install your app into user's machine before you can use
|
||||
the auto-updater, it is recommended to use [grunt-electron-installer][installer]
|
||||
module to generate a Windows installer.
|
||||
|
||||
Your request can include authentication details, custom headers or a request
|
||||
body so that your server has the context it needs in order to supply the most
|
||||
suitable update.
|
||||
The server-side setup is also different from OS X, you can read the documents of
|
||||
[Squirrel.Windows][squirrel-windows] to get more details.
|
||||
|
||||
The update JSON Squirrel requests should be dynamically generated based on
|
||||
criteria in the request and whether an update is required. Squirrel relies
|
||||
on server-side support to determine whether an update is required. See
|
||||
[Server Support](#server-support).
|
||||
### Linux
|
||||
|
||||
Squirrel's installer is designed to be fault tolerant and ensures that any
|
||||
updates installed are valid.
|
||||
|
||||
## Update Requests
|
||||
|
||||
Squirrel is indifferent to the request the client application provides for
|
||||
update checking. `Accept: application/json` is added to the request headers
|
||||
because Squirrel is responsible for parsing the response.
|
||||
|
||||
For the requirements imposed on the responses and the body format of an update
|
||||
response, see [Server Support](#server-support).
|
||||
|
||||
Your update request must *at least* include a version identifier so that the
|
||||
server can determine whether an update for this specific version is required. It
|
||||
may also include other identifying criteria, such as operating system version or
|
||||
username, to allow the server to deliver as fine grained an update as you
|
||||
would like.
|
||||
|
||||
How you include the version identifier or other criteria is specific to the
|
||||
server that you are requesting updates from. A common approach is to use query
|
||||
parameters, like this:
|
||||
|
||||
```javascript
|
||||
// In the main process
|
||||
var app = require('app');
|
||||
var autoUpdater = require('auto-updater');
|
||||
autoUpdater.setFeedUrl('http://mycompany.com/myapp/latest?version=' + app.getVersion());
|
||||
```
|
||||
|
||||
## Server Support
|
||||
|
||||
Your server should determine whether an update is required based on the
|
||||
[Update Request](#update-requests) your client issues.
|
||||
|
||||
If an update is required, your server should respond with a status code of
|
||||
[200 OK](http://tools.ietf.org/html/rfc2616#section-10.2.1) and include the
|
||||
[update JSON](#update-json-format) in the body. Squirrel **will** download and
|
||||
install this update, even if the version of the update is the same as the
|
||||
currently running version. To save redundantly downloading the same version
|
||||
multiple times your server must not inform the client to update.
|
||||
|
||||
If no update is required your server must respond with a status code of
|
||||
[204 No Content](http://tools.ietf.org/html/rfc2616#section-10.2.5). Squirrel
|
||||
will check for an update again at the interval you specify.
|
||||
|
||||
## Update JSON Format
|
||||
|
||||
When an update is available, Squirrel expects the following schema in response
|
||||
to the update request provided:
|
||||
|
||||
```json
|
||||
{
|
||||
"url": "http://mycompany.com/myapp/releases/myrelease",
|
||||
"name": "My Release Name",
|
||||
"notes": "Theses are some release notes innit",
|
||||
"pub_date": "2013-09-18T12:29:53+01:00"
|
||||
}
|
||||
```
|
||||
|
||||
The only required key is "url"; the others are optional.
|
||||
|
||||
Squirrel will request "url" with `Accept: application/zip` and only supports
|
||||
installing ZIP updates. If future update formats are supported their MIME type
|
||||
will be added to the `Accept` header so that your server can return the
|
||||
appropriate format.
|
||||
|
||||
`pub_date` (if present) must be formatted according to ISO 8601.
|
||||
|
||||
## Update server implementations
|
||||
|
||||
[Nuts](https://github.com/GitbookIO/nuts) is an open source implementation of the update server described above, it integrates beautifully with GitHub releases. Nuts manages downloads and updates, it’s compatible with `Squirrel.Mac` and `Squirrel.Windows` so you get cross-platform support out of the box.
|
||||
There is not built-in support for auto-updater on Linux, it is recommended to
|
||||
use the distribution's package manager to update your app.
|
||||
|
||||
## Events
|
||||
|
||||
|
@ -110,8 +35,7 @@ The `autoUpdater` object emits the following events:
|
|||
|
||||
Returns:
|
||||
|
||||
* `event` Event
|
||||
* `message` String
|
||||
* `error` Error
|
||||
|
||||
Emitted when there is an error while updating.
|
||||
|
||||
|
@ -137,10 +61,10 @@ Returns:
|
|||
* `releaseName` String
|
||||
* `releaseDate` Date
|
||||
* `updateUrl` String
|
||||
* `quitAndUpdate` Function
|
||||
|
||||
Emitted when an update has been downloaded. Calling `quitAndUpdate()` will
|
||||
restart the application and install the update.
|
||||
Emitted when an update has been downloaded.
|
||||
|
||||
On Windows only `releaseName` is available.
|
||||
|
||||
## Methods
|
||||
|
||||
|
@ -150,10 +74,20 @@ The `autoUpdater` object has the following methods:
|
|||
|
||||
* `url` String
|
||||
|
||||
Set the `url` and initialize the auto updater. The `url` cannot be changed
|
||||
Sets the `url` and initialize the auto updater. The `url` cannot be changed
|
||||
once it is set.
|
||||
|
||||
### `autoUpdater.checkForUpdates()`
|
||||
|
||||
Ask the server whether there is an update. You must call `setFeedUrl` before
|
||||
Asks the server whether there is an update. You must call `setFeedUrl` before
|
||||
using this API.
|
||||
|
||||
### `autoUpdater.quitAndUpdate()`
|
||||
|
||||
Restarts the app and install the update after it has been downloaded. It should
|
||||
only be called after `update-downloaded` has been emitted.
|
||||
|
||||
[squirrel-mac]: https://github.com/Squirrel/Squirrel.Mac
|
||||
[server-support]: https://github.com/Squirrel/Squirrel.Mac#server-support
|
||||
[squirrel-windows]: https://github.com/Squirrel/Squirrel.Windows
|
||||
[installer]: https://github.com/atom/grunt-electron-installer
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
'atom/browser/api/lib/app.coffee',
|
||||
'atom/browser/api/lib/atom-delegate.coffee',
|
||||
'atom/browser/api/lib/auto-updater.coffee',
|
||||
'atom/browser/api/lib/auto-updater/auto-updater-mac.coffee',
|
||||
'atom/browser/api/lib/auto-updater/auto-updater-win.coffee',
|
||||
'atom/browser/api/lib/auto-updater/squirrel-update-win.coffee',
|
||||
'atom/browser/api/lib/browser-window.coffee',
|
||||
|
@ -114,10 +115,7 @@
|
|||
'atom/browser/api/save_page_handler.h',
|
||||
'atom/browser/auto_updater.cc',
|
||||
'atom/browser/auto_updater.h',
|
||||
'atom/browser/auto_updater_delegate.h',
|
||||
'atom/browser/auto_updater_linux.cc',
|
||||
'atom/browser/auto_updater_mac.mm',
|
||||
'atom/browser/auto_updater_win.cc',
|
||||
'atom/browser/atom_access_token_store.cc',
|
||||
'atom/browser/atom_access_token_store.h',
|
||||
'atom/browser/atom_browser_client.cc',
|
||||
|
|
Loading…
Reference in a new issue