Introduce react native CLI
Reviewed By: @frantic Differential Revision: D2430522
This commit is contained in:
parent
71628638f6
commit
833ca598bc
|
@ -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) {
|
||||
|
|
|
@ -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;
|
|
@ -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;
|
|
@ -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;
|
|
@ -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;
|
|
@ -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();
|
|
@ -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);
|
Loading…
Reference in New Issue