Skip to content

Commit

Permalink
Added hiding of xcode library schemes as a third feature.
Browse files Browse the repository at this point in the history
  • Loading branch information
Kevin Brown committed Jan 25, 2017
1 parent a050d2e commit 5fab200
Show file tree
Hide file tree
Showing 10 changed files with 122 additions and 44 deletions.
19 changes: 11 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,13 +39,12 @@ This configuration will copy the "Debug" build configuration to "Staging" and "P

## What Then?

The package will automatically run this script to do two things on `postinstall`:
The package is able to do three things:
- Swap its own version of react-native-xcode.sh in instead of the stock on that assumes all debug schemes are named 'Debug'.
- Add your build configurations to all library xcode projects.
- Hide any schemes that come from your library projects so they don't show up in the menu.

This means you shouldn't need to do anything further to make this work than the above.

When you want to fix up your xcode projects or script, `yarn` or `npm i` after removing your `node_modules` directory should re-run both scripts automatically.
As long as `react-native-schemes-manager all` has run whenever you add react native modules, you should be good to go.

## It's not working!

Expand All @@ -61,13 +60,17 @@ If you're still having trouble, post an issue so we can look into it.

## Running Manually

You can run the two parts of this package on demand by running either:
You can run the three parts of this package on demand by running either:

- `react-native-schemes-manager fix-libraries`: Adds your build configurations to all library xcode projects.
- `react-native-schemes-manager fix-script`: Swaps a schemes aware build script in instead of the stock react native one.
- `react-native-schemes-manager all`: Runs both scripts above.
- `react-native-schemes-manager hide-library-schemes`: Hides any build schemes that come from your node_modules folder xcodeproj files as you don't usually want to see them anyway.

And of course you can run all 3 easily if you'd prefer:

- `react-native-schemes-manager all`: Runs all the scripts above.

The best way to do this is add to your `package.json` scripts section like so:
The best way to give yourself a manual trigger for this is add to your `package.json` scripts section like so:

```json
{
Expand All @@ -80,7 +83,7 @@ The best way to do this is add to your `package.json` scripts section like so:
}
```

You can then `yarn run fix-xcode` or `npm run fix-xcode` which will run the script.
You can then `yarn run fix-xcode` or `npm run fix-xcode` which will run the cleanup scripts on demand.

## Further Reading

Expand Down
15 changes: 7 additions & 8 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,17 +1,13 @@
#! /usr/bin/env node
const glob = require('glob');

#!/usr/bin/env node
const yargs = require('yargs');

