From 9c03a98e2b58e3792c6ce4ac2970598ff63b937f Mon Sep 17 00:00:00 2001 From: Sergei Zharinov Date: Wed, 4 Aug 2021 16:08:35 +0300 Subject: [PATCH] refactor: Split exec function to smaller blocks --- .../{exec.spec.ts.snap => index.spec.ts.snap} | 2 +- lib/util/exec/{exec.spec.ts => index.spec.ts} | 0 lib/util/exec/index.ts | 145 ++++++++++-------- 3 files changed, 85 insertions(+), 62 deletions(-) rename lib/util/exec/__snapshots__/{exec.spec.ts.snap => index.spec.ts.snap} (93%) rename lib/util/exec/{exec.spec.ts => index.spec.ts} (100%) diff --git a/lib/util/exec/__snapshots__/exec.spec.ts.snap b/lib/util/exec/__snapshots__/index.spec.ts.snap similarity index 93% rename from lib/util/exec/__snapshots__/exec.spec.ts.snap rename to lib/util/exec/__snapshots__/index.spec.ts.snap index c309df433cfdf3..6a7afe72fbbcef 100644 --- a/lib/util/exec/__snapshots__/exec.spec.ts.snap +++ b/lib/util/exec/__snapshots__/index.spec.ts.snap @@ -1,6 +1,6 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`util/exec/exec Supports image prefetch 1`] = ` +exports[`util/exec/index Supports image prefetch 1`] = ` Array [ "echo hello", "echo hello", diff --git a/lib/util/exec/exec.spec.ts b/lib/util/exec/index.spec.ts similarity index 100% rename from lib/util/exec/exec.spec.ts rename to lib/util/exec/index.spec.ts diff --git a/lib/util/exec/index.ts b/lib/util/exec/index.ts index 991ec87ae713e7..a8b0b2342a2871 100644 --- a/lib/util/exec/index.ts +++ b/lib/util/exec/index.ts @@ -21,38 +21,31 @@ export interface ExecOptions extends ChildProcessExecOptions { docker?: Opt; } -function createChildEnv( - env: NodeJS.ProcessEnv, - extraEnv: ExtraEnv -): ExtraEnv { - const extraEnvEntries = Object.entries({ ...extraEnv }).filter(([_, val]) => { - if (val === null) { - return false; - } - if (val === undefined) { - return false; - } - return true; - }); - const extraEnvKeys = Object.keys(extraEnvEntries); +function getChildEnv({ + extraEnv = {}, + env: forcedEnv = {}, +}: ExecOptions): ExtraEnv { + const { customEnvVariables: globalConfigEnv } = getAdminConfig(); - const childEnv = { + const inheritedKeys = Object.entries(extraEnv).reduce( + (acc, [key, val]) => + val === null || val === undefined ? acc : [...acc, key], + [] + ); + const parentEnv = getChildProcessEnv(inheritedKeys); + const childEnv = Object.entries({ ...extraEnv, - ...getChildProcessEnv(extraEnvKeys), - ...env, - }; - - const result: ExtraEnv = {}; - Object.entries(childEnv).forEach(([key, val]) => { - if (val === null) { - return; - } - if (val === undefined) { - return; - } - result[key] = val.toString(); - }); - return result; + ...parentEnv, + ...globalConfigEnv, + ...forcedEnv, + }).reduce( + (acc, [key, val]) => + val === null || val === undefined + ? acc + : { ...acc, [key]: val.toString() }, + {} + ); + return childEnv; } function dockerEnvVars( @@ -65,27 +58,20 @@ function dockerEnvVars( ); } -export async function exec( - cmd: string | string[], - opts: ExecOptions = {} -): Promise { - const { env, docker, cwdFile } = opts; - const { binarySource, dockerChildPrefix, customEnvVariables, localDir } = - getAdminConfig(); - const extraEnv = { ...opts.extraEnv, ...customEnvVariables }; - let cwd; - // istanbul ignore if - if (cwdFile) { - cwd = join(localDir, dirname(cwdFile)); - } - cwd = cwd || opts.cwd || localDir; - const childEnv = createChildEnv(env, extraEnv); +function getCwd({ cwd, cwdFile }: ExecOptions = {}): string { + const { localDir: defaultCwd } = getAdminConfig(); + const paramCwd = cwdFile ? join(defaultCwd, dirname(cwdFile)) : cwd; + return paramCwd || defaultCwd; +} +function getRawExecOptions(opts: ExecOptions): RawExecOptions { const execOptions: ExecOptions = { ...opts }; delete execOptions.extraEnv; delete execOptions.docker; delete execOptions.cwdFile; + const childEnv = getChildEnv(opts); + const cwd = getCwd(opts); const rawExecOptions: RawExecOptions = { encoding: 'utf-8', ...execOptions, @@ -96,31 +82,68 @@ export async function exec( rawExecOptions.timeout = rawExecOptions.timeout || 15 * 60 * 1000; // Set default max buffer size to 10MB rawExecOptions.maxBuffer = rawExecOptions.maxBuffer || 10 * 1024 * 1024; + return rawExecOptions; +} + +function isDocker({ docker }: ExecOptions): boolean { + const { binarySource } = getAdminConfig(); + return binarySource === 'docker' && !!docker; +} - let commands = typeof cmd === 'string' ? [cmd] : cmd; - const useDocker = binarySource === 'docker' && docker; - if (useDocker) { +interface RawExecArguments { + rawCommands: string[]; + rawOptions: RawExecOptions; +} + +async function prepareRawExec( + cmd: string | string[], + opts: ExecOptions = {} +): Promise { + const { docker } = opts; + const { customEnvVariables } = getAdminConfig(); + + const rawOptions = getRawExecOptions(opts); + + let rawCommands = typeof cmd === 'string' ? [cmd] : cmd; + + if (isDocker(opts)) { logger.debug('Using docker to execute'); - const dockerOptions = { - ...docker, - cwd, - envVars: dockerEnvVars(extraEnv, childEnv), - }; - - const dockerCommand = await generateDockerCommand(commands, dockerOptions); - commands = [dockerCommand]; + const extraEnv = { ...opts.extraEnv, ...customEnvVariables }; + const childEnv = getChildEnv(opts); + const envVars = dockerEnvVars(extraEnv, childEnv); + const cwd = getCwd(); + const dockerOptions: DockerOptions = { ...docker, cwd, envVars }; + + const dockerCommand = await generateDockerCommand( + rawCommands, + dockerOptions + ); + rawCommands = [dockerCommand]; } + return { rawCommands, rawOptions }; +} + +export async function exec( + cmd: string | string[], + opts: ExecOptions = {} +): Promise { + const { docker } = opts; + const { dockerChildPrefix } = getAdminConfig(); + + const { rawCommands, rawOptions } = await prepareRawExec(cmd, opts); + const useDocker = isDocker(opts); + let res: ExecResult | null = null; - for (const rawExecCommand of commands) { + for (const rawCmd of rawCommands) { const startTime = Date.now(); if (useDocker) { await removeDockerContainer(docker.image, dockerChildPrefix); } - logger.debug({ command: rawExecCommand }, 'Executing command'); - logger.trace({ commandOptions: rawExecOptions }, 'Command options'); + logger.debug({ command: rawCommands }, 'Executing command'); + logger.trace({ commandOptions: rawOptions }, 'Command options'); try { - res = await rawExec(rawExecCommand, rawExecOptions); + res = await rawExec(rawCmd, rawOptions); } catch (err) { logger.debug({ err }, 'rawExec err'); if (useDocker) { @@ -146,7 +169,7 @@ export async function exec( if (res) { logger.debug( { - cmd: rawExecCommand, + cmd: rawCmd, durationMs, stdout: res.stdout, stderr: res.stderr,