Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Browser map refactor #15

Closed
Closed
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion .jscsrc
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,6 @@
"mark": "'",
"escape": true
},
"validateIndentation": "\t",
"disallowMixedSpacesAndTabs": true,
"disallowTrailingWhitespace": true,
"disallowKeywordsOnNewLine": [ "else", "catch" ],
Expand Down
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
## Upcoming Release

#### Breaking changes
- None yet
- Type `phantom` is now `phantomjs`, which is a little more consistent
- The property "name" is more descriptive for variant channels, e.g. "chrome-canary"

#### User features
- None yet
Expand Down
7 changes: 2 additions & 5 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
var path = require( 'path' ),
_ = require( 'lodash' ),
configModule = require( './lib/config' ),
detect = require( './lib/detect' ),
run = require( './lib/run' ),
Expand Down Expand Up @@ -74,15 +73,13 @@ function getLauncher( configFile, callback ) {
*/
getLauncher.detect = function( callback ) {
detect( function( browsers ) {
callback( browsers.map( function( browser ) {
return _.pick( browser, [ 'name', 'version', 'type', 'command' ] );
} ) );
callback(browsers);
} );
};

/**
* Update the browsers cache and create new profiles if necessary
* @param {String} configDir Path to the configuration file
* @param {String} configFile Path to the configuration file
* @param {Function} callback Callback function
*/
getLauncher.update = function( configFile, callback ) {
Expand Down
File renamed without changes.
2 changes: 1 addition & 1 deletion lib/darwin/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@ exports.safari = require( './safari' );
exports.firefox = require( './firefox' );
exports.chrome = exports[ 'google-chrome' ] = require( './chrome' );
exports.chromium = require( './chromium' );
exports.canary = exports[ 'chrome-canary' ] = exports[ 'google-chrome-canary' ] = require( './canary' );
exports['chrome-canary'] = require( './chrome-canary' );
exports.opera = require( './opera' );
exports.phantomjs = require( './phantomjs' );
259 changes: 141 additions & 118 deletions lib/detect.js
Original file line number Diff line number Diff line change
@@ -1,66 +1,51 @@
var spawn = require( 'child_process' ).spawn,
winDetect = require( 'win-detect-browsers' ),
darwin = require( './darwin' ),
extend = require( 'lodash' ).extend,
browsers = {
'google-chrome': {
name: 'chrome',
re: /Google Chrome (\S+)/,
type: 'chrome',
profile: true
},
'google-chrome-canary': {
name: 'canary',
re: /Google Chrome (\S+)/,
type: 'chrome',
profile: true
},
'chromium': {
name: 'chromium',
re: /Chromium (\S+)/,
type: 'chrome',
profile: true
omit = require( 'lodash' ).omit,
browsers = { // List of commands and version regex for Linux and Mac
chrome: {
regex: /Google Chrome (\S+)/,
profile: true,
variants: {
'chrome': [ 'google-chrome', 'google-chrome-stable' ],
'chrome-beta': 'google-chrome-beta',
'chrome-canary': 'google-chrome-canary'
}
},
'chromium-browser': {
name: 'chromium',
re: /Chromium (\S+)/,
type: 'chrome',
profile: true
chromium: {
regex: /Chromium (\S+)/,
profile: true,
variants: {
'chromium': [ 'chromium', 'chromium-browser' ]
}
},
'firefox': {
name: 'firefox',
re: /Mozilla Firefox (\S+)/,
type: 'firefox',
profile: true
firefox: {
regex: /Mozilla Firefox (\S+)/,
profile: true,
variants: {
'firefox': 'firefox',
'firefox-developer': 'firefox-developer'
}
},
'phantomjs': {
name: 'phantomjs',
re: /(\S+)/,
type: 'phantom',
phantomjs: {
regex: /(\S+)/,
profile: false,
headless: true,
profile: false
variants: 'phantomjs'
},
'safari': {
name: 'safari',
type: 'safari',
profile: false
safari: {
profile: false,
variants: 'safari'
},
'ie': {
name: 'ie',
type: 'ie',
profile: false
ie: {
profile: false,
variants: 'ie'
},
'opera': {
name: 'opera',
re: /Opera (\S+)/,
type: 'opera',
image: 'opera.exe',
profile: true
opera: {
regex: /Opera (\S+)/,
profile: true,
variants: 'opera'
}
},
winDetectMap = {
chrome: 'google-chrome',
chromium: 'chromium-browser'
};

/**
Expand All @@ -71,13 +56,12 @@ var spawn = require( 'child_process' ).spawn,
function detectWindows( callback ) {
winDetect( function( found ) {
var available = found.map( function( browser ) {
var br = browsers[ winDetectMap[ browser.name ] || browser.name ];

return extend( {}, {
return {
name: browser.name,
type: browser.name,
command: browser.path,
version: browser.version
}, br || {} );
};
} );

callback( available );
Expand All @@ -90,45 +74,41 @@ function detectWindows( callback ) {
* @param {String} name Name of a browser
* @param {Function} callback Callback function
*/
function checkDarwin( name, callback ) {
if ( darwin[ name ] ) {
if ( darwin[ name ].all ) {
darwin[ name ].all( function( err, available ) {
if ( err ) {
callback( 'failed to get version for ' + name );
} else {
callback( err, available );
}
} );
} else {
darwin[ name ].version( function( err, version ) {
if ( version ) {
darwin[ name ].path( function( err, p ) {
if ( err ) {
return callback( 'failed to get path for ' + name );
}

callback( null, version, p );
} );
} else {
callback( 'failed to get version for ' + name );
}
} );
}
function checkDarwin(name, callback) {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just removed the surrounding if statement and moved the manual call of checkOthers to the main detection function

if (darwin[name].all) {
darwin[name].all(function (err, available) {
if (err) {
callback('failed to get version for ' + name);
} else {
callback(err, available);
}
});
} else {
checkOthers( name, callback );
darwin[name].version(function (err, version) {
if (version) {
darwin[name].path(function (err, p) {
if (err) {
return callback('failed to get path for ' + name);
}

callback(null, version, p);
});
} else {
callback('failed to get version for ' + name);
}
});
}
}

/**
* Check if the given browser is available (on Unix systems).
* Pass its version to the callback function if found.
* @param {String} name Name of a browser
* @param {RegExp} regex Version matching regex
* @param {Function} callback Callback function
*/
function checkOthers( name, callback ) {
function checkOthers( name, regex, callback ) {
var process = spawn( name, [ '--version' ] ),
re = browsers[ name ].re,
data = '';

process.stdout.on( 'data', function( buf ) {
Expand All @@ -149,10 +129,10 @@ function checkOthers( name, callback ) {
return callback( 'not installed' );
}

var m = re.exec( data );
var match = regex.exec( data );

if ( m ) {
callback( null, m[ 1 ] );
if ( match ) {
callback( null, match[ 1 ] );
} else {
callback( null, data.trim() );
}
Expand All @@ -165,49 +145,92 @@ function checkOthers( name, callback ) {
* @param {Function} callback Callback function
*/
module.exports = function detect( callback ) {
var available = [],
names,
check;

if ( process.platform === 'win32' ) {
if (process.platform === 'win32' ) {
return detectWindows( callback );
} else if ( process.platform === 'darwin' ) {
check = checkDarwin;
} else {
check = checkOthers;
}

names = Object.keys( browsers );
var isOsx = process.platform === 'darwin';
var flatBrowsers = [];

function useDarwinCheck(name) {
return isOsx && darwin[ name ];
}

Object.keys(browsers).map(function(type) {
var multiBrowser = browsers[type];
var regex = multiBrowser.regex;

function next() {
var name = names.shift();
function pushCheck(func, name, type, command) {
var properties = omit(multiBrowser, 'variants');
properties.name = name;
properties.type = type;
properties.command = command;
flatBrowsers.push({func, properties});
}

if ( !name ) {
return callback( available );
if (typeof browsers[type].variants === 'string') {
var check = useDarwinCheck(type) ?
checkDarwin.bind(undefined, type) :
checkOthers.bind(undefined, browsers[type].variants, regex);
pushCheck(check, type, type, browsers[type].variants);
return;
}

var br = browsers[ name ];
Object.keys(multiBrowser.variants).forEach(function(name) {
var variant = multiBrowser.variants[name];

check( name, function( err, v, p ) {
if ( err === null ) {
if ( Array.isArray( v ) ) {
v.forEach( function( item ) {
available.push( extend( {}, br, {
command: item.path,
version: item.version
} ) );
if ( useDarwinCheck( name ) ) {
pushCheck(checkDarwin.bind(undefined, name), type, name);
return;
}

// if variant is a single command
if (typeof variant === 'string') {
pushCheck(checkOthers.bind(undefined, variant, regex), type, name, variant);
return;
}

// variant must be a list of commands
variant.forEach(function(command) {
pushCheck(checkOthers.bind(undefined, command, regex), type, name, command);
});
});
});

var checksComplete = 0;
var available = [];

flatBrowsers.forEach(function(flatBrowser) {
var properties = flatBrowser.properties;
function cb( err, version, path ) {
if ( !err ) {
if ( Array.isArray( version ) ) {
// If `version` is an array, then it's actually a "darwin check" returning multiple browswers.
// See `darwin/firefox.js`
version.forEach( function( item ) {
available.push({
name: properties.name,
type: properties.type,
version: item.version,
command: item.path || properties.command
});
} );
} else {
available.push( extend( {}, br, {
command: p || name,
version: v
} ) );
available.push({
name: properties.name,
type: properties.type,
version: version,
command: path || properties.command
});
}
}

next();
} );
}
checksComplete++;
if (checksComplete === flatBrowsers.length) {
callback(available);
}
}

next();
flatBrowser.func(cb);
});
};