Skip to content

Commit

Permalink
Many bug fixes. Changed the simulator detect results so that all simu…
Browse files Browse the repository at this point in the history
…lator info is now in a 'simulators' object. Fixed detection and handling of sim runtimes and device types.
  • Loading branch information
cb1kenobi committed Jul 28, 2015
1 parent 4665a51 commit e5ecf1b
Show file tree
Hide file tree
Showing 8 changed files with 265 additions and 229 deletions.
Binary file modified lib/iphone_sim_activate.scpt
Binary file not shown.
277 changes: 118 additions & 159 deletions lib/simulator.js

Large diffs are not rendered by default.

32 changes: 30 additions & 2 deletions lib/utilities.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,16 @@

const
appc = require('node-appc'),
bplist = require('bplist-parser'),
crypto = require('crypto'),
EventEmitter = require('events').EventEmitter,
fs = require('fs'),
__ = appc.i18n(__dirname).__;

exports.magik = magik;
exports.hash = hash;
exports.readPlist = readPlist;

/**
* Creates an event emitter, validates that the platform is OS X,
* normalizes the 'options' and 'callback' arguments, and passes all
Expand All @@ -27,7 +33,7 @@ const
*
* @returns {EventEmitter}
*/
exports.magik = function magik(options, callback, body) {
function magik(options, callback, body) {
var emitter = new EventEmitter;
emitter.on('error', function () {});

Expand Down Expand Up @@ -59,6 +65,28 @@ exports.magik = function magik(options, callback, body) {
*
* @returns {String} The MD5 hash.
*/
exports.hash = function hash(str) {
function hash(str) {
return crypto.createHash('md5').update(str || '').digest('hex');
};

/**
* Parses both ascii and binary plist files and returns a JSON representation.
*
* @param {String} file - The path to the plist file.
*
* @returns {Object|null} - Returns a JSON representation of the plist file or null if the file does not exist or unable to parse.
*/
function readPlist(file) {
try {
if (fs.existsSync(file)) {
var buffer = fs.readFileSync(file),
header = buffer.slice(0, 'bplist'.length).toString('utf8');
if (header === 'bplist') {
return bplist.parseBuffer(buffer)[0];
} else {
return (new appc.plist()).parse(buffer.toString());
}
}
} catch (ex) {}
return null;
}
81 changes: 67 additions & 14 deletions lib/xcode.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ const
magik = require('./utilities').magik,
fs = require('fs'),
path = require('path'),
readPlist = require('./utilities').readPlist,
__ = appc.i18n(__dirname).__;

var cache,
Expand Down Expand Up @@ -67,6 +68,26 @@ exports.detect = function detect(options, callback) {
return fireCallbacks(null, cache);
}

function findSimRuntimes(dir) {
var runtimes = {};
fs.existsSync(dir) && fs.readdirSync(dir).forEach(function (name) {
var x = path.join(dir, name, 'Contents', 'Info.plist');
var plist = readPlist(path.join(dir, name, 'Contents', 'Info.plist'));
if (plist) {
var runtime = runtimes[plist.CFBundleIdentifier] = {
name: plist.CFBundleName,
version: null
};

plist = readPlist(path.join(dir, name, 'Contents', 'Resources', 'profile.plist'));
if (plist) {
runtime.version = plist.defaultVersionString;
}
}
});
return runtimes;
}

var searchPaths = {
'/Applications': 1,
'~/Applications': 1
Expand All @@ -76,7 +97,8 @@ exports.detect = function detect(options, callback) {
xcode: {},
issues: []
},
selectedXcodePath = null;
selectedXcodePath = null,
globalSimRuntimes = findSimRuntimes('/Library/Developer/CoreSimulator/Profiles/Runtimes');

// since we do not support Xcode 5 and below, weed them out
options.supportedVersions = (options.supportedVersions ? options.supportedVersions + '||' : '') + '>=6.0.0';
Expand Down Expand Up @@ -205,16 +227,18 @@ exports.detect = function detect(options, callback) {
};
}

results.xcode[ver] = {
xcodeapp: dir.replace(/\/Contents\/Developer\/?$/, ''),
path: dir,
selected: selected,
version: p.CFBundleShortVersionString,
build: p.ProductBuildVersion,
supported: supported,
sdks: findSDKs(path.join(dir, 'Platforms', 'iPhoneOS.platform', 'Developer', 'SDKs'), /^iPhoneOS(.+)\.sdk$/, options.minIosVersion),
sims: findIosSims(path.join(dir, 'Platforms', 'iPhoneSimulator.platform', 'Developer', 'SDKs'), p.CFBundleShortVersionString),
watchos: watchos,
var xc = results.xcode[ver] = {
xcodeapp: dir.replace(/\/Contents\/Developer\/?$/, ''),
path: dir,
selected: selected,
version: p.CFBundleShortVersionString,
build: p.ProductBuildVersion,
supported: supported,
sdks: findSDKs(path.join(dir, 'Platforms', 'iPhoneOS.platform', 'Developer', 'SDKs'), /^iPhoneOS(.+)\.sdk$/, options.minIosVersion),
sims: findIosSims(path.join(dir, 'Platforms', 'iPhoneSimulator.platform', 'Developer', 'SDKs'), p.CFBundleShortVersionString),
simDeviceTypes: {},
simRuntimes: appc.util.mix({}, globalSimRuntimes),
watchos: watchos,
executables: {
xcodebuild: fs.existsSync(f = path.join(dir, 'usr', 'bin', 'xcodebuild')) ? f : null,
clang: fs.existsSync(f = path.join(dir, 'Toolchains', 'XcodeDefault.xctoolchain', 'usr', 'bin', 'clang')) ? f : null,
Expand All @@ -229,20 +253,49 @@ exports.detect = function detect(options, callback) {
}
};

['iPhoneSimulator.platform', 'WatchSimulator.platform'].forEach(function (platform) {
// read in the device types
var deviceTypesDir = path.join(xc.path, 'Platforms', platform, 'Developer', 'Library', 'CoreSimulator', 'Profiles', 'DeviceTypes');
fs.existsSync(deviceTypesDir) && fs.readdirSync(deviceTypesDir).forEach(function (name) {
var plist = readPlist(path.join(deviceTypesDir, name, 'Contents', 'Info.plist')),
devId = plist && plist.CFBundleIdentifier;
if (plist) {
var deviceType = xc.simDeviceTypes[devId] = {
name: plist.CFBundleName,
model: 'unknown',
supportsWatch: false
};

plist = readPlist(path.join(deviceTypesDir, name, 'Contents', 'Resources', 'profile.plist'));
if (plist) {
deviceType.model = plist.modelIdentifier;
}

plist = readPlist(path.join(deviceTypesDir, name, 'Contents', 'Resources', 'capabilities.plist'));
if (plist) {
deviceType.supportsWatch = !!plist.capabilities['watch-companion'];
}
}
});

// read in the runtimes
appc.util.mix(xc.simRuntimes, findSimRuntimes(path.join(xc.path, 'Platforms', platform, 'Developer', 'Library', 'CoreSimulator', 'Profiles', 'Runtimes')));
});

['Simulator', 'iOS Simulator'].some(function (name) {
var p = path.join(dir, 'Applications', name + '.app', 'Contents', 'MacOS', name);
if (fs.existsSync(p)) {
results.xcode[ver].executables.simulator = p;
xc.executables.simulator = p;
return true;
}
});

var watchsim = path.join(dir, 'Applications', 'Simulator (Watch).app', 'Contents', 'MacOS', 'Simulator (Watch)');
if (fs.existsSync(watchsim)) {
results.xcode[ver].executables.watchsimulator = watchsim;
xc.executables.watchsimulator = watchsim;
}

selected && (results.selectedXcode = results.xcode[ver]);
selected && (results.selectedXcode = xc);

if (supported === false) {
results.issues.push({
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "ioslib",
"version": "0.4.0",
"version": "0.4.1",
"description": "iOS Utility Library",
"keywords": [
"appcelerator",
Expand Down
4 changes: 2 additions & 2 deletions test/test-ioslib.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ describe('ioslib', function () {

should(results).be.an.Object;
should(results).have.keys('detectVersion', 'issues', 'devices', 'provisioning', 'executables', 'selectedXcode',
'xcode', 'certs', 'deviceTypes', 'runtimes', 'ios', 'watchos', 'devicePairs', 'crashDir');
'xcode', 'certs', 'simulators');

should(results.detectVersion).be.a.String;

Expand Down Expand Up @@ -162,7 +162,7 @@ describe('ioslib', function () {

function checkXcode(xcode) {
should(xcode).be.an.Object;
should(xcode).have.keys('xcodeapp', 'path', 'selected', 'version', 'build', 'supported', 'sdks', 'sims', 'watchos', 'executables');
should(xcode).have.keys('xcodeapp', 'path', 'selected', 'version', 'build', 'supported', 'sdks', 'sims', 'simDeviceTypes', 'simRuntimes', 'watchos', 'executables');

should(xcode.xcodeapp).be.a.String;
should(xcode.xcodeapp).not.equal('');
Expand Down
75 changes: 25 additions & 50 deletions test/test-simulator.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ function checkSims(sims) {
should(sims).be.an.Array;
sims.forEach(function (sim) {
should(sim).be.an.Object;
should(sim).have.keys('udid', 'name', 'version', 'deviceType', 'deviceName', 'deviceDir', 'model', 'family', 'supportsWatch', 'runtime', 'runtimeName', 'xcode', 'systemLog', 'dataDir');
should(sim).have.keys('udid', 'name', 'version', 'deviceType', 'deviceName', 'deviceDir', 'model', 'family', 'supportsXcode', 'supportsWatch', 'runtime', 'runtimeName', 'systemLog', 'dataDir');

['udid', 'name', 'version', 'state', 'deviceType', 'deviceName', 'deviceDir', 'model', 'family', 'runtime', 'runtimeName', 'xcode', 'systemLog', 'dataDir'].forEach(function (key) {
if (sim[key] !== null) {
Expand Down Expand Up @@ -156,62 +156,35 @@ describe('simulator', function () {
}

should(results).be.an.Object;
should(results).have.keys('deviceTypes', 'runtimes', 'ios', 'watchos', 'devicePairs', 'crashDir', 'issues');

should(results.deviceTypes).be.an.Object;
Object.keys(results.deviceTypes).forEach(function (name) {
should(results.deviceTypes[name]).be.an.Object;
should(results.deviceTypes[name]).have.keys('name', 'model', 'supportsWatch', 'xcode');
should(results.deviceTypes[name].name).be.a.String;
should(results.deviceTypes[name].name).not.equal('');
should(results.deviceTypes[name].model).be.a.String;
should(results.deviceTypes[name].model).not.equal('');
should(results.deviceTypes[name].supportsWatch).be.a.Object;
Object.keys(results.deviceTypes[name].supportsWatch).forEach(function (ver) {
should(results.deviceTypes[name].supportsWatch[ver]).be.a.Boolean;
});
should(results.deviceTypes[name].xcode).be.a.String;
should(results.deviceTypes[name].xcode).not.equal('');
});
should(results).have.keys('simulators', 'issues');

should(results.runtimes).be.an.Object;
Object.keys(results.runtimes).forEach(function (name) {
should(results.runtimes[name]).be.an.Object;
should(results.runtimes[name]).have.keys('name', 'version', 'xcode');
should(results.runtimes[name].name).be.a.String;
should(results.runtimes[name].name).not.equal('');
should(results.runtimes[name].version).be.a.String;
should(results.runtimes[name].version).not.equal('');
if (results.runtimes[name].xcode !== null) {
should(results.runtimes[name].xcode).be.a.String;
should(results.runtimes[name].xcode).not.equal('');
}
});
should(results.simulators).be.an.Object;
should(results.simulators).have.keys('ios', 'watchos', 'devicePairs', 'crashDir');

should(results.ios).be.an.Object;
Object.keys(results.ios).forEach(function (ver) {
checkSims(results.ios[ver]);
should(results.simulators.ios).be.an.Object;
Object.keys(results.simulators.ios).forEach(function (ver) {
checkSims(results.simulators.ios[ver]);
});

should(results.watchos).be.an.Object;
Object.keys(results.watchos).forEach(function (ver) {
checkSims(results.watchos[ver]);
should(results.simulators.watchos).be.an.Object;
Object.keys(results.simulators.watchos).forEach(function (ver) {
checkSims(results.simulators.watchos[ver]);
});

should(results.devicePairs).be.an.Object;
Object.keys(results.devicePairs).forEach(function (udid) {
should(results.devicePairs[udid]).be.an.Object;
should(results.devicePairs[udid]).have.keys('phone', 'watch');
should(results.devicePairs[udid].phone).be.a.String;
should(results.devicePairs[udid].phone).not.equal('');
should(results.devicePairs[udid].watch).be.a.String;
should(results.devicePairs[udid].watch).not.equal('');
should(results.simulators.devicePairs).be.an.Object;
Object.keys(results.simulators.devicePairs).forEach(function (udid) {
should(results.simulators.devicePairs[udid]).be.an.Object;
should(results.simulators.devicePairs[udid]).have.keys('phone', 'watch');
should(results.simulators.devicePairs[udid].phone).be.a.String;
should(results.simulators.devicePairs[udid].phone).not.equal('');
should(results.simulators.devicePairs[udid].watch).be.a.String;
should(results.simulators.devicePairs[udid].watch).not.equal('');
});

should(results.crashDir).be.a.String;
should(results.crashDir).not.equal('');
if (fs.existsSync(results.crashDir)) {
should(fs.statSync(results.crashDir).isDirectory()).be.true;
should(results.simulators.crashDir).be.a.String;
should(results.simulators.crashDir).not.equal('');
if (fs.existsSync(results.simulators.crashDir)) {
should(fs.statSync(results.simulators.crashDir).isDirectory()).be.true;
}

should(results.issues).be.an.Array;
Expand All @@ -232,7 +205,7 @@ describe('simulator', function () {
this.timeout(60000);
this.slow(60000);

ioslib.simulator.launch(null, null, function (err, simHandle, watchSimHandle) {
ioslib.simulator.launch('79D1EC85-352F-4D63-B92F-C397345934A6', null, function (err, simHandle, watchSimHandle) {
simHandlesToWipe.push(simHandle, watchSimHandle);

if (err) {
Expand All @@ -250,6 +223,8 @@ describe('simulator', function () {
done();
});
});
//}).on('log-debug', function (line, simHandle) {
// console.log((simHandle ? '[' + simHandle.family.toUpperCase() + '] ' : '') + '[DEBUG]', line);
});
});

Expand Down
23 changes: 22 additions & 1 deletion test/test-xcode.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ const

function checkXcode(xcode) {
should(xcode).be.an.Object;
should(xcode).have.keys('xcodeapp', 'path', 'selected', 'version', 'build', 'supported', 'sdks', 'sims', 'watchos', 'executables');
should(xcode).have.keys('xcodeapp', 'path', 'selected', 'version', 'build', 'supported', 'sdks', 'sims', 'simDeviceTypes', 'simRuntimes', 'watchos', 'executables');

should(xcode.xcodeapp).be.a.String;
should(xcode.xcodeapp).not.equal('');
Expand Down Expand Up @@ -49,6 +49,27 @@ function checkXcode(xcode) {
should(s).not.equal('');
});

should(xcode.simDeviceTypes).be.an.Object;
Object.keys(xcode.simDeviceTypes).forEach(function (name) {
should(xcode.simDeviceTypes[name]).be.an.Object;
should(xcode.simDeviceTypes[name]).have.keys('name', 'model', 'supportsWatch');
should(xcode.simDeviceTypes[name].name).be.a.String;
should(xcode.simDeviceTypes[name].name).not.equal('');
should(xcode.simDeviceTypes[name].model).be.a.String;
should(xcode.simDeviceTypes[name].model).not.equal('');
should(xcode.simDeviceTypes[name].supportsWatch).be.a.Boolean;
});

should(xcode.simRuntimes).be.an.Object;
Object.keys(xcode.simRuntimes).forEach(function (name) {
should(xcode.simRuntimes[name]).be.an.Object;
should(xcode.simRuntimes[name]).have.keys('name', 'version');
should(xcode.simRuntimes[name].name).be.a.String;
should(xcode.simRuntimes[name].name).not.equal('');
should(xcode.simRuntimes[name].version).be.a.String;
should(xcode.simRuntimes[name].version).not.equal('');
});

if (xcode.watchos !== null) {
should(xcode.watchos.sdks).be.an.Array;
xcode.watchos.sdks.forEach(function (s) {
Expand Down

0 comments on commit e5ecf1b

Please sign in to comment.