Skip to content

Commit

Permalink
Merge rnpm into react-native
Browse files Browse the repository at this point in the history
Summary:
This is initial (first step) in the merging process. For now, we are just going to move our code as is into `local-cli` folder (first commit). There were other tweaks made in separate commits to make it easier to go through the code as the diff is expected to be rather large. The purpose of this is to make it easier to start working in small batches and improving the CLI incrementally on a daily basis.

Current codebase will still leave in `rnpm` organisation on Github where we keep working on new features, bugs and ship releases to `npm` until we finish our integration and provide a nice interface for users to migrate (in case it changes at all)

Flow, Jest and npm will ignore this folder for now until we integrate it properly.

Tests are to be rewritten from mocha to jest in `rnpm/link`. We will hook them all up as soon as we start using them in local-cli.

For now, there's no point in having them running and possibly breaking the builds.

We will announce next steps with Kureev later this week
Closes #7550

Differential Revision: D3327772

Pulled By: mkonicek

fbshipit-source-id: 90faa4bd78476d93ed21b1253e0d95c755d28a30
  • Loading branch information
grabbou authored and Facebook Github Bot 9 committed May 20, 2016
1 parent 00c7780 commit 149d0b9
Show file tree
Hide file tree
Showing 142 changed files with 5,980 additions and 1 deletion.
3 changes: 3 additions & 0 deletions .flowconfig
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,9 @@
# Ignore BUCK generated folders
.*\.buckd/

# Ignore RNPM
.*/local-cli/rnpm/.*

.*/node_modules/is-my-json-valid/test/.*\.json
.*/node_modules/iconv-lite/encodings/tables/.*\.json
.*/node_modules/y18n/test/.*\.json
Expand Down
2 changes: 2 additions & 0 deletions .npmignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# rnpm
/local-cli/rnpm
50 changes: 50 additions & 0 deletions local-cli/rnpm/core/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
{
"name": "rnpm",
"version": "1.7.0",
"description": "React Native Package Manager",
"main": "./src/getCommands.js",
"scripts": {
"test": "jest"
},
"jest": {
"testDirectoryName": "test",
"collectCoverage": true,
"testRunner": "<rootDir>/node_modules/jest-cli/src/testRunners/jasmine/jasmine2.js"
},
"author": "Amazing React Native Community (https://github.com/facebook/react-native)",
"contributors": [
"Alexey Kureev <kureev-mail@ya.ru> (https://github.com/Kureev)",
"Mike Grabowski <grabbou@gmail.com> (https://github.com/grabbou)"
],
"engines": {
"node": ">= 4.0.0"
},
"license": "MIT",
"bugs": {
"url": "https://github.com/rnpm/rnpm/issues"
},
"keywords": [
"react-native",
"native-modules",
"packager",
"rnpm"
],
"homepage": "https://github.com/rnpm/rnpm#readme",
"dependencies": {
"commander": "^2.9.0",
"glob": "^7.0.1",
"lodash": "^3.10.1",
"rnpm-plugin-install": "^1.1.0",
"rnpm-plugin-link": "^1.7.4",
"update-notifier": "^0.6.0",
"xmldoc": "^0.4.0"
},
"devDependencies": {
"babel-eslint": "^4.1.5",
"eslint": "^1.9.0",
"mock-fs": "^3.5.0",
"mock-require": "^1.2.1",
"rewire": "^2.5.1",
"jest-cli": "^0.9.0-fb2"
}
}
21 changes: 21 additions & 0 deletions local-cli/rnpm/core/src/config/android/findAndroidAppFolder.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
const fs = require('fs');
const path = require('path');

/**
* @param {String} folder Folder to seek in
* @return {String}
*/
module.exports = function findAndroidAppFolder(folder) {
const flat = 'android';
const nested = path.join('android', 'app');

if (fs.existsSync(path.join(folder, nested))) {
return nested;
}

if (fs.existsSync(path.join(folder, flat))) {
return flat;
}

return null;
};
17 changes: 17 additions & 0 deletions local-cli/rnpm/core/src/config/android/findManifest.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
const glob = require('glob');
const path = require('path');

