initial commit taken from gitlab.lrz.de

This commit is contained in:
privatereese
2018-08-24 18:09:42 +02:00
parent ae54ed4c48
commit fc05486403
28494 changed files with 2159823 additions and 0 deletions

View File

@@ -0,0 +1,21 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
const PbxFile = require('xcode/lib/pbxFile');
/**
* Given xcodeproj and filePath, it creates new file
* from path provided, adds it to the project
* and returns newly created instance of a file
*/
module.exports = function addFileToProject(project, filePath) {
const file = new PbxFile(filePath);
file.uuid = project.generateUuid();
file.fileRef = project.generateUuid();
project.addToPbxFileReferenceSection(file);
return file;
};

View File

@@ -0,0 +1,20 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
/**
* Given an array of xcodeproj libraries and pbxFile,
* it appends it to that group
*
* Important: That function mutates `libraries` and it's not pure.
* It's mainly due to limitations of `xcode` library.
*/
module.exports = function addProjectToLibraries(libraries, file) {
return libraries.children.push({
value: file.fileRef,
comment: file.basename,
});
};

View File

@@ -0,0 +1,23 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
const createGroupWithMessage = require('./createGroupWithMessage');
module.exports = function addSharedLibraries(project, libraries) {
if (!libraries.length) {
return;
}
// Create a Frameworks group if necessary.
createGroupWithMessage(project, 'Frameworks');
const target = project.getFirstTarget().uuid;
for (var name of libraries) {
project.addFramework(name, { target });
}
};

View File

@@ -0,0 +1,12 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
const mapHeaderSearchPaths = require('./mapHeaderSearchPaths');
module.exports = function addToHeaderSearchPaths(project, path) {
mapHeaderSearchPaths(project, searchPaths => searchPaths.concat(path));
};

View File

@@ -0,0 +1,6 @@
const isInstalledIOS = require('../isInstalled');
const isInstalledPods = require('../../pods/isInstalled');
module.exports = function isInstalled(projectConfig, name, dependencyConfig) {
return isInstalledIOS(projectConfig, dependencyConfig) || isInstalledPods(projectConfig, dependencyConfig);
};

View File

@@ -0,0 +1,16 @@
const registerDependencyIOS = require('../registerNativeModule');
const registerDependencyPods = require('../../pods/registerNativeModule');
module.exports = function registerNativeModule(
name,
dependencyConfig,
params,
projectConfig
) {
if (projectConfig.podfile && dependencyConfig.podspec) {
registerDependencyPods(name, dependencyConfig, projectConfig);
}
else {
registerDependencyIOS(dependencyConfig, projectConfig);
}
};

View File

@@ -0,0 +1,22 @@
const compact = require('lodash').compact;
const isInstalledIOS = require('../isInstalled');
const isInstalledPods = require('../../pods/isInstalled');
const unregisterDependencyIOS = require('../unregisterNativeModule');
const unregisterDependencyPods = require('../../pods/unregisterNativeModule');
module.exports = function unregisterNativeModule(
name,
dependencyConfig,
projectConfig,
otherDependencies
) {
const isIosInstalled = isInstalledIOS(projectConfig, dependencyConfig);
const isPodInstalled = isInstalledPods(projectConfig, dependencyConfig);
if (isIosInstalled) {
const iOSDependencies = compact(otherDependencies.map(d => d.config.ios));
unregisterDependencyIOS(dependencyConfig, projectConfig, iOSDependencies);
}
else if (isPodInstalled) {
unregisterDependencyPods(dependencyConfig, projectConfig);
}
};

View File

@@ -0,0 +1,54 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
const fs = require('fs-extra');
const path = require('path');
const xcode = require('xcode');
const log = require('npmlog');
const groupFilesByType = require('../groupFilesByType');
const createGroupWithMessage = require('./createGroupWithMessage');
const getPlist = require('./getPlist');
const writePlist = require('./writePlist');
/**
* This function works in a similar manner to its Android version,
* except it does not copy fonts but creates Xcode Group references
*/
module.exports = function linkAssetsIOS(files, projectConfig) {
const project = xcode.project(projectConfig.pbxprojPath).parseSync();
const assets = groupFilesByType(files);
const plist = getPlist(project, projectConfig.sourceDir);
createGroupWithMessage(project, 'Resources');
function addResourceFile(f) {
return (f || [])
.map(asset =>
project.addResourceFile(
path.relative(projectConfig.sourceDir, asset),
{ target: project.getFirstTarget().uuid }
)
)
.filter(file => file) // xcode returns false if file is already there
.map(file => file.basename);
}
addResourceFile(assets.image);
const fonts = addResourceFile(assets.font);
const existingFonts = (plist.UIAppFonts || []);
const allFonts = [...existingFonts, ...fonts];
plist.UIAppFonts = Array.from(new Set(allFonts)); // use Set to dedupe w/existing
fs.writeFileSync(
projectConfig.pbxprojPath,
project.writeSync()
);
writePlist(project, projectConfig.sourceDir, plist);
};

