Skip to content

Commit

Permalink
refactor: Split exec function to smaller blocks (#11093)
Browse files Browse the repository at this point in the history
  • Loading branch information
zharinov committed Aug 12, 2021
1 parent 9a3ffe1 commit 64754e6
Show file tree
Hide file tree
Showing 3 changed files with 85 additions and 62 deletions.
@@ -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",
Expand Down
File renamed without changes.
145 changes: 84 additions & 61 deletions lib/util/exec/index.ts
Expand Up @@ -21,38 +21,31 @@ export interface ExecOptions extends ChildProcessExecOptions {
docker?: Opt<DockerOptions>;
}

function createChildEnv(
env: NodeJS.ProcessEnv,
extraEnv: ExtraEnv
): ExtraEnv<string> {
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<string> {
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<string> = {};
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(
Expand All @@ -65,27 +58,20 @@ function dockerEnvVars(
);
}

export async function exec(
cmd: string | string[],
opts: ExecOptions = {}
): Promise<ExecResult> {
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,
Expand All @@ -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<RawExecArguments> {
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<ExecResult> {
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) {
Expand All @@ -146,7 +169,7 @@ export async function exec(
if (res) {
logger.debug(
{
cmd: rawExecCommand,
cmd: rawCmd,
durationMs,
stdout: res.stdout,
stderr: res.stderr,
Expand Down

0 comments on commit 64754e6

Please sign in to comment.