Socket
Socket
Sign inDemoInstall

electron-updater

Package Overview
Dependencies
Maintainers
1
Versions
290
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

electron-updater - npm Package Compare versions

Comparing version 0.0.1 to 0.0.2

.travis.yml

136

lib/check.js
var download = require('./download.js'),
semver = require('semver'),
async = require('async'),
path = require('path'),
file = require('./file.js'),
fs = require('fs'),
directory = require('./directory.js'),
AppDirectory = require('appdirectory')
semver = require('semver'),
async = require('async'),
path = require('path'),
file = require('./file.js'),
fs = require('fs'),
directory = require('./directory.js'),
AppDirectory = require('appdirectory')
function satisfy(registry, name, desired, current, exists, callback) {
var url = registry + '/' + name + '/' + desired
download.getJson(url, function (err, data) {
if(err) return callback(err)
var available = semver.clean(data.version)
if(!exists || semver.gt(available, current)) {
return callback(null, {
name: name,
desired: desired,
current: current,
available: available
})
}
var url = registry + '/' + name + '/' + desired
download.getJson(url, function (err, data) {
if(err) return callback(err)
var available = semver.clean(data.version)
if(!exists || semver.gt(available, current)) {
return callback(null, {
name: name,
desired: desired,
current: current,
available: available
})
}
// We already have the most up-to-date version
callback()
})
// We already have the most up-to-date version
callback()
})
}
function checkApp(context, callback) {
var registry = context.registry
var name = context.name
var desired = context.channel
var current = context.version
satisfy(registry, name, desired, current, true, callback)
var registry = context.registry
var name = context.name
var desired = context.channel
var current = context.version
satisfy(registry, name, desired, current, true, callback)
}
function checkDependency(name, callback) {
var appName = this.name
var registry = this.registry
var desired = this.dependencies[name]
var packagePath = path.join(this.appDir, 'node_modules', name, 'package.json')
file.readJson(packagePath, function (err, pkg) {
var exists = !err
var current = (pkg && pkg.version) || '0.0.0'
satisfy(registry, name, desired, current, exists, callback)
})
var appName = this.name
var registry = this.registry
var desired = this.dependencies[name]
var packagePath = path.join(this.appDir, 'node_modules', name, 'package.json')
file.readJson(packagePath, function (err, pkg) {
var exists = !err
var current = (pkg && pkg.version) || '0.0.0'
satisfy(registry, name, desired, current, exists, callback)
})
}
function checkPlugin(name, callback) {
var appName = this.name
var appVersion = this.version
var registry = this.registry
var desired = this.plugins[name]
var dirs = new AppDirectory(appName)
var appData = path.dirname(dirs.userData())
var currentPluginsPath = path.join(appData, '.current')
file.readJson(currentPluginsPath, function (err, data) {
var current = (data && data[name]) || '0.0.0'
var pluginPackagePath = path.join(appData, 'plugins', name, current, 'package.json')
fs.stat(pluginPackagePath, function (err, stat) {
var exists = !err
satisfy(registry, name, desired, current, exists, callback)
})
})
var appName = this.name
var appVersion = this.version
var registry = this.registry
var desired = this.plugins[name]
var dirs = new AppDirectory(appName)
var appData = path.dirname(dirs.userData())
var currentPluginsPath = path.join(appData, '.current')
file.readJson(currentPluginsPath, function (err, data) {
var current = (data && data[name]) || '0.0.0'
var pluginPackagePath = path.join(appData, 'plugins', name, current, 'package.json')
var pluginPackageLinkPath = path.join(appData, 'plugins', name, 'link', 'package.json')
fs.stat(pluginPackageLinkPath, function (linkErr, stat) {
fs.stat(pluginPackagePath, function (err, stat) {
if (!linkErr) return callback(false)
var exists = !err
satisfy(registry, name, desired, current, exists, callback)
})
})
})
}
function check(item, callback) {
switch(item.kind) {
case 'app':
checkApp(item.context, callback)
break;
case 'dependencies':
async.map(Object.getOwnPropertyNames(item.context.dependencies), checkDependency.bind(item.context), callback)
break;
case 'plugins':
async.map(Object.getOwnPropertyNames(item.context.plugins), checkPlugin.bind(item.context), callback)
break;
default:
return callback(new Error('invalid dependency kind detected'))
}
switch(item.kind) {
case 'app':
checkApp(item.context, callback)
break;
case 'dependencies':
async.map(Object.getOwnPropertyNames(item.context.dependencies), checkDependency.bind(item.context), callback)
break;
case 'plugins':
async.map(Object.getOwnPropertyNames(item.context.plugins), checkPlugin.bind(item.context), callback)
break;
default:
return callback(new Error('invalid dependency kind detected'))
}
}
module.exports = {
check: check
check: check
}