View File

@@ -0,0 +1,34 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
const getGroup = require('./getGroup');
const hasGroup = (pbxGroup, name) => pbxGroup.children.find(group => group.comment === name);
/**
* Given project and path of the group, it deeply creates a given group
* making all outer groups if necessary
*
* Returns newly created group
*/
module.exports = function createGroup(project, path) {
return path.split('/').reduce(
(group, name) => {
if (!hasGroup(group, name)) {
const uuid = project.pbxCreateGroup(name, '""');
group.children.push({
value: uuid,
comment: name,
});
}
return project.pbxGroupByName(name);
},
getGroup(project)
);
};

View File

@@ -0,0 +1,32 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
const log = require('npmlog');
const createGroup = require('./createGroup');
const getGroup = require('./getGroup');
/**
* Given project and path of the group, it checks if a group exists at that path,
* and deeply creates a group for that path if its does not already exist.
*
* Returns the existing or newly created group
*/
module.exports = function createGroupWithMessage(project, path) {
var group = getGroup(project, path);
if (!group) {
group = createGroup(project, path);
log.warn(
'ERRGROUP',
`Group '${path}' does not exist in your Xcode project. We have created it automatically for you.`
);
}
return group;
};

View File

@@ -0,0 +1,25 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
/**
* Gets build property from the main target build section
*
* It differs from the project.getBuildProperty exposed by xcode in the way that:
* - it only checks for build property in the main target `Debug` section
* - `xcode` library iterates over all build sections and because it misses
* an early return when property is found, it will return undefined/wrong value
* when there's another build section typically after the one you want to access
* without the property defined (e.g. CocoaPods sections appended to project
* miss INFOPLIST_FILE), see: https://github.com/alunny/node-xcode/blob/master/lib/pbxProject.js#L1765
*/
module.exports = function getBuildProperty(project, prop) {
const target = project.getFirstTarget().firstTarget;
const config = project.pbxXCConfigurationList()[target.buildConfigurationList];
const buildSection = project.pbxXCBuildConfigurationSection()[config.buildConfigurations[0].value];
return buildSection.buildSettings[prop];
};

View File

@@ -0,0 +1,41 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
const getFirstProject = (project) => project.getFirstProject().firstProject;
const findGroup = (group, name) => group.children.find(group => group.comment === name);
/**
* Returns group from .xcodeproj if one exists, null otherwise
*
* Unlike node-xcode `pbxGroupByName` - it does not return `first-matching`
* group if multiple groups with the same name exist
*
* If path is not provided, it returns top-level group
*/
module.exports = function getGroup(project, path) {
const firstProject = getFirstProject(project);
var group = project.getPBXGroupByKey(firstProject.mainGroup);
if (!path) {
return group;
}
for (var name of path.split('/')) {
var foundGroup = findGroup(group, name);
if (foundGroup) {
group = project.getPBXGroupByKey(foundGroup.value);
} else {
group = null;
break;
}
}
return group;
};

View File

@@ -0,0 +1,59 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
const path = require('path');
const union = require('lodash').union;
const last = require('lodash').last;
/**
* Given an array of directories, it returns the one that contains
* all the other directories in a given array inside it.
*
* Example:
* Given an array of directories: ['/Users/Kureev/a', '/Users/Kureev/b']
* the returned folder is `/Users/Kureev`
*
* Check `getHeaderSearchPath.spec.js` for more use-cases.
*/
const getOuterDirectory = (directories) =>
directories.reduce((topDir, currentDir) => {
const currentFolders = currentDir.split(path.sep);
const topMostFolders = topDir.split(path.sep);
if (currentFolders.length === topMostFolders.length
&& last(currentFolders) !== last(topMostFolders)) {
return currentFolders.slice(0, -1).join(path.sep);
}
return currentFolders.length < topMostFolders.length
? currentDir
: topDir;
});
/**
* Given an array of headers it returns search path so Xcode can resolve
* headers when referenced like below:
* ```
* #import "CodePush.h"
* ```
* If all files are located in one directory (directories.length === 1),
* we simply return a relative path to that location.
*
* Otherwise, we loop through them all to find the outer one that contains
* all the headers inside. That location is then returned with /** appended at
* the end so Xcode marks that location as `recursive` and will look inside
* every folder of it to locate correct headers.
*/
module.exports = function getHeaderSearchPath(sourceDir, headers) {
const directories = union(
headers.map(path.dirname)
);
return directories.length === 1
? `"$(SRCROOT)${path.sep}${path.relative(sourceDir, directories[0])}"`
: `"$(SRCROOT)${path.sep}${path.relative(sourceDir, getOuterDirectory(directories))}/**"`;
};

