@bugsplat/symbol-upload
Version:
Cross platform symbol upload tool
194 lines • 7.92 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const js_api_client_1 = require("@bugsplat/js-api-client");
const command_line_args_1 = __importDefault(require("command-line-args"));
const command_line_usage_1 = __importDefault(require("command-line-usage"));
const glob_1 = require("glob");
const node_crypto_1 = require("node:crypto");
const node_fs_1 = require("node:fs");
const promises_1 = require("node:fs/promises");
const node_path_1 = require("node:path");
const fs_1 = require("../src/fs");
const info_1 = require("../src/info");
const preload_1 = require("../src/preload");
const sym_1 = require("../src/sym");
const tmp_1 = require("../src/tmp");
const upload_1 = require("../src/upload");
const command_line_definitions_1 = require("./command-line-definitions");
(async () => {
let { help, database, application, version, user, password, clientId, clientSecret, remove, files, directory, dumpSyms, localPath, } = await getCommandLineOptions(command_line_definitions_1.argDefinitions);
if (help) {
logHelpAndExit();
}
database = database ?? process.env.BUGSPLAT_DATABASE;
user = user ?? process.env.SYMBOL_UPLOAD_USER;
password = password ?? process.env.SYMBOL_UPLOAD_PASSWORD;
clientId = clientId ?? process.env.SYMBOL_UPLOAD_CLIENT_ID;
clientSecret = clientSecret ?? process.env.SYMBOL_UPLOAD_CLIENT_SECRET;
if (!database && !localPath) {
logMissingArgAndExit('database');
}
if (!application && !localPath) {
logMissingArgAndExit('application');
}
if (!version && !localPath) {
logMissingArgAndExit('version');
}
if (!localPath &&
!validAuthenticationArguments({
user,
password,
clientId,
clientSecret,
})) {
logMissingAuthAndExit();
}
console.log(`Symbol upload working directory: ${process.cwd()}`);
let bugsplat = null;
if (!localPath) {
console.log('About to authenticate...');
bugsplat = await createBugSplatClient({
user,
password,
clientId,
clientSecret,
});
console.log('Authentication success!');
}
if (remove && bugsplat) {
try {
const versionsApiClient = new js_api_client_1.VersionsApiClient(bugsplat);
console.log(`About to delete symbols for ${database}-${application}-${version}...`);
await versionsApiClient.deleteSymbols(database, application, version);
console.log('Symbols deleted successfully!');
}
catch (error) {
console.error(error);
process.exit(1);
}
finally {
return;
}
}
directory = normalizeDirectory(directory);
if (!(0, node_fs_1.existsSync)(tmp_1.tmpDir)) {
await (0, promises_1.mkdir)(tmp_1.tmpDir);
}
const globPattern = `${directory}/${files}`;
let symbolFilePaths = await (0, glob_1.glob)(globPattern);
if (!symbolFilePaths.length) {
throw new Error(`Could not find any files to upload using glob ${globPattern}!`);
}
console.log(`Found files:\n ${symbolFilePaths.join('\n')}`);
if (dumpSyms) {
let nodeDumpSyms;
try {
nodeDumpSyms = (await (0, preload_1.importNodeDumpSyms)()).dumpSyms;
}
catch (cause) {
throw new Error("Can't import dump_syms! Please ensure node-dump-syms is installed https://github.com/BugSplat-Git/node-dump-syms", { cause });
}
const newSymbolFilePaths = [];
for (const file of symbolFilePaths) {
console.log(`Dumping syms for ${file}...`);
const symFile = (0, node_path_1.join)(tmp_1.tmpDir, (0, node_crypto_1.randomUUID)(), (0, sym_1.getNormalizedSymFileName)((0, node_path_1.basename)(file)));
(0, node_fs_1.mkdirSync)((0, node_path_1.dirname)(symFile), { recursive: true });
try {
nodeDumpSyms(file, symFile);
}
catch (error) {
console.warn(`Failed to dump syms for ${file}: ${error?.message || error}`);
continue;
}
newSymbolFilePaths.push(symFile);
}
symbolFilePaths = newSymbolFilePaths;
}
if (!symbolFilePaths.length) {
throw new Error('No valid symbol files found!');
}
const symbolFileInfos = await Promise.all(symbolFilePaths.map(async (symbolFilePath) => await (0, info_1.createSymbolFileInfos)(symbolFilePath))).then((array) => array.flat());
if (localPath) {
await copyFilesToLocalPath(symbolFileInfos, localPath);
}
if (bugsplat) {
await (0, upload_1.uploadSymbolFiles)(bugsplat, database, application, version, symbolFileInfos);
}
await (0, tmp_1.safeRemoveTmp)();
process.exit(0);
})().catch(async (error) => {
await (0, tmp_1.safeRemoveTmp)();
console.error(error.message);
process.exit(1);
});
async function copyFilesToLocalPath(symbolFileInfos, localPath) {
console.log(`Copying files to ${localPath}...`);
for (const symbolFileInfo of symbolFileInfos) {
if (!symbolFileInfo.dbgId) {
console.warn(`Failed to parse UUID for ${symbolFileInfo.path}, skipping...`);
continue;
}
const localFilePath = (0, node_path_1.join)(localPath, symbolFileInfo.moduleName, symbolFileInfo.dbgId, (0, node_path_1.basename)(symbolFileInfo.path));
(0, node_fs_1.mkdirSync)((0, node_path_1.dirname)(localFilePath), { recursive: true });
await (0, promises_1.copyFile)(symbolFileInfo.path, localFilePath);
}
const symSrvMarkerFilePath = (0, node_path_1.join)(localPath, 'index.txt');
await (0, promises_1.writeFile)(symSrvMarkerFilePath, '.');
}
async function createBugSplatClient({ user, password, clientId, clientSecret, }) {
const host = process.env.BUGSPLAT_HOST;
if (user && password) {
return js_api_client_1.BugSplatApiClient.createAuthenticatedClientForNode(user, password, host);
}
return js_api_client_1.OAuthClientCredentialsClient.createAuthenticatedClient(clientId, clientSecret, host);
}
async function getCommandLineOptions(argDefinitions) {
const options = (0, command_line_args_1.default)(argDefinitions);
let { database, application, version } = options;
let packageJson;
if (!database || !application || !version) {
const packageJsonPath = './package.json';
packageJson = (await (0, fs_1.fileExists)(packageJsonPath))
? JSON.parse((await (0, promises_1.readFile)(packageJsonPath)).toString())
: null;
}
if (!database && packageJson) {
database = packageJson.database;
}
if (!application && packageJson) {
application = packageJson.name;
}
if (!version && packageJson) {
version = packageJson.version;
}
return {
...options,
database,
application,
version,
};
}
function logHelpAndExit(code = 0) {
const help = (0, command_line_usage_1.default)(command_line_definitions_1.usageDefinitions);
console.log(help);
process.exit(code);
}
function logMissingArgAndExit(arg) {
console.log(`\nMissing argument: -${arg}\n`);
logHelpAndExit(1);
}
function logMissingAuthAndExit() {
console.log('\nInvalid authentication arguments: please provide either a user and password, or a clientId and clientSecret\n');
logHelpAndExit(1);
}
function normalizeDirectory(directory) {
return directory.replace(/\\/g, '/');
}
function validAuthenticationArguments({ user, password, clientId, clientSecret, }) {
return !!(user && password) || !!(clientId && clientSecret);
}
//# sourceMappingURL=index.js.map