@@ -10,2 +10,3 @@ var util = require('util'),

copier = require('./copier.js'),
file = require('./file.js'),
AppDirectory = require('appdirectory'),

@@ -18,7 +19,11 @@ EventEmitter = require('events').EventEmitter,

function update(appDir, callback) {
function update(appDir, callback) {
if(typeof appDir === 'function') {
callback = appDir
appDir = path.dirname(process.mainModule.filename)
}
check(appDir, function (err, results) {
if(err) return callback(err)
if(!results) return callback()
updater.update(results, callback);
updater.update(results, callback)
})

@@ -104,3 +109,3 @@ }

copier.copy(process.execPath, appName, function (err, tmpExecPath) {
// todo: log error
if(err) return callback(err)
var updateDir = path.resolve(path.join(__dirname, '..'))

@@ -123,22 +128,22 @@ var appDir = path.dirname(process.mainModule.filename)

function start(appDir) {
function start(appDir, callback) {
var that = this
if(typeof appDir === 'function') {
callback = appDir
appDir = null
}
appDir = appDir || path.dirname(process.mainModule.filename)
context.load(appDir, function (err, ctx) {
// todo: handle error
if(err) return callback(err)
if(ctx.pendingUpdate) {
// If there is a pending update, do a full update instead of starting the app.
// This is set when a dependency update is available.
console.log('pending update.')
fullUpdate(ctx.name, function (err) {
if(err) return callback(err)
that.emit('updateRequired')
callback()
})
} else {
isValid(appDir, function (err, valid) {
if(err) {
console.log('Error starting electron-updater')
console.log(err)
return;
}
if(err) return callback(err)
if(valid) {

@@ -151,4 +156,4 @@ // If the app is valid, then go ahead and startup what we have.

check(appDir, function (err, result) {
//todo: handle error
if(result && (result.app || result.dependencies)) {
if(err) return callback(err)
if(result && (result.app || result.dependencies.length)) {
// If a new version of the app is available or

@@ -161,18 +166,23 @@ // a dependency update is available, we must

file.touch(pendingUpdatePath, function (err) {
if(err) return callback(err)
that.emit('updateAvailable')
callback()
})
} else if (result && result.plugins) {
} else if (result && result.plugins.length) {
// If only plugin updates are available we can go ahead and update those
// right now and then notify the user that they can restart to apply them.
updater.update(results, function (err) {
// todo: log errors
this.emit('updateAvailable')
updater.update(result, function (err) {
if(err) return callback(err)
that.emit('updateAvailable')
callback()
})
} else {
callback()
}
})
} else {
console.log('mandatory update.')
fullUpdate(ctx.name, function (err) {
if(err) return console.log(err)
if(err) return callback(err)
that.emit('updateRequired')
callback()
})

@@ -179,0 +189,0 @@ }

var directory = require('./directory.js'),
path = require('path'),
fs = require('fs'),
async = require('async'),
file = require('./file.js'),
AppDirectory = require('appdirectory')
path = require('path'),
fs = require('fs'),
async = require('async'),
file = require('./file.js'),
AppDirectory = require('appdirectory')
function isDevDirectory(appDir, callback) {
var gitDir = path.join(appDir, '.git')
var svnDir = path.join(appDir, '.svn')
fs.readdir(gitDir, function (err) {
if(!err) return callback(true)
fs.readdir(svnDir, function (err) {
if(!err) return callback(true)
callback(false)
})
})
var gitDir = path.join(appDir, '.git')
var svnDir = path.join(appDir, '.svn')
fs.readdir(gitDir, function (err) {
if(!err) return callback(true)
fs.readdir(svnDir, function (err) {
if(!err) return callback(true)
callback(false)
})
})
}
function load(appDir, callback) {
if(!appDir || !callback) throw new Error('Failed to load app context: invalid argument')
isDevDirectory(appDir, function (dev) {
var packagePath = path.join(appDir, 'package.json')
file.readJson(packagePath, function (err, package) {
if (err) return callback(err)
var name = package.name
var version = package.version
var dirs = new AppDirectory(name)
var appData = path.dirname(dirs.userData())
var pendingUpdatePath = path.join(appData, '.update')
var channelPath = path.join(appData, '.channel')
fs.readFile(channelPath, function (err, channel) {
channel = channel || 'latest'
fs.stat(pendingUpdatePath, function (err, stat) {
var pendingUpdate = !err && stat.isFile()
callback(null, {
name: name,
version: version,
channel: channel,
dev: dev,
pendingUpdate: pendingUpdate,
registry: "https://registry.npmjs.org", // resolve from .npmrc's
appDir: appDir,
dependencies: package.dependencies || {},
plugins: package.plugins || {}
})
})
})
})
})
if(!appDir || !callback) throw new Error('Failed to load app context: invalid argument')
isDevDirectory(appDir, function (dev) {
var packagePath = path.join(appDir, 'package.json')
file.readJson(packagePath, function (err, package) {
if (err) return callback(err)
var name = package.name
var version = package.version
var dirs = new AppDirectory(name)
var appData = path.dirname(dirs.userData())
var pendingUpdatePath = path.join(appData, '.update')
var channelPath = path.join(appData, '.channel')
fs.readFile(channelPath, function (err, channel) {
channel = channel || 'latest'
fs.stat(pendingUpdatePath, function (err, stat) {
var pendingUpdate = !err && stat.isFile()
callback(null, {
name: name,
version: version,
channel: channel,
dev: dev,
pendingUpdate: pendingUpdate,
registry: "https://registry.npmjs.org", // resolve from .npmrc's
appDir: appDir,
dependencies: package.dependencies || {},
plugins: package.plugins || {}
})
})
})
})
})
}
module.exports = {
load: load
load: load
}
var directory = require('./directory.js'),
file = require('./file.js'),
fs = process.versions.electron ? require('original-fs') : require('fs'),
path = require('path'),
util = require('util'),
AppDirectory = require('appdirectory')
file = require('./file.js'),
fs = process.versions.electron ? require('original-fs') : require('fs'),
path = require('path'),
util = require('util'),
AppDirectory = require('appdirectory')
var whitelist = [
'resources',
'default_app',
'locales'
'resources',
'default_app',
'locales'
]
function copyFile(sourceDir, destDir, name, callback) {
var sourceFile = path.join(sourceDir, name)
var destFile = path.join(destDir, name)
fs.stat(sourceFile, function (err, sourceStat) {
if(err) return callback(err);
fs.stat(destFile, function (err, destStat) {
if(sourceStat.isFile() && (err || !destStat || (sourceStat.mtime > destStat.mtime))) {
file.copy(sourceFile, destFile, callback)
} else if(sourceStat.isDirectory() && whitelist.indexOf(path.basename(sourceFile)) >= 0) {
copyDir(sourceFile, destFile, callback)
} else {
callback()
}
})
})
var sourceFile = path.join(sourceDir, name)
var destFile = path.join(destDir, name)
fs.stat(sourceFile, function (err, sourceStat) {
if(err) return callback(err);
fs.stat(destFile, function (err, destStat) {
if(sourceStat.isFile() && (err || !destStat || (sourceStat.mtime > destStat.mtime))) {
file.copy(sourceFile, destFile, callback)
} else if(sourceStat.isDirectory() && whitelist.indexOf(path.basename(sourceFile)) >= 0) {
copyDir(sourceFile, destFile, callback)
} else {
callback()
}
})
})
}
function copyDir(sourceDir, destDir, callback) {
directory.create(destDir, function () {
fs.readdir(sourceDir, function (err, files) {
if(err) return callback(err);
async.forEach(
files,
function (f, callback) {
copyFile(sourceDir, destDir, f, callback)
},
callback)
})
})
directory.create(destDir, function () {
fs.readdir(sourceDir, function (err, files) {
if(err) return callback(err);
async.forEach(
files,
function (f, callback) {
copyFile(sourceDir, destDir, f, callback)
},
callback)
})
})
}
function copy(execPath, appName, callback) {
var execDir = path.dirname(execPath)
var dirs = new AppDirectory(appName)
var appData = path.dirname(dirs.userData())
var electronVersion = process.versions.electron
var updateDir = path.join(appData, 'updater', electronVersion)
console.log('copying...')
copyDir(execDir, updateDir, function (err) {
if(err) return callback(err);
callback(null, path.join(updateDir, path.basename(execPath)))
})
var execDir = path.join(path.dirname(execPath))
var dirs = new AppDirectory(appName)
var appData = path.dirname(dirs.userData())
var electronVersion = process.versions.electron
var updateDir = path.join(appData, 'updater', electronVersion)
copyDir(execDir, updateDir, function (err) {
if(err) return callback(err);
callback(null, path.join(updateDir, path.basename(execPath)))
})
}
module.exports = {
copy: copy
copy: copy
}

@@ -8,38 +8,35 @@

function remove(directory, callback) {
fs.lstat(directory, function (err, stat) {
if(err) return callback(err)
if(stat.isDirectory()) {
fs.readdir(directory, function (err, files) {
if(err) return callback(err)
async.map(
files,
function (f, c) {
remove(path.join(directory, f), c)
},
function (err) {
if(err) return callback(err)
fs.rmdir(directory, callback)
})
})
} else {
fs.unlink(directory, callback)
}
})
fs.lstat(directory, function (err, stat) {
if(err) return callback(err)
if(stat.isDirectory()) {
fs.readdir(directory, function (err, files) {
if(err) return callback(err)
async.map(
files,
function (f, c) {
remove(path.join(directory, f), c)
},
function (err) {
if(err) return callback(err)
fs.rmdir(directory, callback)
})
})
} else {
fs.unlink(directory, callback)
}
})
}
function create(directory, callback) {
var parent = path.dirname(directory)
if (!parent || parent === directory) return callback() // root, skip
create(parent, function (error) { // create parent dir
if (error) return callback(error) // couldn't create parent, exit
fs.access(directory, function (error) { // see if folder exists
if (!error) return callback() // already exists, skip
fs.mkdir(directory, callback) // create the directory
})
})
var parent = path.dirname(directory)
if (!parent || parent === directory) return callback() // root, skip
create(parent, function (error) { // create parent dir
if (error && error.code !== 'EEXIST') return callback(error) // failed unexpectedly, exit
fs.mkdir(directory, callback) // create the directory
})
}
module.exports = {
remove: remove,
create: create
create: create,
remove: remove
}

@@ -17,3 +17,3 @@ var util = require('util')

redirects++;
_get(res.headers.location);
_get(res.headers.location)
}

@@ -23,19 +23,7 @@ } else if(res.statusCode === 200) {

} else {
function errorHandler(err, data) {
callback(new Error(util.inspect({
code: res.statusCode,
data: data,
url: url,
headers: res.headers
})))
}
var message = ''
res.setEncoding('utf8')
res.on('data', function (data) {
message += data
})
res.on('end', function () {
return errorHandler(null, message)
})
res.on('error', errorHandler)
var e = new Error('Download failed.')
e.code = res.statusCode
e.url = url
e.headers = res.headers
callback(e, res)
}

@@ -46,3 +34,3 @@ })

_get(url);
_get(url)
}

@@ -52,3 +40,2 @@

get(url, function (err, res) {
if(err) return callback(err)
var json = ''

@@ -61,3 +48,8 @@ res.setEncoding('utf8')

var obj = JSON.parse(json)
return callback(null, obj)
if (err) {
err.data = obj
return callback(err)
} else {
return callback(null, obj)
}
})

@@ -64,0 +56,0 @@ res.on('error', callback)

@@ -8,4 +8,8 @@ var fs = process.versions.electron ? require('original-fs') : require('fs'),

if(err) return callback(err)
var j = JSON.parse(data)
callback(null, j)
try {
var j = JSON.parse(data)
callback(null, j)
} catch (e) {
callback(e)
}
})

@@ -12,0 +16,0 @@ }

@@ -9,3 +9,2 @@ var path = require('path'),

function extract(dir, res, callback) {
console.log('creating dir: ' + dir)
directory.create(dir, function (err) {

@@ -19,14 +18,13 @@ if(err) return callback(err)

})
var name = header.name.split('/');
var name = header.name.split('/')
if (name[0] === 'package')
name.shift();
var joinedName = path.join.apply(path, name);
var outPath = path.join(dir, joinedName);
name.shift()
var joinedName = path.join.apply(path, name)
var outPath = path.join(dir, joinedName)
if(header.type === 'file') {
console.log('Extracting: ' + joinedName);
var outdir = path.dirname(outPath);
var outdir = path.dirname(outPath)
directory.create(outdir, function (err) {
if(err) return callback(err)
var outFile = fs.createWriteStream(outPath);
stream.pipe(outFile);
var outFile = fs.createWriteStream(outPath)
stream.pipe(outFile)
});

@@ -36,13 +34,13 @@ } else if(header.type === 'directory') {

if(err) return callback(err)
stream.resume();
});
stream.resume()
})
} else {
console.log(' unexpected kind of file: ' + header.type);
// else unsupported type
stream.resume()
}
});
})
e.on('finish', function () {
console.log('Extraction complete.')
callback();
callback()
});
res.pipe(z).pipe(e);
res.pipe(z).pipe(e)
})

