diff --git a/atom.gyp b/atom.gyp
index 9d667410523..202a414003f 100644
--- a/atom.gyp
+++ b/atom.gyp
@@ -4,7 +4,7 @@
'product_name%': 'Electron',
'company_name%': 'GitHub, Inc',
'company_abbr%': 'github',
- 'version%': '0.35.1',
+ 'version%': '0.35.2',
},
'includes': [
'filenames.gypi',
diff --git a/atom/browser/resources/mac/Info.plist b/atom/browser/resources/mac/Info.plist
index 481945b8e89..fb4a2332334 100644
--- a/atom/browser/resources/mac/Info.plist
+++ b/atom/browser/resources/mac/Info.plist
@@ -17,9 +17,9 @@
CFBundleIconFile
atom.icns
CFBundleVersion
- 0.35.1
+ 0.35.2
CFBundleShortVersionString
- 0.35.1
+ 0.35.2
LSApplicationCategoryType
public.app-category.developer-tools
LSMinimumSystemVersion
diff --git a/atom/browser/resources/win/atom.rc b/atom/browser/resources/win/atom.rc
index 875727cdaff..773871fd558 100644
--- a/atom/browser/resources/win/atom.rc
+++ b/atom/browser/resources/win/atom.rc
@@ -56,8 +56,8 @@ END
//
VS_VERSION_INFO VERSIONINFO
- FILEVERSION 0,35,1,0
- PRODUCTVERSION 0,35,1,0
+ FILEVERSION 0,35,2,0
+ PRODUCTVERSION 0,35,2,0
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
@@ -74,12 +74,12 @@ BEGIN
BEGIN
VALUE "CompanyName", "GitHub, Inc."
VALUE "FileDescription", "Electron"
- VALUE "FileVersion", "0.35.1"
+ VALUE "FileVersion", "0.35.2"
VALUE "InternalName", "electron.exe"
VALUE "LegalCopyright", "Copyright (C) 2015 GitHub, Inc. All rights reserved."
VALUE "OriginalFilename", "electron.exe"
VALUE "ProductName", "Electron"
- VALUE "ProductVersion", "0.35.1"
+ VALUE "ProductVersion", "0.35.2"
VALUE "SquirrelAwareVersion", "1"
END
END
diff --git a/atom/common/api/atom_api_asar.cc b/atom/common/api/atom_api_asar.cc
index 489118bd70a..4ea7d8c5c36 100644
--- a/atom/common/api/atom_api_asar.cc
+++ b/atom/common/api/atom_api_asar.cc
@@ -54,7 +54,6 @@ class Archive : public mate::Wrappable {
mate::Dictionary dict(isolate, v8::Object::New(isolate));
dict.Set("size", stats.size);
dict.Set("offset", stats.offset);
- dict.Set("executable", stats.executable);
dict.Set("isFile", stats.is_file);
dict.Set("isDirectory", stats.is_directory);
dict.Set("isLink", stats.is_link);
diff --git a/atom/common/asar/archive.cc b/atom/common/asar/archive.cc
index 61b22e9013f..ab93e301b1a 100644
--- a/atom/common/asar/archive.cc
+++ b/atom/common/asar/archive.cc
@@ -13,6 +13,7 @@
#include "atom/common/asar/scoped_temporary_file.h"
#include "base/files/file.h"
+#include "base/files/file_util.h"
#include "base/logging.h"
#include "base/pickle.h"
#include "base/json/json_reader.h"
@@ -96,7 +97,6 @@ bool FillFileInfoWithNode(Archive::FileInfo* info,
return false;
info->size = static_cast(size);
- info->unpacked = false;
if (node->GetBoolean("unpacked", &info->unpacked) && info->unpacked)
return true;
@@ -107,7 +107,6 @@ bool FillFileInfoWithNode(Archive::FileInfo* info,
return false;
info->offset += header_size;
- info->executable = false;
node->GetBoolean("executable", &info->executable);
return true;
@@ -276,6 +275,13 @@ bool Archive::CopyFileOut(const base::FilePath& path, base::FilePath* out) {
if (!temp_file->InitFromFile(&file_, info.offset, info.size))
return false;
+#if defined(OS_POSIX)
+ if (info.executable) {
+ // chmod a+x temp_file;
+ base::SetPosixFilePermissions(temp_file->path(), 0755);
+ }
+#endif
+
*out = temp_file->path();
external_files_.set(path, temp_file.Pass());
return true;
diff --git a/atom/common/asar/archive.h b/atom/common/asar/archive.h
index fb52c6265d3..de5b9de605a 100644
--- a/atom/common/asar/archive.h
+++ b/atom/common/asar/archive.h
@@ -25,7 +25,7 @@ class ScopedTemporaryFile;
class Archive {
public:
struct FileInfo {
- FileInfo() : size(0), offset(0) {}
+ FileInfo() : unpacked(false), executable(false), size(0), offset(0) {}
bool unpacked;
bool executable;
uint32 size;
diff --git a/atom/common/atom_version.h b/atom/common/atom_version.h
index 093da7b5c60..b5cc0982d0d 100644
--- a/atom/common/atom_version.h
+++ b/atom/common/atom_version.h
@@ -7,7 +7,7 @@
#define ATOM_MAJOR_VERSION 0
#define ATOM_MINOR_VERSION 35
-#define ATOM_PATCH_VERSION 1
+#define ATOM_PATCH_VERSION 2
#define ATOM_VERSION_IS_RELEASE 1
diff --git a/atom/common/lib/asar.coffee b/atom/common/lib/asar.coffee
index fba3faed8ce..f7eeceb3f31 100644
--- a/atom/common/lib/asar.coffee
+++ b/atom/common/lib/asar.coffee
@@ -1,6 +1,5 @@
asar = process.binding 'atom_common_asar'
child_process = require 'child_process'
-fs = require 'fs'
path = require 'path'
util = require 'util'
@@ -84,11 +83,6 @@ overrideAPISync = (module, name, arg = 0) ->
newPath = archive.copyFileOut filePath
notFoundError asarPath, filePath unless newPath
- stat = archive.stat filePath
-
- if stat.executable
- fs.chmodSync(newPath, 0o755)
-
arguments[arg] = newPath
old.apply this, arguments
@@ -108,11 +102,6 @@ overrideAPI = (module, name, arg = 0) ->
newPath = archive.copyFileOut filePath
return notFoundError asarPath, filePath, callback unless newPath
- stat = archive.stat filePath
-
- if stat.executable
- fs.chmodSync(newPath, 0o755)
-
arguments[arg] = newPath
old.apply this, arguments
diff --git a/docs/api/global-shortcut.md b/docs/api/global-shortcut.md
index a0f069d7f1c..ab6123bd877 100644
--- a/docs/api/global-shortcut.md
+++ b/docs/api/global-shortcut.md
@@ -46,7 +46,10 @@ The `global-shortcut` module has the following methods:
* `callback` Function
Registers a global shortcut of `accelerator`. The `callback` is called when
-the registered shortcut is pressed by the user.
+the registered shortcut is pressed by the user. Returns `true` if the shortcut
+`accelerator` was registered, `false` otherwise. For example, the specified
+`accelerator` has already been registered by another caller or other native
+applications.
### `globalShortcut.isRegistered(accelerator)`
diff --git a/docs/api/web-contents.md b/docs/api/web-contents.md
index 2612d621227..e976b0ddb81 100644
--- a/docs/api/web-contents.md
+++ b/docs/api/web-contents.md
@@ -499,7 +499,14 @@ win.webContents.on("did-finish-load", function() {
* `path` String
-Adds the specified path to DevTools workspace.
+Adds the specified path to DevTools workspace. Must be used after DevTools
+creation:
+
+```javascript
+mainWindow.webContents.on('devtools-opened', function() {
+ mainWindow.webContents.addWorkSpace(__dirname);
+});
+```
### `webContents.removeWorkSpace(path)`
diff --git a/docs/tutorial/application-packaging.md b/docs/tutorial/application-packaging.md
index 45973e49eaa..c6e0ae3c410 100644
--- a/docs/tutorial/application-packaging.md
+++ b/docs/tutorial/application-packaging.md
@@ -132,6 +132,7 @@ work. This adds a little overhead for those APIs.
APIs that requires extra unpacking are:
* `child_process.execFile`
+* `child_process.execFileSync`
* `fs.open`
* `fs.openSync`
* `process.dlopen` - Used by `require` on native modules
@@ -143,6 +144,17 @@ archives is generated by guessing, because those files do not exist on the
filesystem. So you should not trust the `Stats` object except for getting file
size and checking file type.
+### Executing Binaries Inside `asar` Archive
+
+There are Node APIs that can execute binaries like `child_process.exec`,
+`child_process.spawn` and `child_process.execFile`, but only `execFile` is
+supported to execute binaries inside `asar` archive.
+
+This is because `exec` and `spawn` accept `command` instead of `file` as input,
+and `command`s are executed under shell. There is no reliable way to determine
+whether a command uses a file in asar archive, and even if we do, we can not be
+sure whether we can replace the path in command without side effects.
+
## Adding Unpacked Files in `asar` Archive
As stated above, some Node APIs will unpack the file to filesystem when
diff --git a/spec/asar-spec.coffee b/spec/asar-spec.coffee
index ad480a58252..af39fa3ec5e 100644
--- a/spec/asar-spec.coffee
+++ b/spec/asar-spec.coffee
@@ -392,6 +392,22 @@ describe 'asar package', ->
done()
child.send file
+ describe 'child_process.execFile', ->
+ return unless process.platform is 'darwin'
+
+ {execFile, execFileSync} = require 'child_process'
+ echo = path.join fixtures, 'asar', 'echo.asar', 'echo'
+
+ it 'executes binaries', (done) ->
+ child = execFile echo, ['test'], (error, stdout) ->
+ assert.equal error, null
+ assert.equal stdout, 'test\n'
+ done()
+
+ it 'execFileSync executes binaries', ->
+ output = execFileSync echo, ['test']
+ assert.equal String(output), 'test\n'
+
describe 'internalModuleReadFile', ->
internalModuleReadFile = process.binding('fs').internalModuleReadFile
diff --git a/spec/fixtures/asar/echo.asar b/spec/fixtures/asar/echo.asar
new file mode 100644
index 00000000000..4d72f7a92a7
Binary files /dev/null and b/spec/fixtures/asar/echo.asar differ