/**
* Find an android application path in the folder
*
* @param {String} folder Name of the folder where to seek
* @return {String}
*/
module.exports = function findManifest(folder) {
const manifestPath = glob.sync(path.join('**', 'AndroidManifest.xml'), {
cwd: folder,
ignore: ['node_modules/**', '**/build/**', 'Examples/**', 'examples/**'],
})[0];

return manifestPath ? path.join(folder, manifestPath) : null;
};
20 changes: 20 additions & 0 deletions local-cli/rnpm/core/src/config/android/findPackageClassName.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
const fs = require('fs');
const path = require('path');
const glob = require('glob');

/**
* Gets package's class name (class that implements ReactPackage)
* by searching for its declaration in all Java files present in the folder
*
* @param {String} folder Folder to find java files
*/
module.exports = function getPackageClassName(folder) {
const files = glob.sync('**/*.java', { cwd: folder });

const packages = files
.map(filePath => fs.readFileSync(path.join(folder, filePath), 'utf8'))
.map(file => file.match(/class (.*) implements ReactPackage/))
.filter(match => match);

return packages.length ? packages[0][1] : null;
};
111 changes: 111 additions & 0 deletions local-cli/rnpm/core/src/config/android/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
const path = require('path');
const fs = require('fs');
const glob = require('glob');
const findAndroidAppFolder = require('./findAndroidAppFolder');
const findManifest = require('./findManifest');
const readManifest = require('./readManifest');
const findPackageClassName = require('./findPackageClassName');

const getPackageName = (manifest) => manifest.attr.package;

/**
* Gets android project config by analyzing given folder and taking some
* defaults specified by user into consideration
*/
exports.projectConfig = function projectConfigAndroid(folder, userConfig) {
const src = userConfig.sourceDir || findAndroidAppFolder(folder);

if (!src) {
return null;
}

const sourceDir = path.join(folder, src);
const isFlat = sourceDir.indexOf('app') === -1;
const manifestPath = findManifest(sourceDir);

if (!manifestPath) {
return null;
}

const manifest = readManifest(manifestPath);

const packageName = userConfig.packageName || getPackageName(manifest);
const packageFolder = userConfig.packageFolder ||
packageName.replace(/\./g, path.sep);

const mainActivityPath = path.join(
sourceDir,
userConfig.mainActivityPath || `src/main/java/${packageFolder}/MainActivity.java`
);

const stringsPath = path.join(
sourceDir,
userConfig.stringsPath || 'src/main/res/values/strings.xml'
);

const settingsGradlePath = path.join(
folder,
'android',
userConfig.settingsGradlePath || 'settings.gradle'
);

const assetsPath = path.join(
sourceDir,
userConfig.assetsPath || 'src/main/assets'
);

const buildGradlePath = path.join(
sourceDir,
userConfig.buildGradlePath || 'build.gradle'
);

return {
sourceDir,
isFlat,
folder,
stringsPath,
manifestPath,
buildGradlePath,
settingsGradlePath,
assetsPath,
mainActivityPath,
};
};

/**
* Same as projectConfigAndroid except it returns
* different config that applies to packages only
*/
exports.dependencyConfig = function dependencyConfigAndroid(folder, userConfig) {
const src = userConfig.sourceDir || findAndroidAppFolder(folder);

if (!src) {
return null;
}

const sourceDir = path.join(folder, src);
const manifestPath = findManifest(sourceDir);

if (!manifestPath) {
return null;
}

const manifest = readManifest(manifestPath);
const packageName = userConfig.packageName || getPackageName(manifest);
const packageClassName = findPackageClassName(sourceDir);

/**
* This module has no package to export
*/
if (!packageClassName) {
return null;
}

const packageImportPath = userConfig.packageImportPath ||
`import ${packageName}.${packageClassName};`;

const packageInstance = userConfig.packageInstance ||
`new ${packageClassName}()`;

return { sourceDir, folder, manifest, packageImportPath, packageInstance };
};
10 changes: 10 additions & 0 deletions local-cli/rnpm/core/src/config/android/readManifest.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
const fs = require('fs');
const xml = require('xmldoc');

/**
* @param {String} manifestPath
* @return {XMLDocument} Parsed manifest's content
*/
module.exports = function readManifest(manifestPath) {
return new xml.XmlDocument(fs.readFileSync(manifestPath, 'utf8'));
};
20 changes: 20 additions & 0 deletions local-cli/rnpm/core/src/config/findAssets.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
const glob = require('glob');
const path = require('path');

