Skip to content

Commit

Permalink
[DOP-4033]: Add more comments
Browse files Browse the repository at this point in the history
  • Loading branch information
branberry committed Oct 11, 2023
1 parent 42753cf commit 6749b66
Show file tree
Hide file tree
Showing 3 changed files with 52 additions and 26 deletions.
5 changes: 2 additions & 3 deletions src/commands/src/helpers/dependency-helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,8 @@ async function createEnvProdFile(repoDir: string, projectName: string, baseUrl:
}
}

export async function getCliBuildDependencies(repoName: string, projectName: string, baseUrl: string) {
// before we get build dependencies, we need to clone
// the repo
export async function prepareBuildAndGetDependencies(repoName: string, projectName: string, baseUrl: string) {
// before we get build dependencies, we need to clone the repo
await cloneRepo(repoName);

const repoDir = getRepoDir(repoName);
Expand Down
69 changes: 48 additions & 21 deletions src/commands/src/helpers/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ const openAsync = promisify(fs.open);
const closeAsync = promisify(fs.close);
const existsAsync = promisify(fs.exists);

const EPIPE_CODE = 'EPIPE';
const EPIPE_ERRNO = -32;
const EPIPE_SYSCALL = 'write';

export class ExecuteCommandError extends Error {
data: unknown;
constructor(message: string, data: unknown) {
Expand All @@ -29,6 +33,17 @@ export interface CliCommandResponse {
errorText: string;
}

interface StdinError {
errno: number;
code: string;
syscall: string;
}
/**
* Method to replicate piping output from one command to another e.g. `yes | mut-publish public`
* @param {CliCommandParams} cmdFromParams The command we want to pipe output from to another command
* @param {CliCommandParams} cmdToParams The command that receives input from another command
* @returns {CliCommandResponse} The `CliCommandResponse` from the cmdTo command
*/
export async function executeAndPipeCommands(
cmdFromParams: CliCommandParams,
cmdToParams: CliCommandParams
Expand All @@ -40,29 +55,41 @@ export async function executeAndPipeCommands(
const cmdTo = spawn(cmdToParams.command, cmdToParams.args || [], cmdToParams.options || {});

cmdFrom.stdout?.on('data', (data: Buffer) => {
// For some commands, the command that is being written to
// will end before the first command finishes. In some cases,
// we do want this to happen. For example, the cli command `yes` will
// infinitely output yes to the terminal as a way of automatically responding
// to prompts from the subsequent command. Once the second command completes,
// we don't want `yes` to continue to run, so we kill the command.
if (!cmdTo.stdin?.writable) {
cmdFrom.stdin?.end();
cmdFrom.kill();
return;
}

// this is where we pipe data from the first command to the second command.
cmdTo.stdin?.write(data);
});

cmdFrom.stdout?.on('error', (err) => {
console.log('error on cmdFrom out', err);
});
cmdTo.stdin?.on('error', (err: StdinError) => {
// the error event for the cmdTo stdin gets called whenever it closes prematurely,
// but this is expected in certain situations e.g. when using the `yes` command.
// If this condition is met, we know that this expected, and ignore it otherwise we throw.
// If we don't check, we get an unhandled error exception.
if (err.code === EPIPE_CODE && err.syscall === EPIPE_SYSCALL && err.errno === EPIPE_ERRNO) {
console.log('stdin done');
return;
}

cmdTo.stdin?.on('finish', () => {
console.log('finished stdin');
reject(new ExecuteCommandError('The first command stdin (cmdTo) failed', err));
hasRejected = true;
});

cmdTo.stdin?.on('error', () => {
console.log('stdin done');
cmdFrom.stdout?.on('error', (err) => {
console.log('error on cmdFrom out', err);
});

cmdFrom.on('error', (err) => {
reject(new ExecuteCommandError('The first command failed', err));
reject(new ExecuteCommandError('The first command (cmdTo) failed', err));
hasRejected = true;
});

Expand Down Expand Up @@ -100,7 +127,7 @@ export async function executeAndPipeCommands(
console.error('error', errorText.join());
}

reject(new ExecuteCommandError('The command failed', exitCode));
reject(new ExecuteCommandError('The command failed', { exitCode, outputText, errorText }));
return;
}

Expand All @@ -114,16 +141,16 @@ export async function executeAndPipeCommands(

/**
* A promisified way to execute CLI commands. This approach uses spawn instead of exec, which
* is a safer way of executing CLI commands. Also, spawn allows us to stream output in real-time.
* @param {string} command: The CLI command we want to execute
* @param {string[] | undefined} args: Arguments we want to provide to the command
* @param {SpawnOptions | undefined} options: Options to configure the spawn process
* @param {fs.WriteStream | undefined} writeStream: A writable stream object to pipe output to.
* For example, we can mimic ls >> directory.txt by creating a WriteStream object to write to
* directory.txt, and then provide the WriteStream so that we can pipe the output from the ls
* command to the WriteStream.
* @returns {Promise<CliCommandResponse>} An object containing the CLI output from stdout and stderr.
* stdout is the outputText property, and stderr is the errorText property.
* is a safer way of executing CLI commands. Also, spawn allows us to stream input and output in real-time.
* @param {string} command The CLI command we want to execute
* @param {string[] | undefined} args Arguments we want to provide to the command
* @param {SpawnOptions | undefined} options Options to configure the spawn function
* @param {fs.WriteStream | undefined} writeStream A writable stream object to pipe output to.
* For example, we can `mimic ls >> directory.txt` by creating a `WriteStream` object to write to
* `directory.txt`, and then provide the `WriteStream` so that we can pipe the output from the `ls`
* command to the `WriteStream`.
* @returns {Promise<CliCommandResponse>} An object containing the CLI output from `stdout` and `stderr`.
* stdout is the `outputText` property, and `stderr` is the `errorText` property.
*/
export async function executeCliCommand({
command,
Expand Down Expand Up @@ -228,7 +255,7 @@ export async function getPatchId(repoDir: string): Promise<string | undefined> {
}

export async function getCommitBranch(repoDir: string): Promise<string> {
// equivalent to git rev-parse --short HEAD
// equivalent to git rev-parse --abbrev-ref HEAD
const response = await executeCliCommand({
command: 'git',
args: ['rev-parse', '--abbrev-ref', 'HEAD'],
Expand Down
4 changes: 2 additions & 2 deletions src/entrypoints/localApp.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { nextGenParse } from '../commands/src/shared/next-gen-parse';
import { nextGenHtml } from '../commands/src/shared/next-gen-html';
import { getCliBuildDependencies } from '../commands/src/helpers/dependency-helpers';
import { prepareBuildAndGetDependencies } from '../commands/src/helpers/dependency-helpers';
import { nextGenStage } from '../commands/src/shared/next-gen-stage';
import { oasPageBuild } from '../commands/src/shared/oas-page-build';
import { persistenceModule } from '../commands/src/shared/persistence-module';
Expand All @@ -14,7 +14,7 @@ async function localApp() {
const bucket = 'docs-java-dotcomstg';
const mutPrefix = 'docs/drivers/java/sync';

const { commitHash, patchId, bundlePath, commitBranch, hasRedirects, repoDir } = await getCliBuildDependencies(
const { commitHash, patchId, bundlePath, commitBranch, hasRedirects, repoDir } = await prepareBuildAndGetDependencies(
repoName,
projectName,
baseUrl
Expand Down

0 comments on commit 6749b66

Please sign in to comment.