@sentry/wizard
Version:
Sentry wizard helping you to configure your project
182 lines • 7.08 kB
JavaScript
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.getMainActivity = exports.addManifestSnippet = void 0;
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
const fs = __importStar(require("fs"));
// @ts-expect-error - clack is ESM and TS complains about that. It works though
const clack = __importStar(require("@clack/prompts"));
const Sentry = __importStar(require("@sentry/node"));
const templates_1 = require("./templates");
const xml_js_1 = __importDefault(require("xml-js"));
const chalk_1 = __importDefault(require("chalk"));
/**
* Looks for the closing </application> tag in the manifest and adds the Sentry config after it.
*
* For example:
* ```xml
* <manifest xmlns:android="http://schemas.android.com/apk/res/android"
* xmlns:tools="http://schemas.android.com/tools">
*
* <application>
* ...
* // this is what we add and more
* <meta-data android:name="io.sentry.dsn" android:value="__dsn__" />
* </application> <!-- we are looking for this one
* </manifest>
* ```
*
* @param manifestFile the path to the main AndroidManifest.xml file
* @param dsn
* @returns true if successfully patched the manifest, false otherwise
*/
function addManifestSnippet(manifestFile, dsn, enableLogs) {
if (!fs.existsSync(manifestFile)) {
clack.log.warn('AndroidManifest.xml not found.');
Sentry.captureException('No AndroidManifest file');
return false;
}
const manifestContent = fs.readFileSync(manifestFile, 'utf8');
if (/android:name="io\.sentry[^"]*"/i.test(manifestContent)) {
// sentry is already configured
clack.log.success(chalk_1.default.greenBright('Sentry SDK is already configured.'));
return true;
}
const applicationMatch = /<\/application>/i.exec(manifestContent);
if (!applicationMatch) {
clack.log.warn('<application> tag not found within the manifest.');
Sentry.captureException('No <application> tag');
return false;
}
const insertionIndex = applicationMatch.index;
const newContent = manifestContent.slice(0, insertionIndex) +
(0, templates_1.manifest)(dsn, enableLogs) +
manifestContent.slice(insertionIndex);
fs.writeFileSync(manifestFile, newContent, 'utf8');
clack.log.success(chalk_1.default.greenBright(`Updated ${chalk_1.default.bold('AndroidManifest.xml')} with the Sentry SDK configuration.`));
return true;
}
exports.addManifestSnippet = addManifestSnippet;
/**
* There might be multiple <activity> in the manifest, as well as multiple <activity-alias> with category LAUNCHER,
* but only one main activity with action MAIN. We are looking for this one by parsing xml and walking it.
*
* In addition, older Android versions required to specify the packag name in the manifest,
* while the new ones - in the Gradle config. So we are just sanity checking if the package name
* is in the manifest and returning it as well.
*
* For example:
*
* ```xml
* <manifest xmlns:android="http://schemas.android.com/apk/res/android"
* xmlns:tools="http://schemas.android.com/tools"
* package="com.example.sample">
*
* <application>
* <activity
* android:name="ui.MainActivity"
* ...other props>
* <intent-filter>
* <action android:name="android.intent.action.MAIN" /> <!-- we are looking for this one
*
* <category android:name="android.intent.category.LAUNCHER" />
* </intent-filter>
* </activity>
* </application>
* </manifest>
* ```
*
* @param manifestFile path to the AndroidManifest.xml file
* @returns package name (if available in the manifest) + the main activity name
*/
function getMainActivity(manifestFile) {
if (!fs.existsSync(manifestFile)) {
clack.log.warn('AndroidManifest.xml not found.');
Sentry.captureException('No AndroidManifest file');
return {};
}
const manifestContent = fs.readFileSync(manifestFile, 'utf8');
const converted = xml_js_1.default.xml2js(manifestContent, {
compact: true,
});
const activities = converted.manifest?.application?.activity;
const packageName = converted.manifest?._attributes?.['package'];
if (!activities) {
clack.log.warn('No activity found in AndroidManifest.');
Sentry.captureException('No Activity');
return {};
}
let mainActivity;
if (Array.isArray(activities)) {
const withIntentFilter = activities.filter((a) => !!a['intent-filter']);
mainActivity = withIntentFilter.find((a) => isMainActivity(a));
}
else if (isMainActivity(activities)) {
mainActivity = activities;
}
if (!mainActivity) {
clack.log.warn('No main activity found in AndroidManifest.');
Sentry.captureException('No Main Activity');
return {};
}
const attrs = mainActivity._attributes;
const activityName = attrs?.['android:name'];
return { packageName: packageName, activityName: activityName };
}
exports.getMainActivity = getMainActivity;
function isMainActivity(activity) {
const intentFilters = activity['intent-filter'];
if (Array.isArray(intentFilters)) {
return intentFilters.some((i) => {
const action = i.action;
return hasMainAction(action);
});
}
else {
const action = intentFilters.action;
return hasMainAction(action);
}
}
function hasMainAction(action) {
if (!action) {
return false;
}
function isMain(attrs) {
return attrs?.['android:name'] === 'android.intent.action.MAIN';
}
if (Array.isArray(action)) {
return action.some((c) => {
return isMain(c._attributes);
});
}
else {
return isMain(action._attributes);
}
}
//# sourceMappingURL=manifest.js.map
;