Skip to content

feat: change binary from "base/version/mongod" to "base/mongod-arch-dist-version" #454

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Mar 10, 2021
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
44 changes: 27 additions & 17 deletions packages/mongodb-memory-server-core/src/util/DryMongoBinary.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { isNullOrUndefined, pathExists } from './utils';
import * as path from 'path';
import { arch, homedir, platform } from 'os';
import findCacheDir from 'find-cache-dir';
import getOS, { AnyOS } from './getos';
import getOS, { AnyOS, isLinuxOS } from './getos';

const log = debug('MongoMS:DryMongoBinary');

Expand All @@ -18,7 +18,13 @@ export interface BaseDryMongoBinaryOptions {
}

export interface DryMongoBinaryOptions extends BaseDryMongoBinaryOptions {
version: string;
version: NonNullable<BaseDryMongoBinaryOptions['version']>;
}

export interface DryMongoBinaryNameOptions {
version: NonNullable<DryMongoBinaryOptions['version']>;
arch: NonNullable<DryMongoBinaryOptions['arch']>;
os: NonNullable<DryMongoBinaryOptions['os']>;
}

export interface DryMongoBinaryPaths {
Expand Down Expand Up @@ -47,16 +53,16 @@ export class DryMongoBinary {
*/
static async locateBinary(opts: DryMongoBinaryOptions): Promise<string | undefined> {
log(`locateBinary: Trying to locate Binary for version "${opts.version}"`);
const systemBinary = opts.systemBinary ?? (await this.generateOptions()).systemBinary;
const useOpts = await this.generateOptions(opts);

if (!isNullOrUndefined(systemBinary) && systemBinary.length > 0) {
log(`locateBinary: env "SYSTEM_BINARY" was provided with value: "${systemBinary}"`);
if (!isNullOrUndefined(useOpts.systemBinary) && useOpts.systemBinary.length > 0) {
log(`locateBinary: env "SYSTEM_BINARY" was provided with value: "${useOpts.systemBinary}"`);

const systemReturn = await this.getSystemPath(systemBinary);
const systemReturn = await this.getSystemPath(useOpts.systemBinary);

if (isNullOrUndefined(systemReturn)) {
throw new Error(
`Config option "SYSTEM_BINARY" was provided with value "${systemBinary}", but no binary could be found!`
`Config option "SYSTEM_BINARY" was provided with value "${useOpts.systemBinary}", but no binary could be found!`
);
}

Expand All @@ -71,7 +77,7 @@ export class DryMongoBinary {
}

log('locateBinary: running generateDownloadPath');
const returnValue = await this.generateDownloadPath(opts);
const returnValue = await this.generateDownloadPath(useOpts);

if (!returnValue[0]) {
log('locateBinary: could not find an existing binary');
Expand Down Expand Up @@ -108,8 +114,7 @@ export class DryMongoBinary {
systemBinary: resolveConfig(ResolveConfigVariables.SYSTEM_BINARY) || '',
};

// fix the path, because what gets returned is the full path to the binary (base/version/binary)
final.downloadDir = path.resolve((await this.generateDownloadPath(final))[1], '..', '..');
final.downloadDir = path.dirname((await this.generateDownloadPath(final))[1]);

return final;
}
Expand All @@ -118,10 +123,11 @@ export class DryMongoBinary {
* Get the full path with filename
* @return Absoulte Path with FileName
*/
static getBinaryName(): string {
static getBinaryName(opts: DryMongoBinaryNameOptions): string {
const addExe = platform() === 'win32' ? '.exe' : '';
const dist = isLinuxOS(opts.os) ? opts.os.dist : opts.os.os;

return `mongod${addExe}`;
return `mongod-${opts.arch}-${dist}-${opts.version}${addExe}`;
}

/**
Expand All @@ -133,7 +139,7 @@ export class DryMongoBinary {
basePath: string,
binaryName: string
): string {
return path.resolve(basePath, opts.version, binaryName);
return path.resolve(basePath, binaryName);
}

/**
Expand All @@ -159,14 +165,16 @@ export class DryMongoBinary {
* Generate an "MongoBinaryPaths" object
* @return an finished "MongoBinaryPaths" object
*/
static async generatePaths(opts: DryMongoBinaryOptions): Promise<DryMongoBinaryPaths> {
static async generatePaths(
opts: DryMongoBinaryOptions & DryMongoBinaryNameOptions
): Promise<DryMongoBinaryPaths> {
const final: DryMongoBinaryPaths = {
legacyHomeCache: '',
modulesCache: '',
relative: '',
resolveConfig: '',
};
const binaryName = this.getBinaryName();
const binaryName = this.getBinaryName(opts);
// Assign "node_modules/.cache" to modulesCache

// if we're in postinstall script, npm will set the cwd too deep
Expand Down Expand Up @@ -194,7 +202,7 @@ export class DryMongoBinary {

// Resolve the config value "DOWNLOAD_DIR" if provided, otherwise remove from list
const resolveConfigValue =
resolveConfig(ResolveConfigVariables.DOWNLOAD_DIR) || opts.downloadDir;
opts.downloadDir || resolveConfig(ResolveConfigVariables.DOWNLOAD_DIR);

if (!isNullOrUndefined(resolveConfigValue) && resolveConfigValue.length > 0) {
log(`generatePaths: resolveConfigValue is not empty`);
Expand All @@ -215,7 +223,9 @@ export class DryMongoBinary {
* Generate the Path where an Binary will be located
* @return "boolean" indicating if the binary exists at the provided path, and "string" the path to use for the binary
*/
static async generateDownloadPath(opts: DryMongoBinaryOptions): Promise<[boolean, string]> {
static async generateDownloadPath(
opts: DryMongoBinaryOptions & DryMongoBinaryNameOptions
): Promise<[boolean, string]> {
const preferGlobal = envToBool(resolveConfig(ResolveConfigVariables.PREFER_GLOBAL_PATH));
log(`generateDownloadPath: Generating Download Path, preferGlobal: "${preferGlobal}"`);
const paths = await this.generatePaths(opts);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,11 +62,13 @@ export class MongoBinaryDownload {
* Get the full path with filename
* @return Absoulte Path with FileName
*/
protected getPath(): string {
protected async getPath(): Promise<string> {
const opts = await DryMongoBinary.generateOptions({ version: this.version });

return DryMongoBinary.combineBinaryName(
{ version: this.version },
this.downloadDir,
DryMongoBinary.getBinaryName()
DryMongoBinary.getBinaryName(opts)
);
}

Expand All @@ -76,7 +78,7 @@ export class MongoBinaryDownload {
*/
async getMongodPath(): Promise<string> {
log('getMongodPath');
const mongodPath = this.getPath();
const mongodPath = await this.getPath();

if (await pathExists(mongodPath)) {
return mongodPath;
Expand Down Expand Up @@ -224,7 +226,7 @@ export class MongoBinaryDownload {
*/
async extract(mongoDBArchive: string): Promise<string> {
log('extract');
const mongodbFullPath = this.getPath();
const mongodbFullPath = await this.getPath();
const mongodbDirPath = path.dirname(mongodbFullPath);
log(`extract: archive: "${mongoDBArchive}" final: "${mongodbFullPath}"`);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ describe('DryBinary', () => {
binary: 'mongod',
};
expect(binary.DryMongoBinary.combineBinaryName(input.opts, input.base, input.binary)).toEqual(
path.resolve(input.base, input.opts.version, input.binary)
path.resolve(input.base, 'mongod')
);
});

Expand Down Expand Up @@ -51,11 +51,12 @@ describe('DryBinary', () => {
let tmpDir: tmp.DirResult;
/** Used for non "find-cache-dir" */
let tmpDir2: tmp.DirResult;
let cwdBefore: string;
const cwdBefore = process.cwd();
const version = '4.0.20';
let opts: binary.DryMongoBinaryOptions & binary.DryMongoBinaryNameOptions;
let binaryName: string;
beforeAll(async () => {
delete process.env[envName(ResolveConfigVariables.DOWNLOAD_DIR)]; // i dont know where this comes from, but without it, this property exists
cwdBefore = process.cwd();
tmpDir = tmp.dirSync({ prefix: 'mongo-mem-drybinGP-', unsafeCleanup: true });
tmpDir2 = tmp.dirSync({ prefix: 'mongo-mem-drybinGP-', unsafeCleanup: true });
jest
Expand All @@ -80,106 +81,86 @@ describe('DryBinary', () => {
process.chdir(cwdBefore);
});

beforeEach(() => {
beforeEach(async () => {
// execute this before each test, to always have the correct cwd
process.chdir(path.resolve(tmpDir.name));
opts = await binary.DryMongoBinary.generateOptions({ version });
delete opts.downloadDir; // delete, because these tests are about "generatePaths", which will prioritise "opts.downloadDir" over env
binaryName = binary.DryMongoBinary.getBinaryName(opts);
});
afterEach(() => {
delete process.env[envName(ResolveConfigVariables.DOWNLOAD_DIR)];
});

it('should have 3 complete paths while not being in postinstall or having a config', async () => {
const returnValue = await binary.DryMongoBinary.generatePaths({ version });
const returnValue = await binary.DryMongoBinary.generatePaths(opts);
expect(returnValue).toStrictEqual({
resolveConfig: '', // empty because not having an extra config value
relative: path.resolve(tmpDir.name, 'mongodb-binaries', version, 'mongod'),
legacyHomeCache: path.resolve(
tmpDir.name,
'homedir/.cache/mongodb-binaries',
version,
'mongod'
),
relative: path.resolve(tmpDir.name, 'mongodb-binaries', binaryName),
legacyHomeCache: path.resolve(tmpDir.name, 'homedir/.cache/mongodb-binaries', binaryName),
modulesCache: path.resolve(
tmpDir.name,
'node_modules/.cache/mongodb-memory-server',
version,
'mongod'
binaryName
),
} as binary.DryMongoBinaryPaths);
});

it('should have 3 complete paths while being in postinstall and not having a config', async () => {
process.chdir(path.resolve(tmpDir.name, 'node_modules/mongodb-memory-server'));
const returnValue = await binary.DryMongoBinary.generatePaths({ version });
const returnValue = await binary.DryMongoBinary.generatePaths(opts);
expect(returnValue).toStrictEqual({
resolveConfig: '', // empty because not having an extra config value
relative: path.resolve(
tmpDir.name,
'node_modules/mongodb-memory-server',
'mongodb-binaries',
version,
'mongod'
),
legacyHomeCache: path.resolve(
tmpDir.name,
'homedir/.cache/mongodb-binaries',
version,
'mongod'
binaryName
),
legacyHomeCache: path.resolve(tmpDir.name, 'homedir/.cache/mongodb-binaries', binaryName),
modulesCache: path.resolve(
tmpDir.name,
'node_modules/.cache/mongodb-memory-server',
version,
'mongod'
binaryName
),
} as binary.DryMongoBinaryPaths);
});

it('should have 4 complete paths while not being in postinstall but having a config', async () => {
const customPath = '/some/custom/path';
process.env[envName(ResolveConfigVariables.DOWNLOAD_DIR)] = customPath;
const returnValue = await binary.DryMongoBinary.generatePaths({ version });
const returnValue = await binary.DryMongoBinary.generatePaths(opts);
expect(returnValue).toStrictEqual({
resolveConfig: path.resolve('/some/custom/path', version, 'mongod'),
relative: path.resolve(tmpDir.name, 'mongodb-binaries', version, 'mongod'),
legacyHomeCache: path.resolve(
tmpDir.name,
'homedir/.cache/mongodb-binaries',
version,
'mongod'
),
resolveConfig: path.resolve('/some/custom/path', binaryName),
relative: path.resolve(tmpDir.name, 'mongodb-binaries', binaryName),
legacyHomeCache: path.resolve(tmpDir.name, 'homedir/.cache/mongodb-binaries', binaryName),
modulesCache: path.resolve(
tmpDir.name,
'node_modules/.cache/mongodb-memory-server',
version,
'mongod'
binaryName
),
} as binary.DryMongoBinaryPaths);
});

it('should have 2 complete paths while not being in postinstall and not having a config and not being in an project', async () => {
const customPath = path.resolve(tmpDir2.name);
process.chdir(customPath);
const returnValue = await binary.DryMongoBinary.generatePaths({ version });
const returnValue = await binary.DryMongoBinary.generatePaths(opts);
expect(returnValue).toStrictEqual({
resolveConfig: '', // empty because not having an extra config value
relative: path.resolve(tmpDir2.name, 'mongodb-binaries', version, 'mongod'),
legacyHomeCache: path.resolve(
tmpDir.name,
'homedir/.cache/mongodb-binaries',
version,
'mongod'
),
relative: path.resolve(tmpDir2.name, 'mongodb-binaries', binaryName),
legacyHomeCache: path.resolve(tmpDir.name, 'homedir/.cache/mongodb-binaries', binaryName),
modulesCache: '', // because not being in an project
} as binary.DryMongoBinaryPaths);
});
});

describe('generateDownloadPath', () => {
const filesExist: Set<string> = new Set();
const version = '4.0.20';
let expectedPaths: binary.DryMongoBinaryPaths;
beforeAll(() => {
let opts: Required<binary.DryMongoBinaryOptions>;
beforeAll(async () => {
opts = await binary.DryMongoBinary.generateOptions({ version: '4.0.20' });
delete process.env[envName(ResolveConfigVariables.PREFER_GLOBAL_PATH)];
jest.spyOn(utils, 'pathExists').mockImplementation((file) => {
// this is to ensure it is returning an promise
Expand Down Expand Up @@ -214,7 +195,7 @@ describe('DryBinary', () => {
resolveConfig: expectedPath,
};
filesExist.add(expectedPath);
const returnValue = await binary.DryMongoBinary.generateDownloadPath({ version });
const returnValue = await binary.DryMongoBinary.generateDownloadPath(opts);
expect(binary.DryMongoBinary.generatePaths).toHaveBeenCalledTimes(1);
expect(returnValue).toStrictEqual([true, expectedPath]);
});
Expand All @@ -228,7 +209,7 @@ describe('DryBinary', () => {
resolveConfig: '/no',
};
filesExist.add(expectedPath);
const returnValue = await binary.DryMongoBinary.generateDownloadPath({ version });
const returnValue = await binary.DryMongoBinary.generateDownloadPath(opts);
expect(binary.DryMongoBinary.generatePaths).toHaveBeenCalledTimes(1);
expect(returnValue).toStrictEqual([true, expectedPath]);
});
Expand All @@ -242,7 +223,7 @@ describe('DryBinary', () => {
resolveConfig: '/no',
};
filesExist.add(expectedPath);
const returnValue = await binary.DryMongoBinary.generateDownloadPath({ version });
const returnValue = await binary.DryMongoBinary.generateDownloadPath(opts);
expect(binary.DryMongoBinary.generatePaths).toHaveBeenCalledTimes(1);
expect(returnValue).toStrictEqual([true, expectedPath]);
});
Expand All @@ -256,7 +237,7 @@ describe('DryBinary', () => {
resolveConfig: '/no',
};
filesExist.add(expectedPath);
const returnValue = await binary.DryMongoBinary.generateDownloadPath({ version });
const returnValue = await binary.DryMongoBinary.generateDownloadPath(opts);
expect(binary.DryMongoBinary.generatePaths).toHaveBeenCalledTimes(1);
expect(returnValue).toStrictEqual([true, expectedPath]);
});
Expand All @@ -271,7 +252,7 @@ describe('DryBinary', () => {
relative: '',
resolveConfig: expectedPath,
};
const returnValue = await binary.DryMongoBinary.generateDownloadPath({ version });
const returnValue = await binary.DryMongoBinary.generateDownloadPath(opts);
expect(binary.DryMongoBinary.generatePaths).toHaveBeenCalledTimes(1);
expect(returnValue).toStrictEqual([false, expectedPath]);
});
Expand All @@ -285,7 +266,7 @@ describe('DryBinary', () => {
relative: '',
resolveConfig: '',
};
const returnValue = await binary.DryMongoBinary.generateDownloadPath({ version });
const returnValue = await binary.DryMongoBinary.generateDownloadPath(opts);
expect(binary.DryMongoBinary.generatePaths).toHaveBeenCalledTimes(1);
expect(returnValue).toStrictEqual([false, expectedPath]);
});
Expand All @@ -299,7 +280,7 @@ describe('DryBinary', () => {
relative: '',
resolveConfig: '',
};
const returnValue = await binary.DryMongoBinary.generateDownloadPath({ version });
const returnValue = await binary.DryMongoBinary.generateDownloadPath(opts);
expect(binary.DryMongoBinary.generatePaths).toHaveBeenCalledTimes(1);
expect(returnValue).toStrictEqual([false, expectedPath]);
});
Expand All @@ -313,7 +294,7 @@ describe('DryBinary', () => {
relative: expectedPath,
resolveConfig: '',
};
const returnValue = await binary.DryMongoBinary.generateDownloadPath({ version });
const returnValue = await binary.DryMongoBinary.generateDownloadPath(opts);
expect(binary.DryMongoBinary.generatePaths).toHaveBeenCalledTimes(1);
expect(returnValue).toStrictEqual([false, expectedPath]);
});
Expand Down