Introduce react native CLI

Reviewed By: @frantic

Differential Revision: D2430522
This commit is contained in:
Martín Bigio 2015-09-22 09:00:04 -07:00 committed by facebook-github-bot-4
parent 71628638f6
commit 833ca598bc
7 changed files with 274 additions and 2 deletions

View File

@ -20,7 +20,8 @@
var optimist = require('optimist');
function parseCommandLine(config) {
function parseCommandLine(config, args) {
args = args || process.argv;
// optimist default API requires you to write the command name three time
// This is a small wrapper to accept an object instead
for (var i = 0; i < config.length; ++i) {
@ -38,7 +39,7 @@ function parseCommandLine(config) {
optimist.demand(config[i].command);
}
}
var argv = optimist.parse(process.argv);
var argv = optimist.parse(args);
// optimist doesn't have support for --dev=false, instead it returns 'false'
for (var i = 0; i < config.length; ++i) {

25
private-cli/index.js Normal file
View File

@ -0,0 +1,25 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/
'use strict';
require('babel-core/register')({
only: [
/react-native-github\/private-cli\/src/
],
});
var cli = require('./src/cli');
var fs = require('fs');
var gracefulFs = require('graceful-fs');
// graceful-fs helps on getting an error when we run out of file
// descriptors. When that happens it will enqueue the operation and retry it.
gracefulFs.gracefulify(fs);
module.exports = cli;

62
private-cli/src/cli.js Normal file
View File

@ -0,0 +1,62 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/
'use strict';
const Config = require('./util/Config');
const dependencies = require('./dependencies/dependencies');
const Promise = require('promise');
const documentedCommands = {
dependencies: dependencies,
};
const hiddenCommands = {
'-h': help,
'--help': help,
};
/**
* Programmatic entry point for the cli. This function runs the given
* command passing it the arguments array.
*/
function run(command, commandArgs) {
if (!command) {
throw new Error(helpMessage());
}
commandArgs = commandArgs || [];
const commandToExec = documentedCommands[command] || hiddenCommands[command];
if (!commandToExec) {
throw new Error(helpMessage(command));
}
commandToExec(commandArgs, Config.get()).done();
}
function helpMessage(command) {
const validCommands = Object
.keys(documentedCommands)
.map(c => '"' + c + '"')
.join(' | ');
if (command) {
return 'Unknown command "' + command + '". ' +
'Available commands: ' + validCommands;
} else {
return 'Must specify a command. Available commands: ' +
validCommands;
}
}
function help() {
console.log(helpMessage());
return Promise.resolve();
}
module.exports.run = run;

View File

@ -0,0 +1,93 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/
'use strict';
const fs = require('fs');
const log = require('../util/log').out('dependencies');
const parseCommandLine = require('../../../packager/parseCommandLine');
const path = require('path');
const Promise = require('Promise');
const ReactPackager = require('../../../packager/react-packager');
/**
* Returns the dependencies an entry path has.
*/
function dependencies(argv, conf) {
return new Promise((resolve, reject) => {
_dependencies(argv, conf, resolve, reject);
});
}
function _dependencies(argv, conf, resolve, reject) {
const args = parseCommandLine([
{
command: 'entry-file',
description: 'Absolute path to the root JS file',
type: 'string',
required: true,
}, {
command: 'output',
description: 'File name where to store the output, ex. /tmp/dependencies.txt',
type: 'string',
}
], argv);
const rootModuleAbsolutePath = args['entry-file'];
if (!fs.existsSync(rootModuleAbsolutePath)) {
reject(`File ${rootModuleAbsolutePath} does not exist`);
}
const config = {
projectRoots: conf.getProjectRoots(),
assetRoots: conf.getAssetRoots(),
blacklistRE: conf.getBlacklistRE(),
transformModulePath: conf.getTransformModulePath(),
};
const relativePath = config.projectRoots.map(root =>
path.relative(
root,
rootModuleAbsolutePath
)
)[0];
const writeToFile = args.output;
const outStream = writeToFile
? fs.createWriteStream(args.output)
: process.stdout;
log('Running ReactPackager');
log('Waiting for the packager.');
resolve(ReactPackager.createClientFor(config).then(client => {
log('Packager client was created');
return client.getDependencies(relativePath)
.then(deps => {
log('Packager returned dependencies');
client.close();
deps.forEach(module => {
// Temporary hack to disable listing dependencies not under this directory.
// Long term, we need either
// (a) JS code to not depend on anything outside this directory, or
// (b) Come up with a way to declare this dependency in Buck.
const isInsideProjectRoots = config.projectRoots.filter(root =>
module.path.startsWith(root)
).length > 0;
if (isInsideProjectRoots) {
outStream.write(module.path + '\n');
}
});
writeToFile && outStream.end();
log('Wrote dependencies to output file');
});
}));
}
module.exports = dependencies;

View File

@ -0,0 +1,60 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/
'use strict';
const fs = require('fs');
const path = require('path');
const RN_CLI_CONFIG = 'rn-cli.config.js';
let cachedConfig = null;
/**
* Module capable of getting the configuration that should be used for
* the `rn-cli`. The configuration file is a JS file named `rn-cli.conf.js`.
* It has to be on any parent directory of the cli.
*/
const Config = {
get() {
if (cachedConfig) {
return cachedConfig;
}
const parentDir = findParentDirectory(__dirname, RN_CLI_CONFIG);
if (!parentDir) {
throw new Error(
'Can\'t find "rn-cli.config.js" file in any parent folder of "' +
__dirname + '"'
);
}
cachedConfig = require(path.join(parentDir, RN_CLI_CONFIG));
return cachedConfig;
}
};
// Finds the most near ancestor starting at `currentFullPath` that has
// a file named `filename`
function findParentDirectory(currentFullPath, filename) {
const root = path.parse(currentFullPath).root;
const testDir = (parts) => {
if (parts.length === 0) {
return null;
}
const fullPath = path.join(root, parts.join(path.sep));
var exists = fs.existsSync(path.join(fullPath, filename));
return exists ? fullPath : testDir(parts.slice(0, -1));
};
return testDir(currentFullPath.substring(1).split(path.sep));
}
module.exports = Config;

View File

@ -0,0 +1,12 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/
'use strict';
module.exports.out = () => jest.genMockFn();
module.exports.err = () => jest.genMockFn();

View File

@ -0,0 +1,19 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/
'use strict';
function log(stream, module) {
return function() {
const message = Array.prototype.slice.call(arguments).join(' ');
stream.write(module + ': ' + message + '\n');
};
}
module.exports.out = log.bind(null, process.stdout);
module.exports.err = log.bind(null, process.stderr);