Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .evergreen/compile-artifact.sh
Original file line number Diff line number Diff line change
Expand Up @@ -36,5 +36,7 @@ fi
export PUPPETEER_SKIP_CHROMIUM_DOWNLOAD="true"
npm run evergreen-release compile
dist/mongosh --version
dist/mongosh --build-info
dist/mongosh --build-info | grep -q '"distributionKind": "compiled"'

tar cvzf dist.tgz dist
12 changes: 5 additions & 7 deletions config/build.conf.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,9 @@ const EXECUTABLE_PATH = path.join(OUTPUT_DIR, process.platform === 'win32' ? 'mo
const MONGOCRYPTD_PATH = path.resolve(__dirname, '..', 'tmp', 'mongocryptd-mongosh' + (process.platform === 'win32' ? '.exe' : ''));

/**
* Analytics configuration file.
* Build info JSON data file.
*/
const ANALYTICS_CONFIG_FILE_PATH = path.join(CLI_REPL_DIR, 'lib', 'analytics-config.js');
const BUILD_INFO_FILE_PATH = path.join(CLI_REPL_DIR, 'lib', 'build-info.json');

/**
* The bundle id for MacOs.
Expand All @@ -58,10 +58,7 @@ const APPLE_NOTARIZATION_BUNDLE_ID = 'com.mongodb.mongosh';
/**
* The SHA for the current git HEAD.
*/
// TODO: replace with "real" SHA after EVG-13919
const REVISION = process.env.IS_PATCH ?
`pr-${process.env.GITHUB_PR_NUMBER}-${process.env.REVISION_ORDER_ID}` :
process.env.REVISION;
const REVISION = process.env.GITHUB_COMMIT ?? process.env.REVISION;

/**
* The copyright notice for debian packages and .exe files
Expand All @@ -78,7 +75,8 @@ module.exports = {
execInput: EXEC_INPUT,
executablePath: EXECUTABLE_PATH,
outputDir: OUTPUT_DIR,
analyticsConfigFilePath: ANALYTICS_CONFIG_FILE_PATH,
buildInfoFilePath: BUILD_INFO_FILE_PATH,
executableOsId: process.env.EXECUTABLE_OS_ID,
project: process.env.PROJECT,
revision: REVISION,
branch: process.env.BRANCH_NAME,
Expand Down
65 changes: 0 additions & 65 deletions packages/build/src/analytics.spec.ts

This file was deleted.

37 changes: 0 additions & 37 deletions packages/build/src/analytics.ts

This file was deleted.

2 changes: 1 addition & 1 deletion packages/build/src/barque.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ describe('Barque', () => {
executablePath: 'executablePath',
mongocryptdPath: 'mongocryptdPath',
outputDir: 'outputDir',
analyticsConfigFilePath: 'analyticsConfigFilePath',
buildInfoFilePath: 'buildInfoFilePath',
project: 'project',
revision: 'revision',
branch: 'branch',
Expand Down
30 changes: 30 additions & 0 deletions packages/build/src/build-info.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import type { Config } from './config';
import { promises as fs } from 'fs';
import os from 'os';

/**
* Write data into a build config that is included in the executable but
* comes from the build environment rather than the source tree.
*/
export async function writeBuildInfo(config: Config, distributionKind: 'compiled' | 'packaged'): Promise<void> {
if (!config.buildInfoFilePath) {
throw new Error('Build info file path is required');
}

if (!config.segmentKey) {
throw new Error('Segment key is required');
}

const info = {
segmentApiKey: config.segmentKey,
version: config.version,
distributionKind,
buildArch: os.arch(),
buildPlatform: os.platform(),
buildTarget: config.executableOsId ?? 'unknown',
buildTime: new Date().toISOString(),
gitVersion: config.revision ?? null
};
console.info('mongosh: writing build info data:', config.buildInfoFilePath);
await fs.writeFile(config.buildInfoFilePath, JSON.stringify(info));
}
44 changes: 26 additions & 18 deletions packages/build/src/compile/generate-bundle.spec.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import { expect } from 'chai';
import childProcess from 'child_process';
import { promises as fs } from 'fs';
import os from 'os';
import path from 'path';
import rimraf from 'rimraf';
import { promisify } from 'util';
import { generateBundle } from './generate-bundle';
import type { Config } from '../config';

const execFile = promisify(childProcess.execFile);

Expand All @@ -28,21 +30,25 @@ describe('compile generateBundle', function() {
await fs.writeFile(path.join(tmpdir, 'b.js'), `
console.log(JSON.stringify({
main: 'it ' + require("./a") + '!',
analytics: require("./analytics")
buildInfo: require("./buildInfo.json")
}));
`);
await generateBundle(
path.join(tmpdir, 'b.js'),
path.join(tmpdir, 'compiled.js'),
path.join(tmpdir, 'analytics.js'),
'...segment-key...');
await generateBundle({
input: path.join(tmpdir, 'b.js'),
execInput: path.join(tmpdir, 'compiled.js'),
buildInfoFilePath: path.join(tmpdir, 'buildInfo.json'),
segmentKey: '...segment-key...'
} as Partial<Config> as any);
await fs.unlink(path.join(tmpdir, 'a.js'));
await fs.unlink(path.join(tmpdir, 'b.js'));
await fs.unlink(path.join(tmpdir, 'analytics.js'));
await fs.unlink(path.join(tmpdir, 'buildInfo.json'));
const { stdout } = await execFile(process.execPath, [path.join(tmpdir, 'compiled.js')]);
const parsed = JSON.parse(stdout);
expect(parsed.main).to.equal('it works!');
expect(parsed.analytics.SEGMENT_API_KEY).to.equal('...segment-key...');
expect(parsed.buildInfo.segmentApiKey).to.equal('...segment-key...');
expect(parsed.buildInfo.buildArch).to.equal(os.arch());
expect(parsed.buildInfo.buildPlatform).to.equal(os.platform());
expect(parsed.buildInfo.buildTime).to.be.a('string');
});

it('does not attempt to load ES6 modules because parcel cannot handle them properly', async() => {
Expand All @@ -54,11 +60,12 @@ describe('compile generateBundle', function() {
await fs.writeFile(path.join(tmpdir, 'b.js'), `
console.log(require("some-fake-module"));
`);
await generateBundle(
path.join(tmpdir, 'b.js'),
path.join(tmpdir, 'compiled.js'),
path.join(tmpdir, 'analytics.js'),
'...segment-key...');
await generateBundle({
input: path.join(tmpdir, 'b.js'),
execInput: path.join(tmpdir, 'compiled.js'),
buildInfoFilePath: path.join(tmpdir, 'buildInfo.json'),
segmentKey: '...segment-key...'
} as Partial<Config> as any);
const { stdout } = await execFile(process.execPath, [path.join(tmpdir, 'compiled.js')]);
expect(stdout.trim()).to.equal('cjs');
});
Expand All @@ -72,11 +79,12 @@ describe('compile generateBundle', function() {
await fs.writeFile(path.join(tmpdir, 'b.js'), `
console.log(require("some-fake-module"));
`);
await generateBundle(
path.join(tmpdir, 'b.js'),
path.join(tmpdir, 'compiled.js'),
path.join(tmpdir, 'analytics.js'),
'...segment-key...');
await generateBundle({
input: path.join(tmpdir, 'b.js'),
execInput: path.join(tmpdir, 'compiled.js'),
buildInfoFilePath: path.join(tmpdir, 'buildInfo.json'),
segmentKey: '...segment-key...'
} as Partial<Config> as any);
const { stdout } = await execFile(process.execPath, [path.join(tmpdir, 'compiled.js')]);
expect(stdout.trim()).to.equal('plain');
});
Expand Down
23 changes: 11 additions & 12 deletions packages/build/src/compile/generate-bundle.ts
Original file line number Diff line number Diff line change
@@ -1,29 +1,28 @@
import path from 'path';
import Bundler from 'parcel-bundler';
import { writeAnalyticsConfig } from '../analytics';
import { writeBuildInfo } from '../build-info';
import type { Config } from '../config';

/**
* Generate the bundled up JS entryFile that will be compiled
* into the executable.
*
* @param {string} entryFile - The entry file for generating the bundle.
* @param {string} bundleOutputFile - The output file the bundle will be written to.
* @param {string} analyticsConfigFilePath - The path to the analytics config file.
* @param {string} segmentKey - The segment API key.
* @param {object} config - The current build config.
*/
export async function generateBundle(entryFile: string, bundleOutputFile: string, analyticsConfigFilePath: string, segmentKey: string): Promise<void> {
export async function generateBundle(config: Config): Promise<void> {
// This takes the segment api key and writes it to the
// cli-repl's analytics-config file.
await writeAnalyticsConfig(analyticsConfigFilePath, segmentKey);
// cli-repl's analytics-config file, as well as information about the
// current build environment.
await writeBuildInfo(config, 'compiled');

console.info('mongosh: creating bundle:', bundleOutputFile);
console.info('mongosh: creating bundle:', config.execInput);

// Parcel is the saviour here since it was the only bundling
// tool that could figure out how to handle everything in a
// complex lerna project with cyclic dependencies everywhere.
const bundler = new Bundler(entryFile, {
outDir: path.dirname(bundleOutputFile),
outFile: path.basename(bundleOutputFile),
const bundler = new Bundler(config.input, {
outDir: path.dirname(config.execInput),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah I remember being confused by the name execInput here as the outFile for the bundle. Maybe we can rename execInput to bundleFile inside config? (no need to do in that PR)

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I’m very much up for renaming a number of config options :)

outFile: path.basename(config.execInput),
contentHash: false,
target: 'node',
bundleNodeModules: true,
Expand Down
23 changes: 10 additions & 13 deletions packages/build/src/compile/run-compile.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import type { Config } from '../config';
import type { PackageInformation } from '../packaging/package';
import { generateBundle } from './generate-bundle';
import { SignableCompiler } from './signable-compiler';
Expand All @@ -6,24 +7,20 @@ import { SignableCompiler } from './signable-compiler';
* Compile the executable. This builds the thing that ends up in `dist/`
* that we will zip up and send off to userland.
*/
export async function runCompile(
input: string,
execInput: string,
executablePath: string,
execNodeVersion: string,
analyticsConfigFilePath: string,
segmentKey: string,
executableMetadata: PackageInformation['metadata']
): Promise<string> {
export async function runCompile(config: Config): Promise<string> {
// We use Parcel to bundle up everything into a single JS under
// cli-repl/dist/mongosh.js that the executable generator can use as input.
// This JS also takes care of the analytics config file being written.
await generateBundle(input, execInput, analyticsConfigFilePath, segmentKey);
await generateBundle(config);

console.info('mongosh: creating binary:', executablePath);
console.info('mongosh: creating binary:', config.executablePath);

await new SignableCompiler(execInput, executablePath, execNodeVersion, executableMetadata)
await new SignableCompiler(
config.execInput,
config.executablePath,
config.execNodeVersion,
(config.packageInformation?.metadata ?? {}) as PackageInformation['metadata'])
.compile();

return executablePath;
return config.executablePath;
}
5 changes: 2 additions & 3 deletions packages/build/src/compile/signable-compiler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import pkgUp from 'pkg-up';
import path from 'path';
import childProcess from 'child_process';
import { once } from 'events';
import { Platform } from '../config';
import type { PackageInformation } from '../packaging/package';
import { compileJSFileAsBinary } from 'boxednode';

Expand Down Expand Up @@ -88,8 +87,8 @@ export class SignableCompiler {
// open ssl with asm so we revert back to the slower version.
await compileJSFileAsBinary({
configureArgs:
os.platform() === Platform.Windows ? ['openssl-no-asm'] :
os.platform() === Platform.MacOs ? ['--openssl-no-asm'] : [],
os.platform() === 'win32' ? ['openssl-no-asm'] :
os.platform() === 'darwin' ? ['--openssl-no-asm'] : [],
sourceFile: this.sourceFile,
targetFile: this.targetFile,
nodeVersionRange: this.nodeVersionRange,
Expand Down
3 changes: 2 additions & 1 deletion packages/build/src/config/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ export interface Config {
execInput: string;
executablePath: string;
outputDir: string;
analyticsConfigFilePath?: string;
buildInfoFilePath?: string;
executableOsId?: string;
rootDir: string;
project?: string;
revision?: string;
Expand Down
Loading