yargs
.usage('$0 command')
.command('all', 'run all bundled commands', yargs => {
const files = glob.sync('src/*.js');

for (const file of files) {
if (file.endsWith('utilities.js')) continue;
const operations = require('./src');

require('./' + file)();
for (const key of Object.keys(operations)) {
operations[key]();
}
})
.command('fix-libraries', 'add any missing build configurations to all xcode projects in node_modules', yargs => {
Expand All @@ -20,6 +16,9 @@ yargs
.command('fix-script', 'replace the react native ios bundler with our scheme aware one', yargs => {
require('./src/fix-script')();
})
.command('hide-library-schemes', `hide any schemes that come from your node modules directory so they don't clutter up the menu.`, yargs => {
require('./src/hide-library-schemes')();
})
.demand(1, 'must provide a valid command')
.help('h')
.alias('h', 'help')
Expand Down
7 changes: 7 additions & 0 deletions lib/react-native-xcode.sh
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

set +x

# And on to your previously scheduled React Native build script programming.
eval 'case "$CONFIGURATION" in
'$DEVELOPMENT_BUILD_CONFIGURATIONS')
echo "Debug build!"
Expand All @@ -36,6 +37,7 @@ esac'

# Path to react-native folder inside node_modules
REACT_NATIVE_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../../react-native" && pwd)"
SCHEMES_MANAGER_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"

# Xcode project file for React Native apps is located in ios/ subfolder
cd ..
Expand Down Expand Up @@ -78,3 +80,8 @@ $NODE_BINARY "$REACT_NATIVE_DIR/local-cli/cli.js" bundle \
--dev $DEV \
--bundle-output "$DEST/main.jsbundle" \
--assets-dest "$DEST"

# XCode randomly generates user specific workspace files whenever it feels like it.
# We want these hidden at all times, so go ahead and clean up if they're showing now.
cd "$SCHEMES_MANAGER_DIR/../.."
$NODE_BINARY "$SCHEMES_MANAGER_DIR/index.js" hide-library-schemes
5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "react-native-schemes-manager",
"version": "1.0.0-beta.3",
"version": "1.0.0-beta.4",
"description": "Helps to manage React Native XCode projects that use multiple schemes to manage things like environment variables.",
"main": "index.js",
"bin": {
Expand Down Expand Up @@ -31,9 +31,10 @@
},
"homepage": "https://github.com/Thinkmill/react-native-schemes-manager#readme",
"dependencies": {
"chalk": "^1.1.3",
"glob": "^7.1.1",
"path": "^0.12.7",
"uuid": "^3.0.1",
"plist": "^2.0.1",
"xcode": "^0.9.1",
"yargs": "^6.6.0"
},
Expand Down
8 changes: 4 additions & 4 deletions src/fix-libraries.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
const chalk = require('chalk');
const path = require('path');

const utilities = require('./utilities');
Expand All @@ -17,7 +18,6 @@ function configListForConfig (configLists, configUuid) {
}

function updateProject (project) {
console.log(path.dirname(path.relative(process.cwd(), project.filepath)));

const configs = project.pbxXCBuildConfigurationSection();
const configLists = project.pbxXCConfigurationList();
Expand All @@ -44,19 +44,19 @@ function updateProject (project) {
const clone = JSON.parse(JSON.stringify(debugConfig));
clone.name = mapping;

const configurationUuid = utilities.generateUuid();
const configurationUuid = project.generateUuid();
const configurationCommentKey = `${configurationUuid}_comment`;

configs[configurationUuid] = clone;
configs[configurationCommentKey] = mapping;
configList.buildConfigurations.push({ value: configurationUuid, comment: mapping });
}

console.log(` ✔ [created] Debug -> ${mapping}`);
console.log(chalk.gray(` ${chalk.green('✔')} [fix-libraries]: ${chalk.green('Debug -> ' + mapping + ' created')} in ${path.dirname(path.relative(process.cwd(), project.filepath))}`));

changed = true;
} else {
console.log(` - [skipped] Debug -> ${mapping}`);
console.log(chalk.gray(` - [fix-libraries]: Debug -> ${mapping} skipped in ${path.dirname(path.relative(process.cwd(), project.filepath))}`));
}
}

Expand Down
6 changes: 3 additions & 3 deletions src/fix-script.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
const chalk = require('chalk');
const path = require('path');

const utilities = require('./utilities');
Expand All @@ -15,17 +16,16 @@ function updateProject (project) {
// Found it!
// Need to add our actual mappings to the project.
const configurations = utilities.getMappings().join('|');

const newScript = `"export NODE_BINARY=node\\nexport DEVELOPMENT_BUILD_CONFIGURATIONS=\\"${configurations}|Debug\\"\\n../node_modules/react-native-schemes-manager/lib/react-native-xcode.sh"`;

if (step.shellScript === newScript) {
// It's already up to date.
console.log(' - [skipped] already done');
console.log(chalk.gray(` - [fix-script]: ${path.dirname(path.relative(process.cwd(), project.filepath))} skipped`));
return false;
} else {
step.shellScript = newScript;

console.log(` ✔ [fixed]`);
console.log(chalk.gray(` ${chalk.green('✔')} [fix-script]: ${path.dirname(path.relative(process.cwd(), project.filepath))} ${chalk.green('fixed')}`));
return true;
}
}
Expand Down
38 changes: 38 additions & 0 deletions src/hide-library-schemes.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
const chalk = require('chalk');
const path = require('path');

const utilities = require('./utilities');

function updateFile (file, filePath) {
let changed = false;

if (file.SchemeUserState) {
for (const key of Object.keys(file.SchemeUserState)) {
if (key.endsWith('.xcscheme')) {
const scheme = file.SchemeUserState[key];

if (!scheme.hasOwnProperty('isShown') || scheme.isShown) {
scheme.isShown = false;
changed = true;

console.log(chalk.gray(` ${chalk.green('✔')} [hide-library-schemes]: ${path.dirname(path.relative(process.cwd(), filePath))} ${chalk.green('hidden')}`));
} else {
console.log(chalk.gray(` - [hide-library-schemes]: ${path.dirname(path.relative(process.cwd(), filePath))} skipped`));
}
}
}
}

return changed;
}

module.exports = function findAndFix () {
// Find all of the pbxproj files we care about.
const userSpecificPattern = './node_modules/**/*.xcodeproj/xcuserdata/*.xcuserdatad/xcschemes/xcschememanagement.plist';

console.log(chalk.gray('Hiding schemes from node_modules xcode projects.'));

utilities.updatePlistsMatchingGlob(userSpecificPattern, (err, file, filePath) => {
return updateFile(file, filePath);
});
};
5 changes: 5 additions & 0 deletions src/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
module.exports = {
fixLibraries: require('./fix-libraries'),
fixScript: require('./fix-script'),
hideLibrarySchemes: require('./hide-library-schemes'),
};
43 changes: 28 additions & 15 deletions src/utilities.js
Original file line number Diff line number Diff line change
@@ -1,16 +1,14 @@
const fs = require('fs');
const glob = require('glob');
const path = require('path');
const uuid = require('uuid');
const plist = require('plist');
const xcode = require('xcode');

module.exports = {
getClosestLikelyReactNativeProjectPath () {
let currentPath = process.cwd();
let nextPath;

console.log(`searching in ${currentPath}`);

const pattern = 'ios/*.xcodeproj/project.pbxproj';
let files = glob.sync(path.join(currentPath, pattern));

Expand All @@ -32,29 +30,44 @@ module.exports = {
throw new Error('Could not locate a likely path.');
}
},
updateProjectsMatchingGlob (pattern, callback) {
// Find all of the pbxproj files we care about.
getFilesMatchingGlob (pattern, callback) {
// Find all of the files we care about.
const project = this.getClosestLikelyReactNativeProjectPath();
if (!project) return callback(new Error('Unable to find project path.'));

glob(path.join(project, pattern), (err, files) => {
if (err) throw err;

// Go through each project.
for (const projectPath of files) {
const project = xcode.project(projectPath);
project.parseSync();
for (const filePath of files) {
callback(null, filePath);
}
});
},
updateProjectsMatchingGlob (pattern, callback) {
this.getFilesMatchingGlob(pattern, (err, filePath) => {
if (!filePath) return callback(new Error('Unable to find project path.'));

// And fix it.
if (callback(null, project)) {
console.log('Saving project file.');
fs.writeFileSync(projectPath, project.writeSync());
}
const project = xcode.project(filePath);
project.parseSync();

// And fix it.
if (callback(null, project)) {
fs.writeFileSync(filePath, project.writeSync());
}
});
},
generateUuid () {
return uuid.v4().replace(/-/g, '').substr(0, 24).toUpperCase();
updatePlistsMatchingGlob (pattern, callback) {
this.getFilesMatchingGlob(pattern, (err, filePath) => {
if (!filePath) return callback(new Error('Unable to find plist path.'));

const file = plist.parse(fs.readFileSync(filePath, 'utf8'));

// And fix it.
if (callback(null, file, filePath)) {
fs.writeFileSync(filePath, plist.build(file));
}
});
},
getMappings () {
const project = this.getClosestLikelyReactNativeProjectPath();
Expand Down
20 changes: 16 additions & 4 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,10 @@ base64-js@0.0.8:
version "0.0.8"
resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-0.0.8.tgz#1101e9544f4a76b1bc3b26d452ca96d7a35e7978"

base64-js@1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.1.2.tgz#d6400cac1c4c660976d90d07a04351d89395f5e8"

bplist-creator@0.0.4:
version "0.0.4"
resolved "https://registry.yarnpkg.com/bplist-creator/-/bplist-creator-0.0.4.tgz#4ac0496782e127a85c1d2026a4f5eb22a7aff991"
Expand Down Expand Up @@ -844,6 +848,14 @@ plist@1.2.0:
xmlbuilder "4.0.0"
xmldom "0.1.x"

plist@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/plist/-/plist-2.0.1.tgz#0a32ca9481b1c364e92e18dc55c876de9d01da8b"
dependencies:
base64-js "1.1.2"
xmlbuilder "8.2.2"
xmldom "0.1.x"

pluralize@^1.2.1:
version "1.2.1"
resolved "https://registry.yarnpkg.com/pluralize/-/pluralize-1.2.1.tgz#d1a21483fd22bb41e58a12fa3421823140897c45"
Expand Down Expand Up @@ -1093,10 +1105,6 @@ util@^0.10.3:
dependencies:
inherits "2.0.1"

uuid@^3.0.1:
version "3.0.1"
resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.0.1.tgz#6544bba2dfda8c1cf17e629a3a305e2bb1fee6c1"

validate-npm-package-license@^3.0.1:
version "3.0.1"
resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.1.tgz#2804babe712ad3379459acfbe24746ab2c303fbc"
Expand Down Expand Up @@ -1143,6 +1151,10 @@ xmlbuilder@4.0.0:
dependencies:
lodash "^3.5.0"

xmlbuilder@8.2.2:
version "8.2.2"
resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-8.2.2.tgz#69248673410b4ba42e1a6136551d2922335aa773"

xmldom@0.1.x:
version "0.1.27"
resolved "https://registry.yarnpkg.com/xmldom/-/xmldom-0.1.27.tgz#d501f97b3bdb403af8ef9ecc20573187aadac0e9"
Expand Down

0 comments on commit 5fab200

Please sign in to comment.