const findAssetsInFolder = (folder) =>
glob.sync(path.join(folder, '**'), { nodir: true });

/**
* Given an array of assets folders, e.g. ['Fonts', 'Images'],
* it globs in them to find all files that can be copied.
*
* It returns an array of absolute paths to files found.
*/
module.exports = function findAssets(folder, assets) {
return (assets || [])
.map(assetsFolder => path.join(folder, assetsFolder))
.reduce((assets, assetsFolder) =>
assets.concat(findAssetsInFolder(assetsFolder)),
[]
);
};
44 changes: 44 additions & 0 deletions local-cli/rnpm/core/src/config/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
const path = require('path');

const android = require('./android');
const ios = require('./ios');
const findAssets = require('./findAssets');
const wrapCommands = require('./wrapCommands');

const getRNPMConfig = (folder) =>
require(path.join(folder, './package.json')).rnpm || {};

/**
* Returns project config from the current working directory
* @return {Object}
*/
exports.getProjectConfig = function getProjectConfig() {
const folder = process.cwd();
const rnpm = getRNPMConfig(folder);

return Object.assign({}, rnpm, {
ios: ios.projectConfig(folder, rnpm.ios || {}),
android: android.projectConfig(folder, rnpm.android || {}),
assets: findAssets(folder, rnpm.assets),
});
};

/**
* Returns a dependency config from node_modules/<package_name>
* @param {String} packageName Dependency name
* @return {Object}
*/
exports.getDependencyConfig = function getDependencyConfig(packageName) {
const folder = path.join(process.cwd(), 'node_modules', packageName);
const rnpm = getRNPMConfig(
path.join(process.cwd(), 'node_modules', packageName.split('/')[0])
);

return Object.assign({}, rnpm, {
ios: ios.dependencyConfig(folder, rnpm.ios || {}),
android: android.dependencyConfig(folder, rnpm.android || {}),
assets: findAssets(folder, rnpm.assets),
commands: wrapCommands(rnpm.commands),
params: rnpm.params || [],
});
};
47 changes: 47 additions & 0 deletions local-cli/rnpm/core/src/config/ios/findProject.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
const glob = require('glob');
const path = require('path');

/**
* Glob pattern to look for xcodeproj
*/
const GLOB_PATTERN = '**/*.xcodeproj';

/**
* Regexp matching all test projects
*/
const TEST_PROJECTS = /test|example|sample/i;

/**
* Base iOS folder
*/
const IOS_BASE = 'ios';

/**
* These folders will be excluded from search to speed it up
*/
const GLOB_EXCLUDE_PATTERN = ['**/@(Pods|node_modules)/**'];

/**
* Finds iOS project by looking for all .xcodeproj files
* in given folder.
*
* Returns first match if files are found or null
*
* Note: `./ios/*.xcodeproj` are returned regardless of the name
*/
module.exports = function findProject(folder) {
const projects = glob
.sync(GLOB_PATTERN, {
cwd: folder,
ignore: GLOB_EXCLUDE_PATTERN,
})
.filter(project => {
return path.dirname(project) === IOS_BASE || !TEST_PROJECTS.test(project);
});

if (projects.length === 0) {
return null;
}

return projects[0];
};
31 changes: 31 additions & 0 deletions local-cli/rnpm/core/src/config/ios/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
const path = require('path');
const findProject = require('./findProject');

/**
* Returns project config by analyzing given folder and applying some user defaults
* when constructing final object
*/
exports.projectConfig = function projectConfigIOS(folder, userConfig) {
const project = userConfig.project || findProject(folder);

/**
* No iOS config found here
*/
if (!project) {
return null;
}

const projectPath = path.join(folder, project);

return {
sourceDir: path.dirname(projectPath),
folder: folder,
pbxprojPath: path.join(projectPath, 'project.pbxproj'),
projectPath: projectPath,
projectName: path.basename(projectPath),
libraryFolder: userConfig.libraryFolder || 'Libraries',
plist: userConfig.plist || [],
};
};

exports.dependencyConfig = exports.projectConfig;
Loading

0 comments on commit 149d0b9

Please sign in to comment.