@@ -49,0 +47,0 @@ }

@@ -31,3 +31,2 @@ var util = require('util'),

function updatePlugin(name, version, context, callback) {
console.log('updating plugin: ' + name)
var dirs = new AppDirectory(context.name)

@@ -37,2 +36,4 @@ var appData = path.dirname(dirs.userData())

var dir = path.join(pluginsDir, name, version)
var dir = path.join(pluginsDir, name, version)
var url = context.registry + '/' + name + '/' + version

@@ -82,14 +83,29 @@ download.getJson(url, function (err, data) {

function updateApp(dir, name, version, context, callback) {
var url = context.registry + '/' + name + '/' + version
download.getJson(url, function (err, data) {
if(err) return callback(err)
var payloadUrl = data.dist.tarball
download.get(payloadUrl, function (err, res) {
if(err) return callback(err)
unpacker.extract(dir, res, callback)
})
})
}
function updateEach(dep, callback) {
var context = this
switch(dep.kind) {
case 'app':
updateApp(context.appDir, dep.name, dep.version, context, callback)
break
case 'dependency':
updateDependency(context.appDir, dep.name, dep.version, context, callback)
break;
break
case 'plugin':
updatePlugin(dep.name, dep.version, context, callback)
break;
break
default:
callback(new Error('Updating unexpected kind.'))
break;
break
}

@@ -99,5 +115,2 @@ }

function update(deps, callback) {
// todo: update primary package itself
// todo: get prebuilt binaries for packages
// todo: update dependencies/plugins recursively
var updateContexts = []

@@ -104,0 +117,0 @@ if(deps.app && !deps.context.dev) {

{
"name": "electron-updater",
"version": "0.0.1",
"version": "0.0.2",
"description": "Cross platform auto-updater for electron applications",

@@ -37,6 +37,10 @@ "main": "index.js",

"devDependencies": {
"chai": "^2.3.0",
"colors": "^1.1.0",
"commander": "^2.8.1",
"shelljs": "^0.4.0"
"mocha": "^2.2.4",
"proxyquire": "^1.4.0",
"shelljs": "^0.4.0",
"sinon": "^1.14.1"
}
}

@@ -1,6 +0,12 @@

# electron-updater
# electron-updater
Cross platform auto-updater for electron apps
> Work in progress...
[![Build Status](https://travis-ci.org/EvolveLabs/electron-updater.svg?branch=master)](https://travis-ci.org/EvolveLabs/electron-updater)
# Install
There are two separate packages that make up the `electron-updater`. The updater itself runs in your app's main process while the plugins project loads the plugins downloaded by the updater into the render process. If you don't use plugins, then you don't need the second project.
$ npm install electron-updater --save
$ npm install electron-plugins --save
## Features

@@ -13,2 +19,84 @@ * Update notifications

* Leverages npm for distribution
* Fully based on javascript and node
* Fully based on javascript and node
* Designed for [`electron`](https://github.com/atom/electron)
## Example main.js
```JavaScript
var app = require('app'),
ipc = require('ipc'),
util = require('util'),
BrowserWindow = require('browser-window'),
updater = require('electron-updater')
require('crash-reporter').start()
var mainWindow = null
app.on('window-all-closed', function() {
if (process.platform != 'darwin')
app.quit()
})
app.on('ready', function() {
// Instead of launching your window right away, start the updater
// to check to see if the app is valid or not.
// An app is invalid if any of its dependencies or plugins are missing.
// In this case the updater will begin a 'full' update. Once updated
// your app will be re-launched.
updater.on('ready', function () {
// This event is called if your app is currently valid.
// It may be out-of-date but it has all of the necessary
// dependencies and plugins to launch right now.
// Your app maybe also receive an update-available event following this
mainWindow = new BrowserWindow({width: 800, height: 600})
mainWindow.loadUrl('file://' + __dirname + '/index.html')
mainWindow.openDevTools({detach:true})
mainWindow.on('closed', function() {
mainWindow = null;
});
})
updater.on('updateRequired', function () {
// This event is fired if your app is not currently valid at startup.
// The app must be exited immediately and the auto-updater will be run instead.
// After the auto-update runs the app will be re-run.
app.quit();
})
updater.on('updateAvailable', function () {
// This event is fired after new versions of plugins have been downloaded and
// before the app and dependencies are downloaded. Plugins are installed side-by-side
// so they can be downloaded while the app is running.
// After the app is restarted it will watch for updates and fire the updated required
// event when newer versions are available.
if(mainWindow) {
// Send a message to your view(s)
mainWindow.webContents.send('update-available');
}
})
updater.start()
})
```
## Example index.js (running in render process)
```JavaScript
var plugins = require('electron-plugins'),
util = require('util'),
ipc = require('ipc')
document.addEventListener('DOMContentLoaded', function () {
var context = { document: document }
plugins.load(context, function (err, loaded) {
if(err) return console.error(err)
console.log('Plugins loaded successfully.')
})
})
ipc.on('update-available', function () {
console.log('there is an update available for download')
})
```
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc