@bacons/apple-targets
Version:
Generate Apple Targets with Expo Prebuild
124 lines (123 loc) • 6.23 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.resolveEntitlementsForCodeSign = exports.getEntitlementsConflictMessage = exports.classifySourceEntitlementsFile = exports.writeGeneratedEntitlements = exports.getGeneratedEntitlementsCodeSignPath = exports.getGeneratedEntitlementsPath = exports.getGeneratedEntitlementsDir = exports.GENERATED_ENTITLEMENTS_FILE_NAME = void 0;
const plist_1 = __importDefault(require("@expo/plist"));
const fs_1 = __importDefault(require("fs"));
const path_1 = __importDefault(require("path"));
const target_1 = require("./target");
/**
* File name used for entitlements generated from the `entitlements` object in
* `expo-target.config`. The `generated` prefix signals the file is derived and
* should not be hand-edited.
*/
exports.GENERATED_ENTITLEMENTS_FILE_NAME = "generated.entitlements";
/**
* Absolute path to the directory that holds a target's generated entitlements,
* e.g. `<projectRoot>/ios/.targets/<productName>/`.
*/
function getGeneratedEntitlementsDir(projectRoot, productName) {
return path_1.default.join(projectRoot, "ios", target_1.TARGET_GENERATED_DIR, productName);
}
exports.getGeneratedEntitlementsDir = getGeneratedEntitlementsDir;
/**
* Absolute path to a target's generated entitlements file, e.g.
* `<projectRoot>/ios/.targets/<productName>/generated.entitlements`.
*/
function getGeneratedEntitlementsPath(projectRoot, productName) {
return path_1.default.join(getGeneratedEntitlementsDir(projectRoot, productName), exports.GENERATED_ENTITLEMENTS_FILE_NAME);
}
exports.getGeneratedEntitlementsPath = getGeneratedEntitlementsPath;
/**
* Value for the `CODE_SIGN_ENTITLEMENTS` build setting pointing at a generated
* entitlements file. The path is resolved by Xcode relative to the `ios/`
* project root, e.g. `.targets/<productName>/generated.entitlements`.
*/
function getGeneratedEntitlementsCodeSignPath(productName) {
return `${target_1.TARGET_GENERATED_DIR}/${productName}/${exports.GENERATED_ENTITLEMENTS_FILE_NAME}`;
}
exports.getGeneratedEntitlementsCodeSignPath = getGeneratedEntitlementsCodeSignPath;
/**
* Write a target's entitlements to its generated location, creating parent
* directories as needed. Returns the absolute path of the written file.
*
* This is the single place a generated entitlements file is created — it always
* writes under `ios/<TARGET_GENERATED_DIR>/` and never into the target's source
* directory, keeping derived artifacts out of version control.
*/
function writeGeneratedEntitlements(projectRoot, productName, entitlements) {
const dir = getGeneratedEntitlementsDir(projectRoot, productName);
const file = getGeneratedEntitlementsPath(projectRoot, productName);
fs_1.default.mkdirSync(dir, { recursive: true });
fs_1.default.writeFileSync(file, plist_1.default.build(entitlements));
return file;
}
exports.writeGeneratedEntitlements = writeGeneratedEntitlements;
function classifySourceEntitlementsFile(filePath) {
return path_1.default.basename(filePath) === exports.GENERATED_ENTITLEMENTS_FILE_NAME
? "stale-generated"
: "handwritten";
}
exports.classifySourceEntitlementsFile = classifySourceEntitlementsFile;
/**
* Warning shown when a target has BOTH a `generated.entitlements` file in its
* source folder (written by an older version of this plugin) AND an
* `entitlements` object in `expo-target.config`. The two are an ambiguous,
* conflicting source of truth. This is non-fatal — the config object wins and
* the file is generated under `ios/` — but the user should remove one of the
* two to resolve the ambiguity.
*
* @param entitlementsFileRelativePath project-root-relative path to the source
* `generated.entitlements` file, e.g. `targets/clip/generated.entitlements`.
* @param configRelativePath project-root-relative path to the target config,
* e.g. `targets/clip/expo-target.config.js`.
*/
function getEntitlementsConflictMessage(entitlementsFileRelativePath, configRelativePath) {
return `Ignoring ${entitlementsFileRelativePath} in favor of entitlements object in ${configRelativePath}. Either delete the generated file or remove the entitlements object to continue.`;
}
exports.getEntitlementsConflictMessage = getEntitlementsConflictMessage;
/**
* Resolve which entitlements file should drive `CODE_SIGN_ENTITLEMENTS` for a
* target, with a deterministic precedence:
*
* 1. A generated entitlements file under `ios/<TARGET_GENERATED_DIR>/` (written
* when the config defines an `entitlements` object) always wins.
* 2. Otherwise, a hand-written `*.entitlements` file in the target's source
* folder is used.
* 3. If neither exists, returns `null` and the caller removes the setting.
*/
function resolveEntitlementsForCodeSign({ projectRoot, productName, cwd, }) {
const generatedAbsolutePath = getGeneratedEntitlementsPath(projectRoot, productName);
if (fs_1.default.existsSync(generatedAbsolutePath)) {
return {
absolutePath: generatedAbsolutePath,
codeSignEntitlements: getGeneratedEntitlementsCodeSignPath(productName),
};
}
const sourceCwd = path_1.default.join(projectRoot, "ios", cwd);
const sourceEntitlements = findSourceEntitlementsFiles(sourceCwd);
if (sourceEntitlements.length > 0) {
return {
absolutePath: path_1.default.join(sourceCwd, sourceEntitlements[0]),
codeSignEntitlements: `${cwd}/${sourceEntitlements[0]}`,
};
}
return null;
}
exports.resolveEntitlementsForCodeSign = resolveEntitlementsForCodeSign;
/**
* List the `*.entitlements` files directly inside a target's source folder,
* sorted for deterministic ordering. Non-recursive, mirroring the `*.glob` used
* elsewhere — there should normally be at most one.
*/
function findSourceEntitlementsFiles(sourceCwd) {
if (!fs_1.default.existsSync(sourceCwd)) {
return [];
}
return fs_1.default
.readdirSync(sourceCwd)
.filter((name) => name.endsWith(".entitlements"))
.sort();
}