Skip to content

Commit

Permalink
feat: release package as a library (#80)
Browse files Browse the repository at this point in the history
* feat: release package as a library

* fix: export ApiClient

* chore: update README
  • Loading branch information
bobbyg603 authored Oct 31, 2023
1 parent 7406c18 commit a786c9f
Show file tree
Hide file tree
Showing 16 changed files with 101 additions and 118 deletions.
39 changes: 7 additions & 32 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ Links
2. Import `BugSplatApiClient` and `VersionsApiClient` from @bugsplat/symbol-upload. Alternatively, you can import `OAuthClientCredentialsClient` if you'd prefer to authenticate with an [OAuth2 Client Credentials](https://docs.bugsplat.com/introduction/development/web-services/oauth2#client-credentials) Client ID and Client Secret.

```ts
import { BugSplatApiClient, OAuthClientCredentialsClient, VersionsApiClient } from '@bugsplat/symbol-upload';
import { BugSplatApiClient, OAuthClientCredentialsClient, uploadSymbolFiles } from '@bugsplat/symbol-upload';
```

3. Create a new instance of `BugSplatApiClient` using the `createAuthenticatedClientForNode` async factory function or `OAuthClientCredentialsClient` using the `createAuthenticatedClient` async factory function.
Expand All @@ -124,41 +124,16 @@ const bugsplat = await BugSplatApiClient.createAuthenticatedClientForNode(email,
const bugsplat = await OAuthClientCredentialsClient.createAuthenticatedClient(clientId, clientSecret);
```

4. Create an `UploadableFile` object for each symbol file path.
4. Upload your symbol files to bugsplat by calling the `uploadSymbolFiles` function.

```ts
const files = paths.map(path => {
const stat = fs.statSync(path);
const size = stat.size;
const name = basename(path);
const file = fs.createReadStream(path);
return {
name,
size,
file
};
});
const directory = '/path/to/symbols/dir';
const files = '**/*.+(exe|dll|pdb)';
await uploadSymbolFiles(bugsplat, database, application, version, directory, files);
```

5. Create an instance of `VersionsApiClient` passing it an instance of `BugSplatApiClient`.
If you've done everything correctly, your symbols should be shown by clicking the application link on the [Versions](https://app.bugsplat.com/v2/versions) page.

```ts
const versionsApiClient = new VersionsApiClient(bugsplat);
```

6. Await the call to `postSymbols` passing it the name of your BugSplat `database`, `application`, `version` and an array of `files`. These values need to match the values you used to initialize BugSplat on whichever [platform](https://docs.bugsplat.com/introduction/getting-started/integrations) you've integrated with.

```ts
await versionsApiClient.postSymbols(
database,
application,
version,
files
);
```

If you've done everything correctly your symbols should now be shown on the [Versions](https://app.bugsplat.com/v2/versions) page.

![Versions](https://bugsplat-public.s3.amazonaws.com/npm/symbol-upload/versions.png)
<img width="1728" alt="image" src="https://github.com/BugSplat-Git/symbol-upload/assets/2646053/7314bd36-05db-4188-89e4-10f4e7442cec">

Thanks for using BugSplat!
85 changes: 7 additions & 78 deletions bin/index.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,10 @@
#! /usr/bin/env node
import { ApiClient, BugSplatApiClient, OAuthClientCredentialsClient, SymbolsApiClient, VersionsApiClient } from '@bugsplat/js-api-client';
import { ApiClient, BugSplatApiClient, OAuthClientCredentialsClient, VersionsApiClient } from '@bugsplat/js-api-client';
import commandLineArgs, { CommandLineOptions } from 'command-line-args';
import commandLineUsage from 'command-line-usage';
import { glob } from 'glob';
import { existsSync } from 'node:fs';
import { mkdir, readFile, stat } from 'node:fs/promises';
import { basename, dirname, extname, join, relative } from 'node:path';
import { pool } from 'workerpool';
import { readFile, stat } from 'node:fs/promises';
import { uploadSymbolFiles } from '../src/upload';
import { CommandLineDefinition, argDefinitions, usageDefinitions } from './command-line-definitions';
import { SymbolFileInfo } from './info';
import { tryGetPdbGuid, tryGetPeGuid } from './pdb';
import { getSymFileInfo } from './sym';
import { safeRemoveTmp, tmpDir } from './tmp';
import { createWorkersFromSymbolFiles } from './worker';

const workerPool = pool(join(__dirname, 'compression.js'));

(async () => {
let {
Expand Down Expand Up @@ -75,11 +65,10 @@ const workerPool = pool(join(__dirname, 'compression.js'));

console.log('Authentication success!');

const versionsApiClient = new VersionsApiClient(bugsplat);
const symbolsApiClient = new SymbolsApiClient(bugsplat);

if (remove) {
try {
const versionsApiClient = new VersionsApiClient(bugsplat);

console.log(`About to delete symbols for ${database}-${application}-${version}...`);

await versionsApiClient.deleteSymbols(
Expand All @@ -98,75 +87,15 @@ const workerPool = pool(join(__dirname, 'compression.js'));
}

directory = normalizeDirectory(directory);
const globPattern = `${directory}/${files}`;

let returnCode = 0;
try {
const symbolFilePaths = await 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')}`);
console.log(`About to upload symbols for ${database}-${application}-${version}...`);

if (!existsSync(tmpDir)) {
await mkdir(tmpDir);
}

const symbolFiles = await Promise.all(symbolFilePaths.map(async (symbolFilePath) => await createSymbolFileInfo(directory, symbolFilePath)));
const workers = createWorkersFromSymbolFiles(workerPool, symbolFiles, [symbolsApiClient, versionsApiClient]);
const uploads = workers.map((worker) => worker.upload(database, application, version));
await Promise.all(uploads);

console.log('Symbols uploaded successfully!');
} catch (error) {
console.error(error);
returnCode = 1;
} finally {
await safeRemoveTmp();
}
await uploadSymbolFiles(bugsplat, database, application, version, directory, files);

