Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
51 changes: 38 additions & 13 deletions __tests__/run.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
// Copyright (c) 2019 Magic Leap, Inc. All Rights Reserved
// Distributed under Apache 2.0 License. See LICENSE file in the project root for full license information.
const path = require('path');
// eslint-disable-next-line camelcase
const child_process = require('child_process');
jest.spyOn(child_process, 'exec');
jest.spyOn(child_process, 'spawn');
Expand All @@ -20,7 +22,7 @@ afterEach(() => {
describe('Test Run', () => {
test('not installed "com.abc"', () => {
jest.spyOn(util, 'isInstalled').mockImplementationOnce((packageName, callback) => {
expect(packageName == 'com.abc').toBeTruthy();
expect(packageName === 'com.abc').toBeTruthy();
callback(false);
});
jest.spyOn(console, 'warn').mockImplementationOnce((data) => {
Expand All @@ -31,7 +33,7 @@ describe('Test Run', () => {

test('not installed "com.abc" running', () => {
jest.spyOn(util, 'isInstalled').mockImplementationOnce((packageName, callback) => {
expect(packageName == 'com.abc').toBeTruthy();
expect(packageName === 'com.abc').toBeTruthy();
callback(false);
});
jest.spyOn(console, 'warn').mockImplementationOnce((data) => {
Expand All @@ -48,7 +50,7 @@ describe('Test Run', () => {

test('Installed "com.abc"', () => {
const mockIsInstalled = jest.spyOn(util, 'isInstalled').mockImplementationOnce((packageName, callback) => {
expect(packageName == 'com.abc').toBeTruthy();
expect(packageName === 'com.abc').toBeTruthy();
callback(true);
});
child_process.exec.mockImplementationOnce((command, cb) => {
Expand All @@ -61,7 +63,7 @@ describe('Test Run', () => {

test('Installed "com.abc" running', () => {
const mockIsInstalled = jest.spyOn(util, 'isInstalled').mockImplementationOnce((packageName, callback) => {
expect(packageName == 'com.abc').toBeTruthy();
expect(packageName === 'com.abc').toBeTruthy();
callback(true);
});
jest.spyOn(console, 'info').mockImplementationOnce((data) => {
Expand All @@ -81,7 +83,7 @@ describe('Test Run', () => {

test('Installed "com.abc" running error', () => {
const mockIsInstalled = jest.spyOn(util, 'isInstalled').mockImplementationOnce((packageName, callback) => {
expect(packageName == 'com.abc').toBeTruthy();
expect(packageName === 'com.abc').toBeTruthy();
callback(true);
});
jest.spyOn(console, 'info').mockImplementationOnce((data) => {
Expand All @@ -104,7 +106,7 @@ describe('Test Run', () => {

test('Installed "com.abc" running error launch', () => {
const mockIsInstalled = jest.spyOn(util, 'isInstalled').mockImplementationOnce((packageName, callback) => {
expect(packageName == 'com.abc').toBeTruthy();
expect(packageName === 'com.abc').toBeTruthy();
callback(true);
});
jest.spyOn(console, 'info').mockImplementationOnce((data) => {
Expand Down Expand Up @@ -138,7 +140,7 @@ describe('Test Run', () => {
return { 'stderr': { 'on': stderr }, 'stdout': { 'on': stdout } };
});
const mockIsInstalled = jest.spyOn(util, 'isInstalled').mockImplementationOnce((packageName, callback) => {
expect(packageName == 'com.abc').toBeTruthy();
expect(packageName === 'com.abc').toBeTruthy();
callback(true);
});
jest.spyOn(console, 'info').mockImplementationOnce((data) => {
Expand Down Expand Up @@ -177,7 +179,7 @@ describe('Test Run', () => {
return { 'stderr': { 'on': stderr }, 'stdout': { 'on': stdout }, 'kill': kill };
});
const mockIsInstalled = jest.spyOn(util, 'isInstalled').mockImplementationOnce((packageName, callback) => {
expect(packageName == 'com.abc').toBeTruthy();
expect(packageName === 'com.abc').toBeTruthy();
callback(true);
});
jest.spyOn(console, 'info').mockImplementationOnce((data) => {
Expand Down Expand Up @@ -220,7 +222,7 @@ describe('Test Run', () => {
return { 'stderr': { 'on': stderr }, 'stdout': { 'on': stdout }, 'kill': kill };
});
const mockIsInstalled = jest.spyOn(util, 'isInstalled').mockImplementationOnce((packageName, callback) => {
expect(packageName == 'com.abc').toBeTruthy();
expect(packageName === 'com.abc').toBeTruthy();
callback(true);
});
jest.spyOn(console, 'info').mockImplementationOnce((data) => {
Expand Down Expand Up @@ -263,7 +265,7 @@ describe('Test Run', () => {
return { 'stderr': { 'on': stderr }, 'stdout': { 'on': stdout }, 'kill': kill };
});
const mockIsInstalled = jest.spyOn(util, 'isInstalled').mockImplementationOnce((packageName, callback) => {
expect(packageName == 'com.abc').toBeTruthy();
expect(packageName === 'com.abc').toBeTruthy();
callback(true);
});
jest.spyOn(console, 'info').mockImplementationOnce((data) => {
Expand Down Expand Up @@ -291,7 +293,7 @@ describe('Test Run', () => {

test('Installed "com.abc" running launch log exec success no debug', () => {
const mockIsInstalled = jest.spyOn(util, 'isInstalled').mockImplementationOnce((packageName, callback) => {
expect(packageName == 'com.abc').toBeTruthy();
expect(packageName === 'com.abc').toBeTruthy();
callback(true);
});
jest.spyOn(console, 'info').mockImplementationOnce((data) => {
Expand Down Expand Up @@ -319,7 +321,7 @@ describe('Test Run', () => {

test('Installed "com.abc" running launch with port specified success no debug', () => {
const mockIsInstalled = jest.spyOn(util, 'isInstalled').mockImplementationOnce((packageName, callback) => {
expect(packageName == 'com.abc').toBeTruthy();
expect(packageName === 'com.abc').toBeTruthy();
callback(true);
});
jest.spyOn(console, 'info').mockImplementationOnce((data) => {
Expand Down Expand Up @@ -347,7 +349,7 @@ describe('Test Run', () => {

test('Installed "com.abc" running terminated', () => {
const mockIsInstalled = jest.spyOn(util, 'isInstalled').mockImplementationOnce((packageName, callback) => {
expect(packageName == 'com.abc').toBeTruthy();
expect(packageName === 'com.abc').toBeTruthy();
callback(true);
});
jest.spyOn(console, 'info').mockImplementationOnce((data) => {
Expand All @@ -367,4 +369,27 @@ describe('Test Run', () => {
expect(mockIsInstalled).toHaveBeenCalled();
expect(child_process.exec).toHaveBeenCalled();
});

test('run on host', () => {
child_process.spawn.mockImplementationOnce((command, params) => {
let stdout = function (data, callback) {
expect(data).toBe('data');
callback('1440 chrome://asdf:12345');
};
let stderr = function (data, callback) {
expect(data).toBe('data');
callback('1440 chrome://asdf:12345');
};
expect(command).toBe('mxs');
expect(params.length).toBe(1);
expect(params[0]).toBe('bin/index.js');
return { 'stderr': { 'on': stderr }, 'stdout': { 'on': stdout } };
});
jest.spyOn(util, 'findMPKPath').mockReturnValueOnce('myPath');
process.chdir = jest.fn();
jest.spyOn(path, 'join');
run({ '_': ['run', 'com.abc'], 'host': true, target: 'lumin' });
expect(child_process.spawn).toHaveBeenCalled();
expect(path.join).toHaveBeenCalledWith('bin', 'index.js');
});
});
4 changes: 4 additions & 0 deletions bin/magic-script.js
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,10 @@ require('yargs') // eslint-disable-line
alias: 'p',
default: 0
});
yargs.option('host', {
alias: 'h',
default: false
});
yargs.positional('target', {
describe: 'target(s) to build for',
default: 'lumin'
Expand Down
129 changes: 83 additions & 46 deletions commands/run.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,13 @@
let { exec, spawn } = require('child_process');
let util = require('../lib/util');
let hash = require('hash-index');
let path = require('path');
let fs = require('fs');

let packageName;
let debug;
let port;
let host;

function getPortFromPackageName () {
return hash(packageName, 65535 - 1024) + 1024;
Expand Down Expand Up @@ -42,16 +45,16 @@ function launchFunction (callback) {
let portArg = '-v INSPECTOR_PORT=' + portNumber;
let launchCommand = `mldb launch${autoPrivilege} ${portArg} ${packageName}`;
console.info(`Launching: ${packageName} at port: ${portNumber}`);
function cb (result) {
callback(result);
}
exec(launchCommand, (err, stdout, stderr) => {
if (err) {
console.error(`exec error: ${err}`);
callback(null);
return;
}
if (stdout.includes('Success')) {
function cb (result) {
callback(result);
}
isRunning(cb);
}
});
Expand All @@ -65,67 +68,101 @@ function terminateFunction (callback) {
});
}

function callCommand (command, parameters, shouldForward, pid) {
let spawnCommand = spawn(command, parameters);
spawnCommand.stdout.on('data', (rawData) => {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

'data' means you received some data, it may not be all. If you're block buffered between processes, it'd be possible to get part of the chrome message in one callback, and the rest in another. Or unlikely, but even split across 3 or more reads.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

In theory this is possible, but I haven't encountered this yet in my testing. So far all of the data chunks have been split at newlines

if (rawData !== undefined) {
let data = `${rawData}`;
if ((data.includes(pid) || pid === undefined) && data.includes('chrome')) {
if (shouldForward) {
spawnCommand.kill();
}
let pattern = /chrome.+:(\d{3,5})/;
let matches = data.match(pattern);
if (matches && matches.length > 1) {
let port = matches[1];
if (shouldForward) {
let forwardCommand = 'mldb forward tcp:' + port + ' tcp:' + port;
exec(forwardCommand, (err, stdout, stderr) => {
if (!err && stdout.length === 0 && stderr.length === 0) {
console.info('Success: port forwarded', port);
console.log('Please open in chrome:', matches[0]);
}
});
} else {
console.log('Please open in chrome:', matches[0]);
}
}
}
}
});
spawnCommand.stderr.on('data', (rawData) => {
if (rawData !== undefined) {
let data = `${rawData}`;
let debugPattern = /chrome.+:(\d{3,5})/;
let matches = data.match(debugPattern);
if (matches && matches.length > 1) {
console.log('Please open in chrome:', matches[0]);
}
let pattern = /MagicScript: [debug:|info:].*/g;
data = data.replace(pattern, '').trim();
data = data.replace(/(\r\n|\r|\n){2,}/g, '$1\n');
if (data.length > 0) {
console.log(data);
}
}
});
}

function launchCallback (pid) {
if (pid == null) {
if (pid === null) {
console.error('Failed to launch:', packageName);
return;
}
if (!debug) {
return;
}
const mldbCommand = spawn('mldb', ['log']);
mldbCommand.stdout.on('data', (data) => {
if (data.includes(pid) && data.includes('chrome')) {
mldbCommand.kill();
let dataString = `${data}`;
let pattern = /chrome.+:(\d{3,5})/;
let matches = dataString.match(pattern);
if (matches.length > 1) {
let port = matches[1];
let forwardCommand = 'mldb forward tcp:' + port + ' tcp:' + port;
exec(forwardCommand, (err, stdout, stderr) => {
if (!err && stdout.length == 0 && stderr.length == 0) {
console.info('Success: port forwarded', port);
console.log('Please open in chrome:', matches[0]);
}
});
}
}
});
mldbCommand.stderr.on('data', (data) => {
console.error(`mldbCommand stderr:\n${data}`);
});
callCommand('mldb', ['log'], true, pid);
console.info(packageName, 'launched with PID:', pid);
}

function runLumin (argv) {
let localArguments = argv._;
debug = argv.debug;
port = argv.port;
if (localArguments.length > 1) {
packageName = localArguments[1];
host = argv.host;
if (host) {
let mpkPath = util.findMPKPath();
let hostPath = path.dirname(mpkPath);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

I believe this is "correct enough" in that I don't know of a time when the MPK and the app directory differ. This is how the VSCode extension runs mabu to determine the CWD:

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

mabu_args = ['-t', 'host', '--print-layout-directories', projectTargetPath]

let result = fs.existsSync(hostPath);
console.log(mpkPath, hostPath, result);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Do we want to leave this log in?

if (result) {
process.chdir(hostPath);
}
callCommand('mxs', [path.join('bin', 'index.js')], false);
} else {
packageName = util.findPackageName();
}
if (packageName) {
function installedCallback (installed) {
if (installed) {
isRunning(runningCallback);
} else {
console.warn(`Package: ${packageName} is not installed. Please install it.`);
}
if (localArguments.length > 1) {
packageName = localArguments[1];
} else {
packageName = util.findPackageName();
}
function runningCallback (pid) {
if (pid == null) {
launchFunction(launchCallback);
} else {
function launchMe () {
launchFunction(launchCallback);
if (packageName) {
util.isInstalled(packageName, (installed) => {
if (installed) {
isRunning((pid) => {
if (pid === null) {
launchFunction(launchCallback);
} else {
terminateFunction(() => {
launchFunction(launchCallback);
});
}
});
} else {
console.warn(`Package: ${packageName} is not installed. Please install it.`);
}
terminateFunction(launchMe);
}
});
}
util.isInstalled(packageName, installedCallback);
}
}

Expand Down
2 changes: 1 addition & 1 deletion lib/util.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ module.exports.isInstalled = function (packageName, callback) {

module.exports.startMLDB = function () {
var output = execSync('mldb start-server');
if (typeof output == 'string') {
if (typeof output === 'string') {
console.log(output);
} else {
console.log(output.toString('utf8'));
Expand Down
23 changes: 16 additions & 7 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.