Files
SwimBuddy/scripts/add-sentry-watch.js
T

158 lines
5.7 KiB
JavaScript

#!/usr/bin/env node
/**
* Post-prebuild script: adds SentrySPM Swift Package to the watch target.
*
* Run after `expo prebuild`:
* node scripts/add-sentry-watch.js
*/
const fs = require("fs");
const path = require("path");
const SENTRY_REPO_URL = "https://github.com/getsentry/sentry-cocoa.git";
const SENTRY_MIN_VERSION = "9.25.0";
const SENTRY_PRODUCT = "Sentry";
function genUuid() {
const hex = "0123456789ABCDEF";
let id = "";
for (let i = 0; i < 24; i++) id += hex[Math.floor(Math.random() * 16)];
return id;
}
const projectRoot = path.resolve(__dirname, "..");
const pbxprojPath = path.join(
projectRoot,
"ios",
"SwimBuddy.xcodeproj",
"project.pbxproj"
);
if (!fs.existsSync(pbxprojPath)) {
console.error("project.pbxproj not found. Run expo prebuild first.");
process.exit(1);
}
let content = fs.readFileSync(pbxprojPath, "utf-8");
// Already added?
if (content.includes(SENTRY_REPO_URL)) {
console.log("SentrySPM already present.");
process.exit(0);
}
// ── Find watch target UUID ──
const watchTargetMatch = content.match(
/(\w{24})\s*\/\* SwimBuddy \*\/\s*=\s*\{\s*\n\s*isa = PBXNativeTarget;\s*\n\s*buildConfigurationList = XX792EB48D81CD7C6C71DCXX/
);
if (!watchTargetMatch) {
console.error("Watch target not found");
process.exit(1);
}
const watchTargetUuid = watchTargetMatch[1];
console.log(`Watch target: ${watchTargetUuid}`);
// ── Find watch target's Frameworks build phase UUID ──
const watchTargetBlock = content.match(
new RegExp(
`${watchTargetUuid}\\s*\\/\\* SwimBuddy \\*\\/\\s*=\\s*\\{[\\s\\S]*?buildPhases\\s*=\\s*\\(([\\s\\S]*?)\\);`
)
);
if (!watchTargetBlock) {
console.error("Cannot parse watch target buildPhases");
process.exit(1);
}
const fwPhaseMatch = watchTargetBlock[1].match(/(\w{24})\s*\/\* Frameworks \*\//);
if (!fwPhaseMatch) {
console.error("Watch Frameworks phase not found");
process.exit(1);
}
const watchFwPhaseId = fwPhaseMatch[1];
console.log(`Watch Frameworks phase: ${watchFwPhaseId}`);
// ── Generate UUIDs ──
const pkgRefId = genUuid();
const prodDepId = genUuid();
const buildFileId = genUuid();
// ── 1. PBXBuildFile (single-line format) ──
const buildFileLine = `\t\t${buildFileId} /* ${SENTRY_PRODUCT} in Frameworks */ = {isa = PBXBuildFile; productRef = ${prodDepId} /* ${SENTRY_PRODUCT} */; };`;
content = content.replace(
/\/\* End PBXBuildFile section \*\//,
`${buildFileLine}\n/* End PBXBuildFile section */`
);
// ── 2. XCRemoteSwiftPackageReference section ──
const pkgRefLine = `\t\t${pkgRefId} /* XCRemoteSwiftPackageReference "sentry-cocoa" */ = {isa = XCRemoteSwiftPackageReference; repositoryURL = "${SENTRY_REPO_URL}"; requirement = {kind = "upToNextMajorVersion"; minimumVersion = "${SENTRY_MIN_VERSION}"; }; };`;
if (!content.includes("/* Begin XCRemoteSwiftPackageReference section */")) {
content = content.replace(
/\/\* End PBXProject section \*\//,
`/* Begin XCRemoteSwiftPackageReference section */\n${pkgRefLine}\n/* End XCRemoteSwiftPackageReference section */\n/* End PBXProject section */`
);
} else {
content = content.replace(
/\/\* End XCRemoteSwiftPackageReference section \*\//,
`${pkgRefLine}\n/* End XCRemoteSwiftPackageReference section */`
);
}
// ── 3. XCSwiftPackageProductDependency section ──
const prodDepLine = `\t\t${prodDepId} /* ${SENTRY_PRODUCT} */ = {isa = XCSwiftPackageProductDependency; package = ${pkgRefId} /* XCRemoteSwiftPackageReference "sentry-cocoa" */; productName = ${SENTRY_PRODUCT}; };`;
if (!content.includes("/* Begin XCSwiftPackageProductDependency section */")) {
content = content.replace(
/\/\* End XCRemoteSwiftPackageReference section \*\//,
`/* Begin XCSwiftPackageProductDependency section */\n${prodDepLine}\n/* End XCSwiftPackageProductDependency section */\n/* End XCRemoteSwiftPackageReference section */`
);
} else {
content = content.replace(
/\/\* End XCSwiftPackageProductDependency section \*\//,
`${prodDepLine}\n/* End XCSwiftPackageProductDependency section */`
);
}
// ── 4. Add to watch Frameworks build phase ──
const fwPhasePattern = new RegExp(
`(${watchFwPhaseId}\\s*\\/\\* Frameworks \\*\\/ = \\{[\\s\\S]*?files = \\()[\\s\\S]*?(\\);[\\s\\S]*?runOnlyForDeploymentPostprocessing)`
);
const fwMatch = content.match(fwPhasePattern);
if (fwMatch) {
const insertLine = `\n\t\t\t\t${buildFileId} /* ${SENTRY_PRODUCT} in Frameworks */,`;
content = content.replace(fwPhasePattern, `$1${fwMatch[0].includes(buildFileId) ? "" : insertLine}$2`);
} else {
console.error("Cannot insert into watch Frameworks build phase");
process.exit(1);
}
// ── 5. packageReferences in PBXProject ──
const pkgRefComment = `${pkgRefId} /* XCRemoteSwiftPackageReference "sentry-cocoa" */`;
if (!content.includes("packageReferences = (")) {
content = content.replace(
/(targets\s*=\s*\([^)]*\);)/,
`$1\n\t\t\tpackageReferences = (\n\t\t\t\t${pkgRefComment},\n\t\t\t);`
);
} else {
content = content.replace(
/(packageReferences\s*=\s*\()/,
`$1\n\t\t\t\t${pkgRefComment},`
);
}
// ── 6. packageProductDependencies on watch target ──
const prodDepComment = `${prodDepId} /* ${SENTRY_PRODUCT} */`;
// Find the watch target block and check if packageProductDependencies exists
const wtPattern = new RegExp(
`(${watchTargetUuid}\\s*\\/\\* SwimBuddy \\*\\/ = \\{[\\s\\S]*?fileSystemSynchronizedGroups = \\([\\s\\S]*?\\);[\\s\\S]*?)(name = )`
);
const wtMatch = content.match(wtPattern);
if (wtMatch && !content.includes("packageProductDependencies")) {
content = content.replace(
wtPattern,
`$1\n\t\t\tpackageProductDependencies = (\n\t\t\t\t${prodDepComment},\n\t\t\t);\n\t\t$2`
);
}
fs.writeFileSync(pbxprojPath, content);
console.log("SentrySPM added to watch target successfully.");