Gant 445182c707 react-native link (aka rnpm) support for Windows
Summary:
Seeing as [Windows is a supported platform](72157cf991/packager/defaults.js (L22)) until platforms can better manager their own CLI and packager needs.

Linking 3rd party libraries should be supported first, because then I'd like to do a follow up PR with grabbou to identify how we can effectively move RNPM functionality out of react-native core and eventually housed in each external platform's repo.  The goal would be working with cpojer and hopefully andrewimm to help keep external platform needs in their respective repos, for rnpm/packager _et al._  Seeing as this is a major discussion point, I've made this PR first.  Making small steps towards this goal, seems to be the approved methodology from all.

Additionally, I have a merged PR that makes an excellent place for documenting the CLI when it advances, as preparatio
Closes https://github.com/facebook/react-native/pull/11282

Differential Revision: D4311391

fbshipit-source-id: be9a836344be4aed6c4732b0ce4947c2a16b6dad
2016-12-10 16:58:28 -08:00

180 lines
5.2 KiB
JavaScript

/**
* Copyright (c) 2013-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.
*/
const log = require('npmlog');
const path = require('path');
const uniq = require('lodash').uniq;
const flatten = require('lodash').flatten;
const chalk = require('chalk');
const isEmpty = require('lodash').isEmpty;
const promiseWaterfall = require('./promiseWaterfall');
const registerDependencyAndroid = require('./android/registerNativeModule');
const registerDependencyWindows = require('./windows/registerNativeModule');
const registerDependencyIOS = require('./ios/registerNativeModule');
const isInstalledAndroid = require('./android/isInstalled');
const isInstalledWindows = require('./windows/isInstalled');
const isInstalledIOS = require('./ios/isInstalled');
const copyAssetsAndroid = require('./android/copyAssets');
const copyAssetsIOS = require('./ios/copyAssets');
const getProjectDependencies = require('./getProjectDependencies');
const getDependencyConfig = require('./getDependencyConfig');
const pollParams = require('./pollParams');
const commandStub = require('./commandStub');
const promisify = require('./promisify');
log.heading = 'rnpm-link';
const dedupeAssets = (assets) => uniq(assets, asset => path.basename(asset));
const linkDependencyAndroid = (androidProject, dependency) => {
if (!androidProject || !dependency.config.android) {
return null;
}
const isInstalled = isInstalledAndroid(androidProject, dependency.name);
if (isInstalled) {
log.info(chalk.grey(`Android module ${dependency.name} is already linked`));
return null;
}
return pollParams(dependency.config.params).then(params => {
log.info(`Linking ${dependency.name} android dependency`);
registerDependencyAndroid(
dependency.name,
dependency.config.android,
params,
androidProject
);
log.info(`Android module ${dependency.name} has been successfully linked`);
});
};
const linkDependencyWindows = (windowsProject, dependency) => {
if (!windowsProject || !dependency.config.windows) {
return null;
}
const isInstalled = isInstalledWindows(windowsProject, dependency.config.windows);
if (isInstalled) {
log.info(chalk.grey(`Windows module ${dependency.name} is already linked`));
return null;
}
return pollParams(dependency.config.params).then(params => {
log.info(`Linking ${dependency.name} windows dependency`);
registerDependencyWindows(
dependency.name,
dependency.config.windows,
params,
windowsProject
);
log.info(`Windows module ${dependency.name} has been successfully linked`);
});
};
const linkDependencyIOS = (iOSProject, dependency) => {
if (!iOSProject || !dependency.config.ios) {
return;
}
const isInstalled = isInstalledIOS(iOSProject, dependency.config.ios);
if (isInstalled) {
log.info(chalk.grey(`iOS module ${dependency.name} is already linked`));
return;
}
log.info(`Linking ${dependency.name} ios dependency`);
registerDependencyIOS(dependency.config.ios, iOSProject);
log.info(`iOS module ${dependency.name} has been successfully linked`);
};
const linkAssets = (project, assets) => {
if (isEmpty(assets)) {
return;
}
if (project.ios) {
log.info('Linking assets to ios project');
copyAssetsIOS(assets, project.ios);
}
if (project.android) {
log.info('Linking assets to android project');
copyAssetsAndroid(assets, project.android.assetsPath);
}
log.info('Assets have been successfully linked to your project');
};
/**
* Updates project and links all dependencies to it
*
* If optional argument [packageName] is provided, it's the only one that's checked
*/
function link(args, config) {
var project;
try {
project = config.getProjectConfig();
} catch (err) {
log.error(
'ERRPACKAGEJSON',
'No package found. Are you sure it\'s a React Native project?'
);
return Promise.reject(err);
}
const packageName = args[0];
const dependencies = getDependencyConfig(
config,
packageName ? [packageName] : getProjectDependencies()
);
const assets = dedupeAssets(dependencies.reduce(
(assets, dependency) => assets.concat(dependency.config.assets),
project.assets
));
const tasks = flatten(dependencies.map(dependency => [
() => promisify(dependency.config.commands.prelink || commandStub),
() => linkDependencyAndroid(project.android, dependency),
() => linkDependencyIOS(project.ios, dependency),
() => linkDependencyWindows(project.windows, dependency),
() => promisify(dependency.config.commands.postlink || commandStub),
]));
tasks.push(() => linkAssets(project, assets));
return promiseWaterfall(tasks).catch(err => {
log.error(
`It seems something went wrong while linking. Error: ${err.message} \n`
+ 'Please file an issue here: https://github.com/facebook/react-native/issues'
);
throw err;
});
}
module.exports = {
func: link,
description: 'links all native dependencies',
name: 'link [packageName]',
};