View File

@@ -0,0 +1,25 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
const glob = require('glob');
const path = require('path');
const GLOB_EXCLUDE_PATTERN = ['node_modules/**', 'Pods/**', 'Examples/**', 'examples/**'];
/**
* Given folder, it returns an array of all header files
* inside it, ignoring node_modules and examples
*/
module.exports = function getHeadersInFolder(folder) {
return glob
.sync('**/*.h', {
cwd: folder,
nodir: true,
ignore: GLOB_EXCLUDE_PATTERN,
})
.map(file => path.join(folder, file));
};

View File

@@ -0,0 +1,27 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
const plistParser = require('plist');
const getPlistPath = require('./getPlistPath');
const fs = require('fs');
/**
* Returns Info.plist located in the iOS project
*
* Returns `null` if INFOPLIST_FILE is not specified.
*/
module.exports = function getPlist(project, sourceDir) {
const plistPath = getPlistPath(project, sourceDir);
if (!plistPath || !fs.existsSync(plistPath)) {
return null;
}
return plistParser.parse(
fs.readFileSync(plistPath, 'utf-8')
);
};

View File

@@ -0,0 +1,22 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
const path = require('path');
const getBuildProperty = require('./getBuildProperty');
module.exports = function getPlistPath(project, sourceDir) {
const plistFile = getBuildProperty(project, 'INFOPLIST_FILE');
if (!plistFile) {
return null;
}
return path.join(
sourceDir,
plistFile.replace(/"/g, '').replace('$(SRCROOT)', '')
);
};

View File

@@ -0,0 +1,19 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
/**
* Given xcodeproj it returns list of products ending with
* .a extension, so that we know what elements add to target
* project static library
*/
module.exports = function getProducts(project) {
return project
.pbxGroupByName('Products')
.children
.map(c => c.comment)
.filter(c => c.indexOf('.a') > -1);
};

View File

@@ -0,0 +1,27 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
/**
* Given xcodeproj it returns list of targets
*/
module.exports = function getTargets(project) {
let targets = project.getFirstProject().firstProject.targets;
let nativeTargetSection = project.pbxNativeTargetSection();
return targets.map(function(target) {
let key = target.value;
let configurationListId = project.pbxNativeTargetSection()[key].buildConfigurationList;
let configurationList = project.pbxXCConfigurationList()[configurationListId];
let buildConfigurationId = configurationList.buildConfigurations[0].value;
let buildConfiguration = project.pbxXCBuildConfigurationSection()[buildConfigurationId];
return {
uuid: key,
target: nativeTargetSection[key],
name: nativeTargetSection[key].productReference_comment,
isTVOS: (buildConfiguration.buildSettings.SDKROOT && (buildConfiguration.buildSettings.SDKROOT.indexOf('appletv') !== -1)) || false
};
});
};

View File

@@ -0,0 +1,17 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
/**
* Given an array of libraries already imported and packageName that will be
* added, returns true or false depending on whether the library is already linked
* or not
*/
module.exports = function hasLibraryImported(libraries, packageName) {
return libraries.children
.filter(library => library.comment === packageName)
.length > 0;
};

View File

@@ -0,0 +1,9 @@
module.exports = function() {
return {
isInstalled: require('./common/isInstalled'),
register: require('./common/registerNativeModule'),
unregister: require('./common/unregisterNativeModule'),
copyAssets: require('./copyAssets'),
unlinkAssets: require('./unlinkAssets')
};
};

View File

@@ -0,0 +1,25 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
const xcode = require('xcode');
const getGroup = require('./getGroup');
const hasLibraryImported = require('./hasLibraryImported');
/**
* Returns true if `xcodeproj` specified by dependencyConfig is present
* in a top level `libraryFolder`
*/
module.exports = function isInstalled(projectConfig, dependencyConfig) {
const project = xcode.project(projectConfig.pbxprojPath).parseSync();
const libraries = getGroup(project, projectConfig.libraryFolder);
if (!libraries) {
return false;
}
return hasLibraryImported(libraries, dependencyConfig.projectName);
};

View File

@@ -0,0 +1,48 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
/**
* Given Xcode project and path, iterate over all build configurations
* and execute func with HEADER_SEARCH_PATHS from current section
*
* We cannot use builtin addToHeaderSearchPaths method since react-native init does not
* use $(TARGET_NAME) for PRODUCT_NAME, but sets it manually so that method will skip
* that target.
*
* To workaround that issue and make it more bullet-proof for different names,
* we iterate over all configurations and look for `lc++` linker flag to detect
* React Native target.
*
* Important: That function mutates `buildSettings` and it's not pure thus you should
* not rely on its return value
*/
const defaultHeaderPaths = ['"$(inherited)"'];
module.exports = function headerSearchPathIter(project, func) {
const config = project.pbxXCBuildConfigurationSection();
Object
.keys(config)
.filter(ref => ref.indexOf('_comment') === -1)
.forEach(ref => {
const buildSettings = config[ref].buildSettings;
const shouldVisitBuildSettings = (
Array.isArray(buildSettings.OTHER_LDFLAGS) ?
buildSettings.OTHER_LDFLAGS :
[]
)
.indexOf('"-lc++"') >= 0;
if (shouldVisitBuildSettings) {
const searchPaths = buildSettings.HEADER_SEARCH_PATHS ?
[].concat(buildSettings.HEADER_SEARCH_PATHS) :
defaultHeaderPaths;
buildSettings.HEADER_SEARCH_PATHS = func(searchPaths);
}
});
};

View File

@@ -0,0 +1,83 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
const xcode = require('xcode');
const fs = require('fs');
const path = require('path');
const log = require('npmlog');
const addToHeaderSearchPaths = require('./addToHeaderSearchPaths');
const getHeadersInFolder = require('./getHeadersInFolder');
const getHeaderSearchPath = require('./getHeaderSearchPath');
const getProducts = require('./getProducts');
const getTargets = require('./getTargets');
const createGroupWithMessage = require('./createGroupWithMessage');
const addFileToProject = require('./addFileToProject');
const addProjectToLibraries = require('./addProjectToLibraries');
const addSharedLibraries = require('./addSharedLibraries');
const isEmpty = require('lodash').isEmpty;
const getGroup = require('./getGroup');
/**
* Register native module IOS adds given dependency to project by adding
* its xcodeproj to project libraries as well as attaching static library
* to the first target (the main one)
*
* If library is already linked, this action is a no-op.
*/
module.exports = function registerNativeModuleIOS(dependencyConfig, projectConfig) {
const project = xcode.project(projectConfig.pbxprojPath).parseSync();
const dependencyProject = xcode.project(dependencyConfig.pbxprojPath).parseSync();
const libraries = createGroupWithMessage(project, projectConfig.libraryFolder);
const file = addFileToProject(
project,
path.relative(projectConfig.sourceDir, dependencyConfig.projectPath)
);
const targets = getTargets(project);
addProjectToLibraries(libraries, file);
getTargets(dependencyProject).forEach(product => {
var i;
if (!product.isTVOS) {
for (i = 0; i < targets.length; i++) {
if (!targets[i].isTVOS) {
project.addStaticLibrary(product.name, {
target: targets[i].uuid
});
}
}
}
if (product.isTVOS) {
for (i = 0; i < targets.length; i++) {
if (targets[i].isTVOS) {
project.addStaticLibrary(product.name, {
target: targets[i].uuid
});
}
}
}
});
addSharedLibraries(project, dependencyConfig.sharedLibraries);
const headers = getHeadersInFolder(dependencyConfig.folder);
if (!isEmpty(headers)) {
addToHeaderSearchPaths(
project,
getHeaderSearchPath(projectConfig.sourceDir, headers)
);
}
fs.writeFileSync(
projectConfig.pbxprojPath,
project.writeSync()
);
};

View File

@@ -0,0 +1,17 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
const mapHeaderSearchPaths = require('./mapHeaderSearchPaths');
/**
* Given Xcode project and absolute path, it makes sure there are no headers referring to it
*/
module.exports = function addToHeaderSearchPaths(project, path) {
mapHeaderSearchPaths(project,
searchPaths => searchPaths.filter(searchPath => searchPath !== path)
);
};

View File

@@ -0,0 +1,23 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
/**
* For all files that are created and referenced from another `.xcodeproj` -
* a new PBXItemContainerProxy is created that contains `containerPortal` value
* which equals to xcodeproj file.uuid from PBXFileReference section.
*/
module.exports = function removeFromPbxItemContainerProxySection(project, file) {
const section = project.hash.project.objects.PBXContainerItemProxy;
for (var key of Object.keys(section)) {
if (section[key].containerPortal === file.uuid) {
delete section[key];
}
}
return;
};

View File

@@ -0,0 +1,22 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
/**
* Every file added to the project from another project is attached to
* `PBXItemContainerProxy` through `PBXReferenceProxy`.
*/
module.exports = function removeFromPbxReferenceProxySection(project, file) {
const section = project.hash.project.objects.PBXReferenceProxy;
for (var key of Object.keys(section)) {
if (section[key].path === file.basename) {
delete section[key];
}
}
return;
};

View File

@@ -0,0 +1,33 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
/**
* For each file (.xcodeproj), there's an entry in `projectReferences` created
* that has two entries - `ProjectRef` - reference to a file.uuid and
* `ProductGroup` - uuid of a Products group.
*
* When projectReference is found - it's deleted and the removed value is returned
* so that ProductGroup in PBXGroup section can be removed as well.
*
* Otherwise returns null
*/
module.exports = function removeFromProjectReferences(project, file) {
const firstProject = project.getFirstProject().firstProject;
const projectRef = firstProject.projectReferences.find(item => item.ProjectRef === file.uuid);
if (!projectRef) {
return null;
}
firstProject.projectReferences.splice(
firstProject.projectReferences.indexOf(projectRef),
1
);
return projectRef;
};

View File

@@ -0,0 +1,28 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
const PbxFile = require('xcode/lib/pbxFile');
const removeFromPbxReferenceProxySection = require('./removeFromPbxReferenceProxySection');
/**
* Removes file from static libraries
*
* Similar to `node-xcode` addStaticLibrary
*/
module.exports = function removeFromStaticLibraries(project, path, opts) {
const file = new PbxFile(path);
file.target = opts ? opts.target : undefined;
project.removeFromPbxFileReferenceSection(file);
project.removeFromPbxBuildFileSection(file);
project.removeFromPbxFrameworksBuildPhase(file);
project.removeFromLibrarySearchPaths(file);
removeFromPbxReferenceProxySection(project, file);
return file;
};

View File

@@ -0,0 +1,18 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
module.exports = function removeProductGroup(project, productGroupId) {
const section = project.hash.project.objects.PBXGroup;
for (var key of Object.keys(section)) {
if (key === productGroupId) {
delete section[key];
}
}
return;
};

View File

@@ -0,0 +1,19 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
/**
* Given an array of xcodeproj libraries and pbxFile,
* it removes it from that group by comparing basenames
*
* Important: That function mutates `libraries` and it's not pure.
* It's mainly due to limitations of `xcode` library.
*/
module.exports = function removeProjectFromLibraries(libraries, file) {
libraries.children = libraries.children.filter(library =>
library.comment !== file.basename
);
};

View File

@@ -0,0 +1,33 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
const PbxFile = require('xcode/lib/pbxFile');
const removeFromPbxItemContainerProxySection = require('./removeFromPbxItemContainerProxySection');
const removeFromProjectReferences = require('./removeFromProjectReferences');
const removeProductGroup = require('./removeProductGroup');
/**
* Given xcodeproj and filePath, it creates new file
* from path provided and removes it. That operation is required since
* underlying method requires PbxFile instance to be passed (it does not
* have to have uuid or fileRef defined since it will do equality check
* by path)
*
* Returns removed file (that one will have UUID)
*/
module.exports = function removeProjectFromProject(project, filePath) {
const file = project.removeFromPbxFileReferenceSection(new PbxFile(filePath));
const projectRef = removeFromProjectReferences(project, file);
if (projectRef) {
removeProductGroup(project, projectRef.ProductGroup);
}
removeFromPbxItemContainerProxySection(project, file);
return file;
};

View File

@@ -0,0 +1,18 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
module.exports = function removeSharedLibraries(project, libraries) {
if (!libraries.length) {
return;
}
const target = project.getFirstTarget().uuid;
for (var name of libraries) {
project.removeFramework(name, { target });
}
};

View File

@@ -0,0 +1,63 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
const fs = require('fs-extra');
const path = require('path');
const xcode = require('xcode');
const log = require('npmlog');
const groupFilesByType = require('../groupFilesByType');
const getPlist = require('./getPlist');
const writePlist = require('./writePlist');
const difference = require('lodash').difference;
/**
* Unlinks assets from iOS project. Removes references for fonts from `Info.plist`
* fonts provided by application and from `Resources` group
*/
module.exports = function unlinkAssetsIOS(files, projectConfig) {
const project = xcode.project(projectConfig.pbxprojPath).parseSync();
const assets = groupFilesByType(files);
const plist = getPlist(project, projectConfig.sourceDir);
if (!plist) {
return log.error(
'ERRPLIST',
'Could not locate Info.plist file. Check if your project has \'INFOPLIST_FILE\' set properly'
);
}
if (!project.pbxGroupByName('Resources')) {
return log.error(
'ERRGROUP',
'Group \'Resources\' does not exist in your Xcode project. There is nothing to unlink.'
);
}
const removeResourceFile = function (f) {
(f || [])
.map(asset =>
project.removeResourceFile(
path.relative(projectConfig.sourceDir, asset),
{ target: project.getFirstTarget().uuid }
)
)
.map(file => file.basename);
};
removeResourceFile(assets.image);
const fonts = removeResourceFile(assets.font);
plist.UIAppFonts = difference(plist.UIAppFonts || [], fonts);
fs.writeFileSync(
projectConfig.pbxprojPath,
project.writeSync()
);
writePlist(project, projectConfig.sourceDir, plist);
};

View File

@@ -0,0 +1,71 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
const xcode = require('xcode');
const path = require('path');
const fs = require('fs');
const difference = require('lodash').difference;
const isEmpty = require('lodash').isEmpty;
const getGroup = require('./getGroup');
const getProducts = require('./getProducts');
const getTargets = require('./getTargets');
const getHeadersInFolder = require('./getHeadersInFolder');
const getHeaderSearchPath = require('./getHeaderSearchPath');
const removeProjectFromProject = require('./removeProjectFromProject');
const removeProjectFromLibraries = require('./removeProjectFromLibraries');
const removeFromStaticLibraries = require('./removeFromStaticLibraries');
const removeFromHeaderSearchPaths = require('./removeFromHeaderSearchPaths');
const removeSharedLibraries = require('./removeSharedLibraries');
/**
* Unregister native module IOS
*
* If library is already unlinked, this action is a no-op.
*/
module.exports = function unregisterNativeModule(dependencyConfig, projectConfig, iOSDependencies) {
const project = xcode.project(projectConfig.pbxprojPath).parseSync();
const dependencyProject = xcode.project(dependencyConfig.pbxprojPath).parseSync();
const libraries = getGroup(project, projectConfig.libraryFolder);
const file = removeProjectFromProject(
project,
path.relative(projectConfig.sourceDir, dependencyConfig.projectPath)
);
removeProjectFromLibraries(libraries, file);
getTargets(dependencyProject).forEach(target => {
removeFromStaticLibraries(project, target.name, {
target: project.getFirstTarget().uuid,
});
});
const sharedLibraries = difference(
dependencyConfig.sharedLibraries,
iOSDependencies.reduce(
(libs, dependency) => libs.concat(dependency.sharedLibraries),
projectConfig.sharedLibraries
)
);
removeSharedLibraries(project, sharedLibraries);
const headers = getHeadersInFolder(dependencyConfig.folder);
if (!isEmpty(headers)) {
removeFromHeaderSearchPaths(
project,
getHeaderSearchPath(projectConfig.sourceDir, headers)
);
}
fs.writeFileSync(
projectConfig.pbxprojPath,
project.writeSync()
);
};

View File

@@ -0,0 +1,31 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
const plistParser = require('plist');
const getPlistPath = require('./getPlistPath');
const fs = require('fs');
/**
* Writes to Info.plist located in the iOS project
*
* Returns `null` if INFOPLIST_FILE is not specified or file is non-existent.
*/
module.exports = function writePlist(project, sourceDir, plist) {
const plistPath = getPlistPath(project, sourceDir);
if (!plistPath) {
return null;
}
// We start with an offset of -1, because Xcode maintains a custom
// indentation of the plist.
// Ref: https://github.com/facebook/react-native/issues/11668
return fs.writeFileSync(
plistPath,
plistParser.build(plist, { indent: '\t', offset: -1 }) + '\n'
);
};