process.exit(returnCode);
process.exit(0);
})().catch((error) => {
console.error(error.message);
process.exit(1);
});

async function createSymbolFileInfo(searchDirectory: string, symbolFilePath: string): Promise<SymbolFileInfo> {
const path = symbolFilePath;
const relativePath = relative(searchDirectory, dirname(path));
const extLowerCase = extname(path).toLowerCase();
const isSymFile = extLowerCase.includes('.sym');
const isPdbFile = extLowerCase.includes('.pdb');
const isPeFile = extLowerCase.includes('.exe') || extLowerCase.includes('.dll');

let dbgId = '';
let moduleName = '';

if (isPdbFile) {
dbgId = await tryGetPdbGuid(path);
}

if (isPeFile) {
dbgId = await tryGetPeGuid(path);
}

if (isSymFile) {
({ dbgId, moduleName } = await getSymFileInfo(path));
}

moduleName = moduleName || basename(path);

return {
path,
dbgId,
moduleName,
relativePath
} as SymbolFileInfo;
}

async function createBugSplatClient({
user,
password,
Expand Down
5 changes: 4 additions & 1 deletion index.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
export {
ApiClient,
BugSplatApiClient,
VersionsApiClient,
SymbolsApiClient,
OAuthClientCredentialsClient,
UploadableFile,
GZippedSymbolFile
} from '@bugsplat/js-api-client';
} from '@bugsplat/js-api-client';

export { uploadSymbolFiles } from './src/upload';
2 changes: 1 addition & 1 deletion spec/compression.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { join } from 'node:path';
import workerpool from 'workerpool';
import extract from 'extract-zip';
import { cwd } from 'node:process';
const pool = workerpool.pool(join(__dirname, '../bin/compression.js'));
const pool = workerpool.pool(join(__dirname, '../src/compression.js'));

describe('gzip', () => {
describe('createGzipFile', () => {
Expand Down
2 changes: 1 addition & 1 deletion spec/pdb.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { tryGetPdbGuid, tryGetPeGuid } from '../bin/pdb';
import { tryGetPdbGuid, tryGetPeGuid } from '../src/pdb';

describe('pdb', () => {
describe('tryGetPdbGuid', () => {
Expand Down
2 changes: 1 addition & 1 deletion spec/sym.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { getSymFileInfo } from '../bin/sym';
import { getSymFileInfo } from '../src/sym';

describe('getSymFileInfo', () => {
it('should get debug id for file with a 33 character debug id', async () => {
Expand Down
2 changes: 1 addition & 1 deletion spec/tmp.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { safeRemoveTmp } from '../bin/tmp';
import { safeRemoveTmp } from '../src/tmp';

describe('tmp', () => {
it('should retry removing tmp directory', async () => {
Expand Down
4 changes: 2 additions & 2 deletions spec/worker.spec.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { SymbolsApiClient, VersionsApiClient } from '@bugsplat/js-api-client';
import retryPromise from 'promise-retry';
import { SymbolFileInfo } from '../bin/info';
import { UploadWorker, createWorkersFromSymbolFiles } from '../bin/worker';
import { SymbolFileInfo } from '../src/info';
import { UploadWorker, createWorkersFromSymbolFiles } from '../src/worker';
import { cpus } from 'node:os';
import { WorkerPool } from 'workerpool';
import { basename } from 'node:path';
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
76 changes: 76 additions & 0 deletions src/upload.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import { ApiClient, SymbolsApiClient, VersionsApiClient } from "@bugsplat/js-api-client";
import { existsSync } from "node:fs";
import { mkdir } from "node:fs/promises";
import { basename, dirname, extname, join, relative } from "node:path";
import { pool } from "workerpool";
import { SymbolFileInfo } from './info';
import { tryGetPdbGuid, tryGetPeGuid } from './pdb';
import { getSymFileInfo } from './sym';
import { safeRemoveTmp, tmpDir } from './tmp';
import { createWorkersFromSymbolFiles } from './worker';
import { glob } from "glob";

const workerPool = pool(join(__dirname, 'compression.js'));

export async function uploadSymbolFiles(bugsplat: ApiClient, database: string, application: string, version: string, directory: string, filesGlob: string) {
try {
const globPattern = `${directory}/${filesGlob}`;

const symbolFilePaths = await 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')}`);
console.log(`About to upload symbols for ${database}-${application}-${version}...`);

if (!existsSync(tmpDir)) {
await mkdir(tmpDir);
}

const symbolsApiClient = new SymbolsApiClient(bugsplat);
const versionsApiClient = new VersionsApiClient(bugsplat);
const symbolFiles = await Promise.all(symbolFilePaths.map(async (symbolFilePath) => await createSymbolFileInfo(directory, symbolFilePath)));
const workers = createWorkersFromSymbolFiles(workerPool, symbolFiles, [symbolsApiClient, versionsApiClient]);
const uploads = workers.map((worker) => worker.upload(database, application, version));
await Promise.all(uploads);

console.log('Symbols uploaded successfully!');
} finally {
await safeRemoveTmp();
}
}

async function createSymbolFileInfo(searchDirectory: string, symbolFilePath: string): Promise<SymbolFileInfo> {
const path = symbolFilePath;
const relativePath = relative(searchDirectory, dirname(path));
const extLowerCase = extname(path).toLowerCase();
const isSymFile = extLowerCase.includes('.sym');
const isPdbFile = extLowerCase.includes('.pdb');
const isPeFile = extLowerCase.includes('.exe') || extLowerCase.includes('.dll');

let dbgId = '';
let moduleName = '';

if (isPdbFile) {
dbgId = await tryGetPdbGuid(path);
}

if (isPeFile) {
dbgId = await tryGetPeGuid(path);
}

if (isSymFile) {
({ dbgId, moduleName } = await getSymFileInfo(path));
}

moduleName = moduleName || basename(path);

return {
path,
dbgId,
moduleName,
relativePath
} as SymbolFileInfo;
}
File renamed without changes.
2 changes: 1 addition & 1 deletion tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,6 @@
"files": [
"./index.ts",
"./bin/index.ts",
"./bin/compression.js"
"src/compression.js"
]
}

0 comments on commit a786c9f

Please sign in to comment.