You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cordova.apache.org by ag...@apache.org on 2013/12/17 20:57:56 UTC

git commit: CB-5667 Skip over non-executable hooks in non-windows environments.

Updated Branches:
  refs/heads/master 7b57f1214 -> 4a5dc4040


CB-5667 Skip over non-executable hooks in non-windows environments.


Project: http://git-wip-us.apache.org/repos/asf/cordova-cli/repo
Commit: http://git-wip-us.apache.org/repos/asf/cordova-cli/commit/4a5dc404
Tree: http://git-wip-us.apache.org/repos/asf/cordova-cli/tree/4a5dc404
Diff: http://git-wip-us.apache.org/repos/asf/cordova-cli/diff/4a5dc404

Branch: refs/heads/master
Commit: 4a5dc404075b63d377d9f6014029fdf7093e90f5
Parents: 7b57f12
Author: Andrew Grieve <ag...@chromium.org>
Authored: Tue Dec 17 14:57:15 2013 -0500
Committer: Andrew Grieve <ag...@chromium.org>
Committed: Tue Dec 17 14:57:15 2013 -0500

----------------------------------------------------------------------
 src/hooker.js | 86 ++++++++++++++++++++++++++++--------------------------
 1 file changed, 45 insertions(+), 41 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/4a5dc404/src/hooker.js
----------------------------------------------------------------------
diff --git a/src/hooker.js b/src/hooker.js
index 8ac51a0..4d9ac1e 100644
--- a/src/hooker.js
+++ b/src/hooker.js
@@ -70,9 +70,36 @@ module.exports.prototype = {
     }
 };
 
+function extractSheBangInterpreter(fullpath) {
+    var hookFd = fs.openSync(fullpath, "r");
+    try {
+        // this is a modern cluster size. no need to read less
+        var fileData = new Buffer (4096);
+        var octetsRead = fs.readSync(hookFd, fileData, 0, 4096, 0);
+        var fileChunk = fileData.toString();
+    } finally {
+        fs.closeSync(hookFd);
+    }
+
+    var hookCmd, shMatch;
+    // Filter out /usr/bin/env so that "/usr/bin/env node" works like "node".
+    var shebangMatch = fileChunk.match(/^#!(?:\/usr\/bin\/env )?([^\r\n]+)/m);
+    if (octetsRead == 4096 && !fileChunk.match(/[\r\n]/))
+        events.emit('warn', 'shebang is too long for "' + fullpath + '"');
+    if (shebangMatch)
+        hookCmd = shebangMatch[1];
+    // Likewise, make /usr/bin/bash work like "bash".
+    if (hookCmd)
+        shMatch = hookCmd.match(/bin\/((?:ba)?sh)$/)
+    if (shMatch)
+        hookCmd = shMatch[1]
+    return hookCmd;
+}
+
 // Returns a promise.
 function execute_scripts_serially(scripts, root, dir, opts) {
     opts = opts || {};
+    var isWindows = os.platform().slice(0, 3) === 'win';
     if (scripts.length) {
         var s = scripts.shift();
         var fullpath = path.join(dir, s);
@@ -80,43 +107,14 @@ function execute_scripts_serially(scripts, root, dir, opts) {
             events.emit('verbose', 'skipped directory "' + fullpath + '" within hook directory');
             return execute_scripts_serially(scripts, root, dir, opts); // skip directories if they're in there.
         } else {
-            var command = fullpath + ' "' + root + '"';
-
-            var hookFd = fs.openSync(fullpath, "r");
-            // this is a modern cluster size. no need to read less
-            var fileData = new Buffer (4096);
-            var octetsRead = fs.readSync(hookFd, fileData, 0, 4096, 0);
-            var fileChunk = fileData.toString();
-
-            var hookCmd, shMatch;
-            var shebangMatch = fileChunk.match(/^#!(\/usr\/bin\/env )?([^\r\n]+)/m);
-            if (octetsRead == 4096 && !fileChunk.match(/[\r\n]/))
-                events.emit('warn', 'shebang is too long for "' + fullpath + '"');
-            if (shebangMatch)
-                hookCmd = shebangMatch[2];
-            if (hookCmd)
-                shMatch = hookCmd.match(/bin\/((ba)?sh)$/)
-            if (shMatch)
-                hookCmd = shMatch[1]
-
-            // according to the http://www.microsoft.com/resources/documentation/windows/xp/all/proddocs/en-us/wsh_runfromwindowsbasedhost.mspx?mfr=true
-            // win32 cscript natively supports .wsf, .vbs, .js extensions
-            // also, cmd.exe supports .bat files
-            // .ps1 powershell http://technet.microsoft.com/en-us/library/ee176949.aspx
-            var sExt = path.extname(s);
-
-            if (sExt.match(/^.(bat|wsf|vbs|js|ps1)$/)) {
-                if (os.platform() != 'win32' && !hookCmd) {
-                    events.emit('verbose', 'hook file "' + fullpath + '" skipped');
-                    // found windows script, without shebang this script definitely
-                    // will not run on unix
-                    return execute_scripts_serially(scripts, root, dir, opts);
-                }
-            }
-
-            if (os.platform() == 'win32' && hookCmd) {
+            var command = '"' + fullpath + '" "' + root + '"';
+            if (os.platform().slice(0, 3) == 'win') {
+                // TODO: Make shebang sniffing a setting (not everyone will want this).
+                var interpreter = extractSheBangInterpreter(fullpath);
                 // we have shebang, so try to run this script using correct interpreter
-                command = hookCmd + ' ' + command;
+                if (interpreter) {
+                    command = '"' + interpreter + '" ' + command;
+                }
             }
 
             var execOpts = {cwd: root};
@@ -127,14 +125,20 @@ function execute_scripts_serially(scripts, root, dir, opts) {
             execOpts.env.CORDOVA_HOOK = fullpath;
             execOpts.env.CORDOVA_CMDLINE = process.argv.join(' ');
 
-            events.emit('verbose', 'Executing hook "' + command + '" (output to follow)...');
+            events.emit('verbose', 'Executing hook "' + command + '"');
             var d = Q.defer();
             child_process.exec(command, execOpts, function(err, stdout, stderr) {
-                events.emit('verbose', stdout, stderr);
-                if (err) {
-                    d.reject(new Error('Script "' + fullpath + '" exited with non-zero status code. Aborting. Output: ' + stdout + stderr));
-                } else {
+                // Don't treat non-executable files as errors. They could be READMEs, or Windows-only scripts.
+                if (!isWindows && err && err.code === 126) {
+                    events.emit('verbose', 'skipped non-executable file: "' + fullpath);
                     d.resolve(execute_scripts_serially(scripts, root, dir, opts));
+                } else {
+                    events.emit('verbose', stdout, stderr);
+                    if (err) {
+                        d.reject(new Error('Script "' + fullpath + '" exited with status code ' + err.code + '. Aborting. Output: \n' + stdout + '\n' + stderr));
+                    } else {
+                        d.resolve(execute_scripts_serially(scripts, root, dir, opts));
+                    }
                 }
             });
             return d.promise;