Skip to content

Commit

Permalink
fix(jsii-pacmak): retry .NET build a couple of times (#509)
Browse files Browse the repository at this point in the history
Try to survive NuGet's failing due to race conditions.
  • Loading branch information
rix0rrr authored May 22, 2019
1 parent 3d6415e commit d1ef618
Show file tree
Hide file tree
Showing 2 changed files with 55 additions and 27 deletions.
3 changes: 2 additions & 1 deletion packages/jsii-pacmak/lib/targets/dotnet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,10 +53,11 @@ export default class Dotnet extends Target {
const packageId: string = pkg.jsii.targets.dotnet.packageId;
const project: string = path.join(packageId, `${packageId}.csproj`);

// Add retry as NuGet on Ubuntu is prone to failing due to race conditions
await shell(
'dotnet',
[ 'build', project, '-c', 'Release' ],
{ cwd: sourceDir }
{ cwd: sourceDir, retry: true }
);

await this.copyFiles(
Expand Down
79 changes: 53 additions & 26 deletions packages/jsii-pacmak/lib/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,15 @@ import spec = require('jsii-spec');
import path = require('path');
import logging = require('./logging');

export interface ShellOptions extends SpawnOptions {
/**
* Retry execution up to 3 times if it fails
*
* @default false
*/
retry?: boolean;
}

/**
* Given an npm package directory and a dependency name, returns the package directory of the dep.
* @param packageDir the root of the package declaring the dependency.
Expand All @@ -15,33 +24,51 @@ export function resolveDependencyDirectory(packageDir: string, dependencyName: s
return path.dirname(require.resolve(`${dependencyName}/package.json`, { paths: lookupPaths }));
}

export function shell(cmd: string, args: string[], options: SpawnOptions): Promise<string> {
return new Promise<string>((resolve, reject) => {
logging.debug(cmd, args.join(' '), JSON.stringify(options));
const child = spawn(cmd, args, { ...options, shell: true, env: { ...process.env, ...options.env || {} }, stdio: ['ignore', 'pipe', 'pipe'] });
const stdout = new Array<Buffer>();
const stderr = new Array<Buffer>();
child.stdout.on('data', chunk => {
if (logging.level >= logging.LEVEL_VERBOSE) {
process.stderr.write(chunk); // notice - we emit all build output to stderr
}
stdout.push(Buffer.from(chunk));
});
child.stderr.on('data', chunk => {
if (logging.level >= logging.LEVEL_VERBOSE) {
process.stderr.write(chunk);
}
stderr.push(Buffer.from(chunk));
});
child.once('error', reject);
child.once('exit', (code, signal) => {
const out = Buffer.concat(stdout).toString('utf-8');
if (code === 0) { return resolve(out); }
const err = Buffer.concat(stderr).toString('utf-8');
if (code != null) { return reject(new Error(`Process exited with status ${code}\n${out}\n${err}`)); }
reject(new Error(`Process terminated by signal ${signal}\n${out}\n${err}`));
export async function shell(cmd: string, args: string[], options: ShellOptions): Promise<string> {
function spawn1() {
return new Promise<string>((resolve, reject) => {
logging.debug(cmd, args.join(' '), JSON.stringify(options));
const child = spawn(cmd, args, {
...options,
shell: true,
env: { ...process.env, ...options.env || {} },
stdio: ['ignore', 'pipe', 'pipe']
});
const stdout = new Array<Buffer>();
const stderr = new Array<Buffer>();
child.stdout.on('data', chunk => {
if (logging.level >= logging.LEVEL_VERBOSE) {
process.stderr.write(chunk); // notice - we emit all build output to stderr
}
stdout.push(Buffer.from(chunk));
});
child.stderr.on('data', chunk => {
if (logging.level >= logging.LEVEL_VERBOSE) {
process.stderr.write(chunk);
}
stderr.push(Buffer.from(chunk));
});
child.once('error', reject);
child.once('exit', (code, signal) => {
const out = Buffer.concat(stdout).toString('utf-8');
if (code === 0) { return resolve(out); }
const err = Buffer.concat(stderr).toString('utf-8');
if (code != null) { return reject(new Error(`Process exited with status ${code}\n${out}\n${err}`)); }
reject(new Error(`Process terminated by signal ${signal}\n${out}\n${err}`));
});
});
});
}

let attempts = options.retry ? 3 : 1;
while (true) {
attempts--;
try {
return spawn1();
} catch (e) {
if (attempts === 0) { throw e; }
logging.info(`${e.message} (retrying)`);
}
}
}

/**
Expand Down

0 comments on commit d1ef618

Please sign in to comment.