From 7f8bf93d37a5d8d83e1ec1dc1d2bf44eb2c3023c Mon Sep 17 00:00:00 2001 From: "Glenn R. Martin" Date: Sun, 16 Apr 2017 22:03:21 -0400 Subject: [PATCH 1/8] Formatting and Cleanup to ES6. Including EditorConfig. --- .editorconfig | 12 ++ examples/browser-sync-02/gulpfile.js | 19 +-- examples/browser-sync/gulpfile.js | 13 +- .../gulpfile.js | 47 +++---- examples/simple/gulpfile.js | 15 ++- formatting.idea.xml | 117 ++++++++++++++++++ 6 files changed, 182 insertions(+), 41 deletions(-) create mode 100644 .editorconfig create mode 100644 formatting.idea.xml diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..bbf3cb4 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,12 @@ +root = true + +[*] +indent_style = space +indent_size = 2 +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true +end_of_line = lf + +[*.md] +trim_trailing_whitespace = false diff --git a/examples/browser-sync-02/gulpfile.js b/examples/browser-sync-02/gulpfile.js index 6381ca5..d5f4c98 100644 --- a/examples/browser-sync-02/gulpfile.js +++ b/examples/browser-sync-02/gulpfile.js @@ -1,10 +1,13 @@ -var gulp = require('gulp'), - connect = require('../../index.js'), - browserSync = require('browser-sync'); +/* jshint esversion: 6, node: true */ +'use strict'; + +const gulp = require('gulp'), + connect = require('../../index.js'), + browserSync = require('browser-sync'); //task that fires up php server at port 8001 -gulp.task('connect', function(callback) { +gulp.task('connect', function (callback) { connect.server({ port: 8001 }, callback); @@ -12,10 +15,10 @@ gulp.task('connect', function(callback) { //task that fires up browserSync proxy after connect server has started -gulp.task('browser-sync',['connect'], function() { - browserSync({ - proxy: '127.0.0.1:8001', - port: 8910 +gulp.task('browser-sync', ['connect'], function () { + browserSync({ + proxy: '127.0.0.1:8001', + port: 8910 }); }); diff --git a/examples/browser-sync/gulpfile.js b/examples/browser-sync/gulpfile.js index 8597f32..bf7f4d7 100644 --- a/examples/browser-sync/gulpfile.js +++ b/examples/browser-sync/gulpfile.js @@ -1,9 +1,12 @@ -var gulp = require('gulp'), - connect = require('../../index.js'), - browserSync = require('browser-sync'); +/* jshint esversion: 6, node: true */ +'use strict'; -gulp.task('connect-sync', function() { - connect.server({}, function (){ +const gulp = require('gulp'), + connect = require('../../index.js'), + browserSync = require('browser-sync'); + +gulp.task('connect-sync', function () { + connect.server({}, function () { browserSync({ proxy: 'localhost:8000' }); diff --git a/examples/simple-with-argument-manipulation/gulpfile.js b/examples/simple-with-argument-manipulation/gulpfile.js index 66522c2..d605c8c 100644 --- a/examples/simple-with-argument-manipulation/gulpfile.js +++ b/examples/simple-with-argument-manipulation/gulpfile.js @@ -1,31 +1,34 @@ -var gulp = require('gulp'), - connect = require('../../index.js'); +/* jshint esversion: 6, node: true */ +'use strict'; + +const gulp = require('gulp'), + connect = require('../../index.js'); gulp.task('connect', function _gulp_connect_task() { - connect.server({ - configCallback: function _configCallback(type, collection) { - // If you wish to leave one of the argument types alone, simply return the passed in collection. - if (type === connect.OPTIONS_SPAWN_OBJ) { // As the constant suggests, collection is an Object. + connect.server({ + configCallback: function _configCallback(type, collection) { + // If you wish to leave one of the argument types alone, simply return the passed in collection. + if (type === connect.OPTIONS_SPAWN_OBJ) { // As the constant suggests, collection is an Object. - // Lets add a custom env var. Good for injecting AWS_RDS config variables. - collection.env = Object.assign({ - MY_CUSTOM_ENV_VAR: "env_var_value" - }, process.env); + // Lets add a custom env var. Good for injecting AWS_RDS config variables. + collection.env = Object.assign({ + MY_CUSTOM_ENV_VAR: "env_var_value" + }, process.env); - return collection; - } else if (type === connect.OPTIONS_PHP_CLI_ARR) { // As the constant suggests, collection is an Array. - var newArgs = [ - '-e', // Generate extended information for debugger/profiler. - '-d', 'memory_limit=2G' // Define INI entry, Up memory limit to 2G. - ]; + return collection; + } else if (type === connect.OPTIONS_PHP_CLI_ARR) { // As the constant suggests, collection is an Array. + let newArgs = [ + '-e', // Generate extended information for debugger/profiler. + '-d', 'memory_limit=2G' // Define INI entry, Up memory limit to 2G. + ]; - // Ensure our argument switches appear before the rest. - return newArgs.concat(collection); - } + // Ensure our argument switches appear before the rest. + return newArgs.concat(collection); } - }, function _connected_callback(){ - console.log("PHP Development Server Connected."); - }); + } + }, function _connected_callback() { + console.log("PHP Development Server Connected."); + }); }); gulp.task('default', ['connect']); diff --git a/examples/simple/gulpfile.js b/examples/simple/gulpfile.js index 6539265..0123198 100644 --- a/examples/simple/gulpfile.js +++ b/examples/simple/gulpfile.js @@ -1,10 +1,13 @@ -var gulp = require('gulp'), - connect = require('../../index.js'); +/* jshint esversion: 6, node: true */ +'use strict'; -gulp.task('connect', function() { - connect.server({}, function(){ - // connected - }); +const gulp = require('gulp'), + connect = require('../../index.js'); + +gulp.task('connect', function () { + connect.server({}, function () { + // connected + }); }); gulp.task('default', ['connect']); diff --git a/formatting.idea.xml b/formatting.idea.xml new file mode 100644 index 0000000..ea0d4c0 --- /dev/null +++ b/formatting.idea.xml @@ -0,0 +1,117 @@ + + + + + From 570d45e525a6e10fac30733c628a0d1e05149a2c Mon Sep 17 00:00:00 2001 From: "Glenn R. Martin" Date: Sun, 16 Apr 2017 22:03:57 -0400 Subject: [PATCH 2/8] Initial Code-Rework for 1.0.0. --- index.js | 319 +++++++++++++++++++++++++++------------------------ package.json | 4 +- test/test.js | 141 ++++++++++++++++------- 3 files changed, 270 insertions(+), 194 deletions(-) diff --git a/index.js b/index.js index d32af3c..0270b27 100644 --- a/index.js +++ b/index.js @@ -1,150 +1,173 @@ +/* jshint esversion: 6, node: true */ 'use strict'; -var extend = require('util')._extend; -var spawn = require('child_process').spawn; -var exec = require('child_process').exec; -var http = require('http'); -var open = require('opn'); -var binVersionCheck = require('bin-version-check'); -var fs = require('fs'); - -module.exports = (function (OPTIONS_SPAWN_OBJ, OPTIONS_PHP_CLI_ARR) { - var checkServerTries = 0; - var workingPort = 8000; - - function checkServer(hostname, port, cb) { - setTimeout(function () { - http.request({ - method: 'HEAD', - hostname: hostname, - port: port - }, function (res) { - var statusCodeType = Number(res.statusCode.toString()[0]); - - if ([2, 3, 4].indexOf(statusCodeType) !== -1) { - return cb(); - } else if (statusCodeType === 5) { - console.log( - 'Server docroot returned 500-level response. Please check ' + - 'your configuration for possible errors.' - ); - return cb(); - } - - checkServer(hostname, port, cb); - }).on('error', function (err) { - // back off after 1s - if (++checkServerTries > 20) { - console.log('PHP server not started. Retrying...'); - return cb(); - } - checkServer(hostname, port, cb); - }).end(); - }, 50); - } - - var closeServer = function (cb) { - var child = exec('lsof -i :' + workingPort, - function (error, stdout, stderr) { - //console.log('stdout: ' + stdout); - //console.log('stderr: ' + stderr); - if (error !== null) { - console.log('exec error: ' + error); - } - - // get pid then kill it - var pid = stdout.match(/php\s+?([0-9]+)/)[1]; - if (pid) { - exec('kill ' + pid, function (error, stdout, stderr) { - //console.log('stdout: ' + stdout); - //console.log('stderr: ' + stderr); - cb(); - }); - } else { - cb({error: "couldn't find process id and kill it"}); - } - }); - }; - - var server = function (options, cb){ - if (!cb) { - cb = function(){}; - } - - options = extend({ - port: 8000, - hostname: '127.0.0.1', - base: '.', - open: false, - bin: 'php', - root: '/', - stdio: 'inherit', - configCallback: null, - debug: false - }, options); - - workingPort = options.port; - var host = options.hostname + ':' + options.port; - var args = ['-S', host, '-t', options.base]; - - if (options.ini) { - args.push('-c', options.ini); - } - - if (options.router) { - args.push(require('path').resolve(options.router)); - } - - if (options.debug) { - spawn = function (outerSpawn) { return function debugSpawnWrapper(file, args, options) { - console.log('Invoking Spawn with:'); - console.log(file); - console.log(args); - console.log(options); - - return outerSpawn(file, args, options); - }}(spawn); - } - - if (options.configCallback === null || options.configCallback === undefined) { - options.configCallback = function noOpConfigCallback(type, collection) { return collection; } - } - - spawn = function (outerSpawn) { return function configCallbackSpawnWrapper(file, spawnArgs, spawnOptions) { - return outerSpawn(file, options.configCallback(OPTIONS_PHP_CLI_ARR, spawnArgs), options.configCallback(OPTIONS_SPAWN_OBJ, spawnOptions)); - }}(spawn); - - binVersionCheck(options.bin, '>=5.4', function (err) { - if (err) { - cb(); - return; - } - var checkPath = function(){ - var exists = fs.existsSync(options.base); - if (exists === true) { - spawn(options.bin, args, { - cwd: '.', - stdio: options.stdio - }); - } - else{ - setTimeout(checkPath, 100); - } - }; - checkPath(); - // check when the server is ready. tried doing it by listening - // to the child process `data` event, but it's not triggered... - checkServer(options.hostname, options.port, function () { - if (options.open) { - open('http://' + host + options.root); - } - cb(); - }.bind(this)); - }.bind(this)); - }; - return { - server: server, - closeServer: closeServer, - OPTIONS_SPAWN_OBJ: OPTIONS_SPAWN_OBJ, - OPTIONS_PHP_CLI_ARR: OPTIONS_PHP_CLI_ARR - } + +(function _gulp_php_connect_module_scoping(OPTIONS_SPAWN_OBJ, OPTIONS_PHP_CLI_ARR) { + const childProcess = require('child_process'); + let spawn = childProcess.spawn; + const exec = childProcess.exec; + const http = require('http'); + const open = require('opn'); + const binVersionCheck = require('bin-version-check'); + const fs = require('fs'); + + class PhpDevelopmentServerConnection { + constructor() { + this.checkServerTries = 0; + this.workingPort = 8000; + return this; // `new` bug + } + + closeServer(cb) { + if (this.childProcess) { + cb(this.childProcess.kill('SIGKILL')); + return; + } + cb(); + } + + + checkServer(hostname, port, cb) { + const self = this; + setTimeout(function () { + http.request({ + method: 'HEAD', + hostname: hostname, + port: port + }, function (res) { + const statusCodeType = Number(res.statusCode.toString()[0]); + + if ([2, 3, 4].indexOf(statusCodeType) !== -1) { + return cb(); + } else if (statusCodeType === 5) { + console.log( + 'Server docroot returned 500-level response. Please check ' + + 'your configuration for possible errors.' + ); + return cb(); + } + + //self.checkServer(hostname, port, cb); + }).on('error', function (err) { + // back off after 1s + if (++this.checkServerTries > 20) { + console.log('PHP server not started. Retrying...'); + return cb(); + } + //self.checkServer(hostname, port, cb); + }).end(); + }, 50); + } + + server(options, cb) { + if (!cb) { + cb = function () { + }; + } + + var self = this; + + options = Object.assign({ + port: 8000, + hostname: '127.0.0.1', + base: '.', + open: false, + bin: 'php', + root: '/', + stdio: 'inherit', + configCallback: null, + debug: false + }, options); + + this.workingPort = options.port; + var host = options.hostname + ':' + options.port; + var args = ['-S', host, '-t', options.base]; + + if (options.ini) { + args.push('-c', options.ini); + } + + if (options.router) { + args.push(require('path').resolve(options.router)); + } + + if (options.debug) { + spawn = function (outerSpawn) { + return function debugSpawnWrapper(file, args, options) { + console.log('Invoking Spawn with:'); + console.log(file); + console.log(args); + console.log(options); + + return outerSpawn(file, args, options); + } + }(spawn); + } + + if (options.configCallback === null || options.configCallback === undefined) { + options.configCallback = function noOpConfigCallback(type, collection) { + return collection; + } + } + + spawn = function (outerSpawn) { + return function configCallbackSpawnWrapper(file, spawnArgs, spawnOptions) { + return outerSpawn(file, options.configCallback(OPTIONS_PHP_CLI_ARR, spawnArgs), options.configCallback(OPTIONS_SPAWN_OBJ, spawnOptions)); + } + }(spawn); + + + binVersionCheck(options.bin, '>=5.4', function (err) { + if (err) { + cb(); + return; + } + var checkPath = function () { + var exists = fs.existsSync(options.base); + if (exists === true) { + self.childProcess = spawn(options.bin, args, { + cwd: '.', + stdio: options.stdio + }); + } + else { + setTimeout(checkPath, 100); + } + }; + checkPath(); + // check when the server is ready. tried doing it by listening + // to the child process `data` event, but it's not triggered... + self.checkServer(options.hostname, options.port, function () { + if (options.open) { + open('http://' + host + options.root); + } + cb(); + }.bind(this)); + }.bind(this)); + }; + } + + module.exports = (function _export_scoping() { + + let returnStructure = PhpDevelopmentServerConnection; + + const adopterBinder = (adopter, inst, method) => adopter[method] = inst[method].bind(inst); + + returnStructure.compat = (function _naught_version_compatibility() { + // This is segregated beacuse in the future around v1.5 we will make it emit a warning. + // In v2.0 we will gut it completely. + const inst = new PhpDevelopmentServerConnection; + inst.OPTIONS_SPAWN_OBJ = OPTIONS_SPAWN_OBJ; + inst.OPTIONS_PHP_CLI_ARR = OPTIONS_PHP_CLI_ARR; + return inst; + })(); + + // You cannot actually bind a function to a method directly... so... lets manually bind to get a function that calls the right instance. + adopterBinder(returnStructure, returnStructure.compat, 'server'); + adopterBinder(returnStructure, returnStructure.compat, 'closeServer'); + + returnStructure.OPTIONS_SPAWN_OBJ = OPTIONS_SPAWN_OBJ; + returnStructure.OPTIONS_PHP_CLI_ARR = OPTIONS_PHP_CLI_ARR; + + return returnStructure; + })(); })('spawn', 'php_args'); diff --git a/package.json b/package.json index fadd3e0..10fdabb 100644 --- a/package.json +++ b/package.json @@ -1,10 +1,10 @@ { "name": "gulp-connect-php", - "version": "0.0.9", + "version": "1.0.0", "description": "Starts a php server", "main": "index.js", "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" + "test": "mocha ./test" }, "repository": { "type": "git", diff --git a/test/test.js b/test/test.js index 56bc94d..dae6953 100644 --- a/test/test.js +++ b/test/test.js @@ -1,51 +1,104 @@ +/* jshint esversion: 6, node: true */ +'use strict'; + require("mocha"); -var request = require("supertest"), - assert = require("assert"), - connect = require("../index.js"); - -describe('gulp-connect-php', function () { - it('Should start a basic php server', function (done) { - connect.server({}, function() { - request('http://127.0.0.1:8000') - .get('/test/fixtures/hello.php') - .expect(/hello world/) - .expect(200) - .end(function (err, res) { - connect.closeServer(function (){ - done(); - }); - if (err) return done(err); + +const request = require("supertest"), + //assert = require("assert"), + connect = require("../index.js"); + +/* + - Anonymous Functions in the Test Suite should have internal names. This makes failure traces easier to read. + - For Simplicities sake, please avoid 'Arrow'-Functions (Lambda-like Constructs) and Opt for Anonymous Functions... + Like the first point, this makes failure traces simpler to read. + - Suites should be grouped by IIFE. + */ + +const noop = function _noop() { }; +const noopReturn = function _noopReturn(x) { return x; }; + +(function _suite1() { + describe('gulp-connect-php', function _test_basic() { + it('Should start a basic php server', function _basic_serverCallback(done) { + connect.server({}, function () { + request('http://127.0.0.1:8000') + .get('/test/fixtures/hello.php') + .expect(/hello world/) + .expect(200) + .end(function _basic_endEvent(err, res) { + if (err) return done(err); + connect.closeServer(function _basic_closeServer() { + done(); + }); + }); }); }); - }); - - it('Should start a basic php server, with a set environment variable and updated memory limits set via the configCallback option', function (done) { - connect.server({ - configCallback: function _configCallback(type, collection) { - if (type === connect.OPTIONS_SPAWN_OBJ) { - collection.env = Object.assign({ - TEST_ENV_VAR: "SET_OK" - }, process.env); - - return collection; - } else if (type === connect.OPTIONS_PHP_CLI_ARR) { - var newArgs = [ - '-d', 'memory_limit=2.1G' - ]; - return newArgs.concat(collection); + + it('Should start a set of basic php servers', function _test_multiples(done) { + let doneCounter = 0; + + const tickDone = function _tickDone(x) { + ++doneCounter === 2 ? done(x) : noopReturn(x) + }; + + const conn1 = new connect(); + const conn2 = new connect(); + + conn1.server({port: 8001}, function _multiples1_serverCallback() { + request('http://127.0.0.1:8001') + .get('/test/fixtures/hello.php') + .expect(/hello world/) + .expect(200) + .end(function _multiples1_endEvent(err, res) { + if (err) return done(err); + conn1.closeServer(function _multiples1_closeServer() { + tickDone(); + }); + }); + }); + + conn2.server({port: 8002}, function _multiples2_serverCallback() { + request('http://127.0.0.1:8002') + .get('/test/fixtures/hello.php') + .expect(/hello world/) + .expect(200) + .end(function _multiples2_endEvent(err, res) { + if (err) return done(err); + conn2.closeServer(function _multiples2_closeServer() { + tickDone(); + }); + }); + }); + }); + + it('Should start a basic php server, with a set environment variable and updated memory limits set via the configCallback option', function _test_configCallback(done) { + connect.server({ + configCallback: function _configCallback(type, collection) { + if (type === connect.OPTIONS_SPAWN_OBJ) { + collection.env = Object.assign({ + TEST_ENV_VAR: "SET_OK" + }, process.env); + + return collection; + } else if (type === connect.OPTIONS_PHP_CLI_ARR) { + let newArgs = [ + '-d', 'memory_limit=2.1G' + ]; + return newArgs.concat(collection); + } } - } - }, function() { - request('http://127.0.0.1:8000') - .get('/test/fixtures/config-cb-checker.php') - .expect(/ENVVAR=SET_OK,MEM_LIMIT=2\.1G;/) - .expect(200) - .end(function (err, res) { - connect.closeServer(function (){ - done(); + }, function _configCallback_serverCallback() { + request('http://127.0.0.1:8000') + .get('/test/fixtures/config-cb-checker.php') + .expect(/ENVVAR=SET_OK,MEM_LIMIT=2\.1G;/) + .expect(200) + .end(function _configCallback_endEvent(err, res) { + if (err) return done(err); + connect.closeServer(function _configCallback_closeServer() { + done(); + }); }); - if (err) return done(err); - }); + }); }); }); -}); +})(); \ No newline at end of file From 3adb0eee33f9175970adff8177c84dea25eb6e64 Mon Sep 17 00:00:00 2001 From: "Glenn R. Martin" Date: Mon, 17 Apr 2017 08:52:51 -0400 Subject: [PATCH 3/8] Adding Constructor Options that can be overridden during the `server(...)` call. Adding examples to the Documentation of how to use this library in the form of a class instance. --- README.md | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++++--- index.js | 41 +++++++++++++++++++----------------- 2 files changed, 81 insertions(+), 22 deletions(-) diff --git a/README.md b/README.md index 7c3390a..11c0975 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ > Start a [PHP-server](http://php.net/manual/en/features.commandline.webserver.php) -This is pretty much a gulp version of [@sindresorhus's](https://github.com/sindresorhus) [grunt-php] (https://github.com/sindresorhus/grunt-php) and acts as a _basic version_ drop-in replacement for [gulp-connect](https://www.npmjs.com/package/gulp-connect), though please note not all features from gulp-connect are supported with gulp-connect-php. I am open to supporting other features and pull requests that implement them. +This is pretty much a gulp version of [@sindresorhus's](https://github.com/sindresorhus) [grunt-php](https://github.com/sindresorhus/grunt-php) and acts as a _basic version_ drop-in replacement for [gulp-connect](https://www.npmjs.com/package/gulp-connect), though please note not all features from gulp-connect are supported with gulp-connect-php. I am open to supporting other features and pull requests that implement them. Uses the built-in server in PHP 5.4.0+. @@ -14,6 +14,7 @@ $ npm install --save-dev gulp-connect-php ## Usage +### As a Singleton ```js var gulp = require('gulp'), connect = require('gulp-connect-php'); @@ -25,9 +26,26 @@ gulp.task('connect', function() { gulp.task('default', ['connect']); ``` +### As an Instance +```js +var gulp = require('gulp'), + connect = require('gulp-connect-php'); + +let server = new connect(); + +gulp.task('connect', function() { + server.server(); +}); +gulp.task('disconnect', function() { + server.closeServer(); +}); + +gulp.task('default', ['connect', 'disconnect']); +``` + ## Examples -#### Use it with Browser Sync +### Use it with Browser Sync ```js var gulp = require('gulp'), @@ -47,6 +65,43 @@ gulp.task('connect-sync', function() { }); ``` +### Advanced Option Manipulation + +```js +gulp.task('connect', function() { + connect.server({ + configCallback: function _configCallback(type, collection) { + // If you wish to leave one of the argument types alone, simply return the passed in collection. + if (type === connect.OPTIONS_SPAWN_OBJ) { // As the constant suggests, collection is an Object. + + // Lets add a custom env var. Good for injecting AWS_RDS config variables. + collection.env = Object.assign({ + MY_CUSTOM_ENV_VAR: "env_var_value" + }, process.env); + + return collection; + } else if (type === connect.OPTIONS_PHP_CLI_ARR) { // As the constant suggests, collection is an Array. + let newArgs = [ + '-e', // Generate extended information for debugger/profiler. + '-d', 'memory_limit=2G' // Define INI entry, Up memory limit to 2G. + ]; + + // Ensure our argument switches appear before the rest. + return newArgs.concat(collection); + } + } + }, function _connected_callback() { + console.log("PHP Development Server Connected."); + }); +}); + +gulp.task('disconnect', function() { + connect.closeServer(); +}); + +gulp.task('default', ['connect', 'disconnect']); +``` + ## Options ### port @@ -123,7 +178,8 @@ Node's [stdio parameter](https://nodejs.org/api/child_process.html#child_process Type: `function (type, collection) : collection` -Prototype: +Prototype: + - `type` - String, either `OPTIONS_SPAWN_OBJ` or `OPTIONS_PHP_CLI_ARR`. - `collection` - Array or Object, the initial version of the collection specified by `type`. diff --git a/index.js b/index.js index 0270b27..f341525 100644 --- a/index.js +++ b/index.js @@ -11,9 +11,22 @@ const fs = require('fs'); class PhpDevelopmentServerConnection { - constructor() { + constructor(opts) { this.checkServerTries = 0; + this.workingPort = 8000; + + this.defaults = Object.assign({ + port: 8000, + hostname: '127.0.0.1', + base: '.', + open: false, + bin: 'php', + root: '/', + stdio: 'inherit', + configCallback: null, + debug: false + }, opts || {}); return this; // `new` bug } @@ -25,6 +38,7 @@ cb(); } + get port() { return this.workingPort; } checkServer(hostname, port, cb) { const self = this; @@ -60,27 +74,16 @@ server(options, cb) { if (!cb) { - cb = function () { - }; + cb = function () { }; } - var self = this; + const self = this; - options = Object.assign({ - port: 8000, - hostname: '127.0.0.1', - base: '.', - open: false, - bin: 'php', - root: '/', - stdio: 'inherit', - configCallback: null, - debug: false - }, options); + options = Object.assign({}, this.defaults, options); this.workingPort = options.port; - var host = options.hostname + ':' + options.port; - var args = ['-S', host, '-t', options.base]; + const host = options.hostname + ':' + options.port; + const args = ['-S', host, '-t', options.base]; if (options.ini) { args.push('-c', options.ini); @@ -121,8 +124,8 @@ cb(); return; } - var checkPath = function () { - var exists = fs.existsSync(options.base); + const checkPath = function () { + const exists = fs.existsSync(options.base); if (exists === true) { self.childProcess = spawn(options.bin, args, { cwd: '.', From 319cac9ac7d53bc48247652e4369d5e5435650a5 Mon Sep 17 00:00:00 2001 From: "Glenn R. Martin" Date: Mon, 17 Apr 2017 09:51:08 -0400 Subject: [PATCH 4/8] Adding Systemic Status... Allowing us to have a state machine and tighten up timers. Updating anonymous functions to have names for easier to follow debugging. --- index.js | 221 +++++++++++++++++++++++++++++++------------------------ 1 file changed, 126 insertions(+), 95 deletions(-) diff --git a/index.js b/index.js index f341525..1a50f86 100644 --- a/index.js +++ b/index.js @@ -10,144 +10,175 @@ const binVersionCheck = require('bin-version-check'); const fs = require('fs'); - class PhpDevelopmentServerConnection { - constructor(opts) { - this.checkServerTries = 0; - - this.workingPort = 8000; - - this.defaults = Object.assign({ - port: 8000, - hostname: '127.0.0.1', - base: '.', - open: false, - bin: 'php', - root: '/', - stdio: 'inherit', - configCallback: null, - debug: false - }, opts || {}); - return this; // `new` bug - } + //let counter = 0; - closeServer(cb) { - if (this.childProcess) { - cb(this.childProcess.kill('SIGKILL')); - return; - } - cb(); - } + function EnumSet() { + [...arguments].forEach((x) => { this[x] = Symbol(x) }); + } - get port() { return this.workingPort; } + const PhpDevelopmentServerConnection = ((function _PhpDevelopmentServerConnection_private_scope() { + const Status = new EnumSet('NEW', 'STARTING', 'STARTED', 'FINISHED'); - checkServer(hostname, port, cb) { + function checkServer(hostname, port, cb) { const self = this; - setTimeout(function () { + //console.log(`[${this.counter}] checkServer`); + + if (self.status !== Status.STARTING) return; + + setTimeout(function _checkServer_fire() { http.request({ method: 'HEAD', hostname: hostname, port: port - }, function (res) { + }, function _checkServer_httpCallback(res) { const statusCodeType = Number(res.statusCode.toString()[0]); if ([2, 3, 4].indexOf(statusCodeType) !== -1) { - return cb(); + return cb(true); } else if (statusCodeType === 5) { console.log( 'Server docroot returned 500-level response. Please check ' + 'your configuration for possible errors.' ); - return cb(); + return cb(true); } - //self.checkServer(hostname, port, cb); - }).on('error', function (err) { + checkServer.call(self, hostname, port, cb); + }).on('error', function _checkServer_httpError(err) { // back off after 1s - if (++this.checkServerTries > 20) { + if (++self.checkServerTries > 20) { console.log('PHP server not started. Retrying...'); - return cb(); + return cb(false); } - //self.checkServer(hostname, port, cb); + checkServer.call(self, hostname, port, cb); }).end(); - }, 50); + }, 15); } - server(options, cb) { - if (!cb) { - cb = function () { }; - } + class PhpDevelopmentServerConnection { + constructor(opts) { + //this.counter = ++counter; + //console.log(`[${this.counter}] constructor`); - const self = this; + this.status = Status.NEW; - options = Object.assign({}, this.defaults, options); + this.checkServerTries = 0; - this.workingPort = options.port; - const host = options.hostname + ':' + options.port; - const args = ['-S', host, '-t', options.base]; + this.workingPort = 8000; - if (options.ini) { - args.push('-c', options.ini); - } + this.defaults = Object.assign({ + port: 8000, + hostname: '127.0.0.1', + base: '.', + open: false, + bin: 'php', + root: '/', + stdio: 'inherit', + configCallback: null, + debug: false + }, opts || {}); - if (options.router) { - args.push(require('path').resolve(options.router)); + return this; // `new` bug } - if (options.debug) { - spawn = function (outerSpawn) { - return function debugSpawnWrapper(file, args, options) { - console.log('Invoking Spawn with:'); - console.log(file); - console.log(args); - console.log(options); - - return outerSpawn(file, args, options); - } - }(spawn); - } + closeServer(cb) { + //console.log(`[${this.counter}] closeServer`); + const self = this; + if (this.loading) { + setTimeout(() => self.closeServer(cb), 5); + return; + } - if (options.configCallback === null || options.configCallback === undefined) { - options.configCallback = function noOpConfigCallback(type, collection) { - return collection; + if (this.childProcess) { + cb(this.childProcess.kill('SIGKILL')); + this.status = Status.FINISHED; + return; } + + cb(); } - spawn = function (outerSpawn) { - return function configCallbackSpawnWrapper(file, spawnArgs, spawnOptions) { - return outerSpawn(file, options.configCallback(OPTIONS_PHP_CLI_ARR, spawnArgs), options.configCallback(OPTIONS_SPAWN_OBJ, spawnOptions)); + get port() { return this.workingPort; } + + server(options, cb) { + //console.log(`[${this.counter}] server`); + cb = cb || function _noop() { }; + + const self = this; + + options = Object.assign({}, this.defaults, options); + + this.workingPort = options.port; + const host = options.hostname + ':' + options.port; + const args = ['-S', host, '-t', options.base]; + + if (options.ini) { + args.push('-c', options.ini); } - }(spawn); + if (options.router) { + args.push(require('path').resolve(options.router)); + } - binVersionCheck(options.bin, '>=5.4', function (err) { - if (err) { - cb(); - return; + if (options.debug) { + spawn = function _debugSpawn(outerSpawn) { + return function debugSpawnWrapper(file, args, options) { + console.log('Invoking Spawn with:'); + console.log(file); + console.log(args); + console.log(options); + + return outerSpawn(file, args, options); + } + }(spawn); } - const checkPath = function () { - const exists = fs.existsSync(options.base); - if (exists === true) { - self.childProcess = spawn(options.bin, args, { - cwd: '.', - stdio: options.stdio - }); + + if (options.configCallback === null || options.configCallback === undefined) { + options.configCallback = function noOpConfigCallback(type, collection) { + return collection; } - else { - setTimeout(checkPath, 100); + } + + spawn = function _configCallbackSpawn(outerSpawn) { + return function configCallbackSpawnWrapper(file, spawnArgs, spawnOptions) { + return outerSpawn(file, options.configCallback(OPTIONS_PHP_CLI_ARR, spawnArgs), options.configCallback(OPTIONS_SPAWN_OBJ, spawnOptions)); } - }; - checkPath(); - // check when the server is ready. tried doing it by listening - // to the child process `data` event, but it's not triggered... - self.checkServer(options.hostname, options.port, function () { - if (options.open) { - open('http://' + host + options.root); + }(spawn); + + binVersionCheck(options.bin, '>=5.4', function _binVerCheck(err) { + if (err) { + cb(); + return; } - cb(); + const checkPath = function _checkPath() { + const exists = fs.existsSync(options.base); + if (exists === true) { + self.status = Status.STARTING; + self.childProcess = spawn(options.bin, args, { + cwd: '.', + stdio: options.stdio + }); + } + else { + setTimeout(checkPath, 100); + } + }; + checkPath(); + // check when the server is ready. tried doing it by listening + // to the child process `data` event, but it's not triggered... + checkServer.call(self, options.hostname, options.port, function _server_checkServer() { + self.status = Status.STARTED; + if (options.open) { + open('http://' + host + options.root); + } + cb(); + }.bind(this)); }.bind(this)); - }.bind(this)); - }; - } + }; + } + + return PhpDevelopmentServerConnection; + }))(); module.exports = (function _export_scoping() { From 2c8e34968caab5c1b49b5f3cde3fb8f8be2afaab Mon Sep 17 00:00:00 2001 From: "Glenn R. Martin" Date: Mon, 17 Apr 2017 14:22:25 -0400 Subject: [PATCH 5/8] Making closeServer method callback optional. Adding Test for @jake-a-wood in https://github.com/micahblu/gulp-connect-php/issues/33. --- index.js | 3 +- test/test.js | 152 ++++++++++++++++++++++++++++----------------------- 2 files changed, 85 insertions(+), 70 deletions(-) diff --git a/index.js b/index.js index 1a50f86..dfcdb5e 100644 --- a/index.js +++ b/index.js @@ -82,6 +82,7 @@ } closeServer(cb) { + cb = cb || function _closeServerCb_noop() { }; //console.log(`[${this.counter}] closeServer`); const self = this; if (this.loading) { @@ -102,7 +103,7 @@ server(options, cb) { //console.log(`[${this.counter}] server`); - cb = cb || function _noop() { }; + cb = cb || function _serverCB_noop() { }; const self = this; diff --git a/test/test.js b/test/test.js index dae6953..471f4a1 100644 --- a/test/test.js +++ b/test/test.js @@ -17,88 +17,102 @@ const request = require("supertest"), const noop = function _noop() { }; const noopReturn = function _noopReturn(x) { return x; }; -(function _suite1() { - describe('gulp-connect-php', function _test_basic() { - it('Should start a basic php server', function _basic_serverCallback(done) { - connect.server({}, function () { - request('http://127.0.0.1:8000') - .get('/test/fixtures/hello.php') - .expect(/hello world/) - .expect(200) - .end(function _basic_endEvent(err, res) { - if (err) return done(err); - connect.closeServer(function _basic_closeServer() { - done(); - }); +describe('gulp-connect-php', function _base_suite1() { + + it('Should start a basic php server', function _test_basic(done) { + connect.server({}, function _basic_serverCallback() { + request('http://127.0.0.1:8000') + .get('/test/fixtures/hello.php') + .expect(/hello world/) + .expect(200) + .end(function _basic_endEvent(err, res) { + if (err) return done(err); + connect.closeServer(function _basic_closeServer() { + done(); }); - }); + }); }); + }); - it('Should start a set of basic php servers', function _test_multiples(done) { - let doneCounter = 0; + it('Should start a set of basic php servers', function _test_multiples(done) { + let doneCounter = 0; - const tickDone = function _tickDone(x) { - ++doneCounter === 2 ? done(x) : noopReturn(x) - }; + const tickDone = function _tickDone(x) { + ++doneCounter === 2 ? done(x) : noopReturn(x) + }; - const conn1 = new connect(); - const conn2 = new connect(); + const conn1 = new connect(); + const conn2 = new connect(); - conn1.server({port: 8001}, function _multiples1_serverCallback() { - request('http://127.0.0.1:8001') - .get('/test/fixtures/hello.php') - .expect(/hello world/) - .expect(200) - .end(function _multiples1_endEvent(err, res) { - if (err) return done(err); - conn1.closeServer(function _multiples1_closeServer() { - tickDone(); - }); + conn1.server({port: 8001}, function _multiples1_serverCallback() { + request('http://127.0.0.1:8001') + .get('/test/fixtures/hello.php') + .expect(/hello world/) + .expect(200) + .end(function _multiples1_endEvent(err, res) { + if (err) return done(err); + conn1.closeServer(function _multiples1_closeServer() { + tickDone(); }); - }); + }); + }); - conn2.server({port: 8002}, function _multiples2_serverCallback() { - request('http://127.0.0.1:8002') - .get('/test/fixtures/hello.php') - .expect(/hello world/) - .expect(200) - .end(function _multiples2_endEvent(err, res) { - if (err) return done(err); - conn2.closeServer(function _multiples2_closeServer() { - tickDone(); - }); + conn2.server({port: 8002}, function _multiples2_serverCallback() { + request('http://127.0.0.1:8002') + .get('/test/fixtures/hello.php') + .expect(/hello world/) + .expect(200) + .end(function _multiples2_endEvent(err, res) { + if (err) return done(err); + conn2.closeServer(function _multiples2_closeServer() { + tickDone(); }); - }); + }); }); + }); - it('Should start a basic php server, with a set environment variable and updated memory limits set via the configCallback option', function _test_configCallback(done) { - connect.server({ - configCallback: function _configCallback(type, collection) { - if (type === connect.OPTIONS_SPAWN_OBJ) { - collection.env = Object.assign({ - TEST_ENV_VAR: "SET_OK" - }, process.env); + it('Should start a basic php server, with a set environment variable and updated memory limits set via the configCallback option', function _test_configCallback(done) { + connect.server({ + configCallback: function _configCallback(type, collection) { + if (type === connect.OPTIONS_SPAWN_OBJ) { + collection.env = Object.assign({ + TEST_ENV_VAR: "SET_OK" + }, process.env); - return collection; - } else if (type === connect.OPTIONS_PHP_CLI_ARR) { - let newArgs = [ - '-d', 'memory_limit=2.1G' - ]; - return newArgs.concat(collection); - } + return collection; + } else if (type === connect.OPTIONS_PHP_CLI_ARR) { + let newArgs = [ + '-d', 'memory_limit=2.1G' + ]; + return newArgs.concat(collection); } - }, function _configCallback_serverCallback() { - request('http://127.0.0.1:8000') - .get('/test/fixtures/config-cb-checker.php') - .expect(/ENVVAR=SET_OK,MEM_LIMIT=2\.1G;/) - .expect(200) - .end(function _configCallback_endEvent(err, res) { - if (err) return done(err); - connect.closeServer(function _configCallback_closeServer() { - done(); - }); + } + }, function _configCallback_serverCallback() { + request('http://127.0.0.1:8000') + .get('/test/fixtures/config-cb-checker.php') + .expect(/ENVVAR=SET_OK,MEM_LIMIT=2\.1G;/) + .expect(200) + .end(function _configCallback_endEvent(err, res) { + if (err) return done(err); + connect.closeServer(function _configCallback_closeServer() { + done(); }); - }); + }); }); }); -})(); \ No newline at end of file + + it('Should start a basic php server without a close callback', function _test_basicNoCloseCB(done) { + connect.server({}, function _basicNoCloseCB_serverCallback() { + request('http://127.0.0.1:8000') + .get('/test/fixtures/hello.php') + .expect(/hello world/) + .expect(200) + .end(function _basicNoCloseCB_endEvent(err, res) { + if (err) return done(err); + connect.closeServer(); + setTimeout(done, 150); + }); + }); + }); + +}); \ No newline at end of file From c36c7bf54d443ca3185c2f2f263dabfd6cc40895 Mon Sep 17 00:00:00 2001 From: "Glenn R. Martin" Date: Mon, 17 Apr 2017 14:43:04 -0400 Subject: [PATCH 6/8] Basic JavaDoc style comments on Methods and Classes. Error parameter for start callback. --- index.js | 37 +++++++++++++++++++++++++++++++++++-- test/test.js | 15 ++++++++++----- 2 files changed, 45 insertions(+), 7 deletions(-) diff --git a/index.js b/index.js index dfcdb5e..b95e4f4 100644 --- a/index.js +++ b/index.js @@ -1,7 +1,7 @@ /* jshint esversion: 6, node: true */ 'use strict'; -(function _gulp_php_connect_module_scoping(OPTIONS_SPAWN_OBJ, OPTIONS_PHP_CLI_ARR) { +(function _gulp_connect_php_module_scoping(OPTIONS_SPAWN_OBJ, OPTIONS_PHP_CLI_ARR) { const childProcess = require('child_process'); let spawn = childProcess.spawn; const exec = childProcess.exec; @@ -19,6 +19,12 @@ const PhpDevelopmentServerConnection = ((function _PhpDevelopmentServerConnection_private_scope() { const Status = new EnumSet('NEW', 'STARTING', 'STARTED', 'FINISHED'); + /** + * Private: Check wherther the server is running. + * @param hostname + * @param port + * @param cb + */ function checkServer(hostname, port, cb) { const self = this; //console.log(`[${this.counter}] checkServer`); @@ -55,7 +61,17 @@ }, 15); } + /** + * PHP Development Server Connection Instance + * + * {@link http://php.net/manual/en/features.commandline.webserver.php} + */ class PhpDevelopmentServerConnection { + /** + * Create a new Instance + * @param opts Default Options. Will be merged with our own internal set of default options. Can be overwridden in the connect ('server') call. + * @returns {PhpDevelopmentServerConnection} + */ constructor(opts) { //this.counter = ++counter; //console.log(`[${this.counter}] constructor`); @@ -81,6 +97,10 @@ return this; // `new` bug } + /** + * 'Close'/Shutdown the PHP Development Server + * @param cb Optional single parameter Callback. Parameter is the return (if any) of the node `ChildProcess.kill(...)` call or nothing if not started. + */ closeServer(cb) { cb = cb || function _closeServerCb_noop() { }; //console.log(`[${this.counter}] closeServer`); @@ -99,14 +119,27 @@ cb(); } + /** + * Get the port the server is running on. + * @returns {number|*} Port number. + */ get port() { return this.workingPort; } + /** + * Start the Server + * @param options Optional Server Options to overwrite the defaults in the CTor. + * @param cb Optional Callback for Completion. May pass in an error when there is a fault. + */ server(options, cb) { //console.log(`[${this.counter}] server`); cb = cb || function _serverCB_noop() { }; const self = this; + if (this.status !== Status.NEW && this.status !== Status.FINISHED) { + return cb(new Error('You may not start a server that is starting or started.')); + } + options = Object.assign({}, this.defaults, options); this.workingPort = options.port; @@ -148,7 +181,7 @@ binVersionCheck(options.bin, '>=5.4', function _binVerCheck(err) { if (err) { - cb(); + cb(err); return; } const checkPath = function _checkPath() { diff --git a/test/test.js b/test/test.js index 471f4a1..e16759b 100644 --- a/test/test.js +++ b/test/test.js @@ -20,7 +20,8 @@ const noopReturn = function _noopReturn(x) { return x; }; describe('gulp-connect-php', function _base_suite1() { it('Should start a basic php server', function _test_basic(done) { - connect.server({}, function _basic_serverCallback() { + connect.server({}, function _basic_serverCallback(error) { + if (error) throw error; request('http://127.0.0.1:8000') .get('/test/fixtures/hello.php') .expect(/hello world/) @@ -44,7 +45,8 @@ describe('gulp-connect-php', function _base_suite1() { const conn1 = new connect(); const conn2 = new connect(); - conn1.server({port: 8001}, function _multiples1_serverCallback() { + conn1.server({port: 8001}, function _multiples1_serverCallback(error) { + if (error) throw error; request('http://127.0.0.1:8001') .get('/test/fixtures/hello.php') .expect(/hello world/) @@ -57,7 +59,8 @@ describe('gulp-connect-php', function _base_suite1() { }); }); - conn2.server({port: 8002}, function _multiples2_serverCallback() { + conn2.server({port: 8002}, function _multiples2_serverCallback(error) { + if (error) throw error; request('http://127.0.0.1:8002') .get('/test/fixtures/hello.php') .expect(/hello world/) @@ -87,7 +90,8 @@ describe('gulp-connect-php', function _base_suite1() { return newArgs.concat(collection); } } - }, function _configCallback_serverCallback() { + }, function _configCallback_serverCallback(error) { + if (error) throw error; request('http://127.0.0.1:8000') .get('/test/fixtures/config-cb-checker.php') .expect(/ENVVAR=SET_OK,MEM_LIMIT=2\.1G;/) @@ -102,7 +106,8 @@ describe('gulp-connect-php', function _base_suite1() { }); it('Should start a basic php server without a close callback', function _test_basicNoCloseCB(done) { - connect.server({}, function _basicNoCloseCB_serverCallback() { + connect.server({}, function _basicNoCloseCB_serverCallback(error) { + if (error) throw error; request('http://127.0.0.1:8000') .get('/test/fixtures/hello.php') .expect(/hello world/) From 2a7dc776561e22f88dd6a440dba44cbb14773be3 Mon Sep 17 00:00:00 2001 From: "Glenn R. Martin" Date: Mon, 17 Apr 2017 15:38:22 -0400 Subject: [PATCH 7/8] Windows Validation - Readme example for a Batch script - Fix for Advanced Options Callback that wasnt resepcting bad retuns as we comitted to in the documentation. Tests added for this condition. --- README.md | 46 ++++++++++++++++++++++++++++++++++++++++++++ index.js | 2 +- test/test.js | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 101 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 11c0975..fac87c9 100644 --- a/README.md +++ b/README.md @@ -102,6 +102,52 @@ gulp.task('disconnect', function() { gulp.task('default', ['connect', 'disconnect']); ``` +### Windows (via Batch file) + +Windows Batch file execution via a `%PATH%` specified batchfile is possible, but some considerations are required. + +1. The batch file must be on your `%PATH%` and executable with permissions of the invoker. +2. You must pass the parameter set off to the PHP process. +3. We have no -real- way of detecting an error state at this point. +4. You must use the 'Advanced Option Maniulation' scheme and set the `shell` option on `spawn(...)`. + +#### Scenario + +- PHP is located at `C:\Users\mainuser\Applications\PHP\7.0.17-NTS-VC14\php.exe`. +- The batch file is located at `C:\Users\mainuser\MyProject\strap\php.bat`. +- I have set `%PATH%` manually to `C:\Users\mainuser\MyProject\strap\;%PATH%`. + +#### Contents of php.bat + +```batch +@echo off + +REM We specify the whole path to PHP since the working directory is that of gulp... +REM unless we also changed that in our gulp callback. + +C:\Users\mainuser\Applications\PHP\7.0.17-NTS-VC14\php.exe %* +``` + +#### Contents of our gulp task +```js +gulp.task('connect', function _gulp_connect_task() { + connect.server({ + configCallback: function _configCallback(type, collection) { + if (type === connect.OPTIONS_SPAWN_OBJ) { + // Windows Batch files are NOT executable on their own. This will start a shell + // session then execute. + collection.shell = true; + return collection; + } + } + }, function _connected_callback() { + console.log("PHP Development Server Connected."); + }); +}); + +gulp.task('default', ['connect']); +```` + ## Options ### port diff --git a/index.js b/index.js index b95e4f4..f98a7ac 100644 --- a/index.js +++ b/index.js @@ -175,7 +175,7 @@ spawn = function _configCallbackSpawn(outerSpawn) { return function configCallbackSpawnWrapper(file, spawnArgs, spawnOptions) { - return outerSpawn(file, options.configCallback(OPTIONS_PHP_CLI_ARR, spawnArgs), options.configCallback(OPTIONS_SPAWN_OBJ, spawnOptions)); + return outerSpawn(file, options.configCallback(OPTIONS_PHP_CLI_ARR, spawnArgs) || spawnArgs, options.configCallback(OPTIONS_SPAWN_OBJ, spawnOptions) || spawnOptions); } }(spawn); diff --git a/test/test.js b/test/test.js index e16759b..b35bd92 100644 --- a/test/test.js +++ b/test/test.js @@ -120,4 +120,58 @@ describe('gulp-connect-php', function _base_suite1() { }); }); + it('Should start a basic php server, with a set environment variable and updated memory limits set via the configCallback option with null', function _test_configCallback(done) { + connect.server({ + configCallback: function _configCallback(type, collection) { + if (type === connect.OPTIONS_SPAWN_OBJ) { + collection.env = Object.assign({ + TEST_ENV_VAR: "SET_OK" + }, process.env); + + return collection; + } else if (type === connect.OPTIONS_PHP_CLI_ARR) { + return null; + } + } + }, function _configCallback_serverCallback(error) { + if (error) throw error; + request('http://127.0.0.1:8000') + .get('/test/fixtures/config-cb-checker.php') + .expect(/ENVVAR=SET_OK,MEM_LIMIT=2\.1G;/) + .expect(200) + .end(function _configCallback_endEvent(err, res) { + if (err) return done(err); + connect.closeServer(function _configCallback_closeServer() { + done(); + }); + }); + }); + }); + + it('Should start a basic php server, with a set environment variable and updated memory limits set via the configCallback option with no return', function _test_configCallback(done) { + connect.server({ + configCallback: function _configCallback(type, collection) { + if (type === connect.OPTIONS_SPAWN_OBJ) { + collection.env = Object.assign({ + TEST_ENV_VAR: "SET_OK" + }, process.env); + + return collection; + } + } + }, function _configCallback_serverCallback(error) { + if (error) throw error; + request('http://127.0.0.1:8000') + .get('/test/fixtures/config-cb-checker.php') + .expect(/ENVVAR=SET_OK,MEM_LIMIT=2\.1G;/) + .expect(200) + .end(function _configCallback_endEvent(err, res) { + if (err) return done(err); + connect.closeServer(function _configCallback_closeServer() { + done(); + }); + }); + }); + }); + }); \ No newline at end of file From 68ce3a01c000a2167a32ffc4e1006e1bf9cde17a Mon Sep 17 00:00:00 2001 From: "Glenn R. Martin" Date: Mon, 17 Apr 2017 16:07:19 -0400 Subject: [PATCH 8/8] Fix for binVersionCheck and Paths with spaces. Work originally by @nurtext as part of PR: github.com/micahblu/gulp-connect-php/pull/36. --- index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.js b/index.js index f98a7ac..4609fc3 100644 --- a/index.js +++ b/index.js @@ -179,7 +179,7 @@ } }(spawn); - binVersionCheck(options.bin, '>=5.4', function _binVerCheck(err) { + binVersionCheck(`"${options.bin}"`, '>=5.4', function _binVerCheck(err) { if (err) { cb(err); return;