Skip to content

Commit 07f0353

Browse files
committed
refactor: move execShell to formatter.ts as only this modules uses it
1 parent 7522eb8 commit 07f0353

File tree

3 files changed

+82
-99
lines changed

3 files changed

+82
-99
lines changed

src/formatter.ts

Lines changed: 77 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,78 @@
1+
import * as path from 'path';
2+
import * as os from 'os';
3+
import * as cp from 'child_process';
4+
15
import * as vscode from 'vscode';
2-
import {languages} from 'vscode';
6+
37
import * as utils from './utils';
48
import { Log as logger } from './logger';
59
import { getWellKnownBuiltinContribs } from './constants';
6-
import { Configuration, getWorkspaceFolder, VsCodeSettings } from './configuration';
10+
import { Configuration,
11+
getWorkspaceFolder,
12+
VsCodeSettings } from './configuration';
713
import { PghhError } from './error';
8-
import * as path from 'path';
9-
import * as os from 'os';
1014

1115
class FormattingError extends PghhError {}
1216

17+
class ShellExecError extends PghhError {
18+
constructor(public command: string,
19+
public stderr: string,
20+
public stdout: string,
21+
public code: number) {
22+
super(`command "${command}" failed to execute: ${stderr}`);
23+
}
24+
}
25+
26+
interface ShellExecResult {
27+
code: number,
28+
stdout: string,
29+
stderr: string,
30+
};
31+
32+
async function execShell(cmd: string, args?: string[],
33+
cwd?: string): Promise<ShellExecResult> {
34+
return await new Promise<ShellExecResult>((resolve, reject) => {
35+
const child = cp.spawn(cmd, args, {cwd, shell: true});
36+
const stderr: string[] = [];
37+
const stdout: string[] = [];
38+
39+
child.on('error', (err) => {
40+
reject(err);
41+
});
42+
43+
child.stderr?.on('data', (chunk) => {
44+
stderr.push(chunk);
45+
});
46+
child.stdout?.on('data', (chunk) => {
47+
stdout.push(chunk);
48+
});
49+
50+
child.on('close', (code) => {
51+
if (code !== 0) {
52+
const command = `${cmd} ${args?.join(' ')}`;
53+
reject(new ShellExecError(command, stderr.join(''), stdout.join(''), code ?? 1));
54+
} else {
55+
resolve({
56+
code: code ?? 0,
57+
stdout: stdout.join(''),
58+
stderr: stderr.join(''),
59+
});
60+
}
61+
});
62+
child.on('error', (err) => {
63+
reject(err);
64+
});
65+
66+
child.stdin.end();
67+
68+
setTimeout(() => {
69+
if (child.exitCode !== null) {
70+
child.kill('SIGKILL');
71+
}
72+
}, 300 * 1000 /* 5 minutes */);
73+
});
74+
}
75+
1376
function isBuiltinContrib(name: string) {
1477
return getWellKnownBuiltinContribs().has(name);
1578
}
@@ -107,9 +170,9 @@ export class PgindentDocumentFormatterProvider implements vscode.DocumentFormatt
107170
workspace, 'src', 'tools', 'pgindent');
108171
logger.info('cloning pg_bsd_indent repository');
109172
/* XXX: maybe better to download archive, not full history? */
110-
await utils.execShell(
173+
await execShell(
111174
'git', ['clone', 'https://git.postgresql.org/git/pg_bsd_indent.git'],
112-
{cwd: pgindentDir.fsPath});
175+
pgindentDir.fsPath);
113176

114177
/*
115178
* Each pgindent requires specific version of pg_bsd_indent and
@@ -193,8 +256,8 @@ export class PgindentDocumentFormatterProvider implements vscode.DocumentFormatt
193256

194257
/* Try to build it */
195258
logger.info('building pg_bsd_indent in %s', pgBsdIndentDir.fsPath);
196-
await utils.execShell('make', ['-C', pgBsdIndentDir.fsPath],
197-
{cwd: workspace.fsPath});
259+
await execShell('make', ['-C', pgBsdIndentDir.fsPath],
260+
workspace.fsPath);
198261
return pgBsdIndent;
199262
}
200263

@@ -216,9 +279,9 @@ export class PgindentDocumentFormatterProvider implements vscode.DocumentFormatt
216279

217280
logger.info('building pg_bsd_indent');
218281
/* Repo's version requires passing PG_CONFIG (just build, no 'install') */
219-
await utils.execShell(
282+
await execShell(
220283
'make', ['all', `PG_CONFIG="${pgConfigPath.fsPath}"`],
221-
{cwd: pgBsdIndentDir.fsPath});
284+
pgBsdIndentDir.fsPath);
222285
return pgBsdIndent;
223286
}
224287

@@ -355,16 +418,16 @@ export class PgindentDocumentFormatterProvider implements vscode.DocumentFormatt
355418
/* Work in pgindent dir, so it can find default typedefs.list */
356419
const cwd = path.resolve(pgindent.fsPath, '..');
357420
try {
358-
await utils.execShell(
421+
await execShell(
359422
pgindent.fsPath, [
360423
...typedefs,
361424
`--indent=${pg_bsd_indent.fsPath}`,
362425
document.fsPath,
363426
],
364-
{cwd},
427+
cwd,
365428
);
366429
} catch (err) {
367-
if (!(err instanceof utils.ShellExecError)) {
430+
if (!(err instanceof ShellExecError)) {
368431
throw err;
369432
}
370433

@@ -530,7 +593,7 @@ export async function showFormatterDiffCommand(formatter: PgindentDocumentFormat
530593

531594
export function setupFormatting(context: vscode.ExtensionContext, config: Configuration) {
532595
const formatter = new PgindentDocumentFormatterProvider(config);
533-
const d = languages.registerDocumentFormattingEditProvider({
596+
const d = vscode.languages.registerDocumentFormattingEditProvider({
534597
language: 'c',
535598
}, formatter);
536599
context.subscriptions.push(d);

src/test/suite/formatting.test.ts

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
11
import * as assert from 'assert';
22
import * as fs from 'fs';
3+
import * as cp from 'child_process';
34
import * as path from 'path';
45
import * as vscode from 'vscode';
56

67
import { getTestEnv, TestEnv } from './env';
78

8-
import * as utils from '../../utils';
9-
109
function getFormattedFile(env: TestEnv) {
1110
const path = env.getExtensionPath('src', 'test', 'patches', 'formatted.c');
1211

@@ -26,9 +25,9 @@ suite('Formatting', async function () {
2625
let env: TestEnv;
2726
let expected: string;
2827
suiteSetup(async () => {
29-
const swallow = async (fn: () => Promise<void>) => {
28+
const swallow = async (fn: () => void) => {
3029
try {
31-
await fn();
30+
fn();
3231
} catch {
3332
/* skip */
3433
}
@@ -42,14 +41,11 @@ suite('Formatting', async function () {
4241
});
4342

4443
/* Clean already built pg_bsd_indent */
45-
await swallow(async () => {
44+
swallow(() => {
4645
const pgBsdIndentDir = env.getWorkspaceFile('src', 'tools', 'pg_bsd_indent');
4746
const pgBsdIndent = path.join(pgBsdIndentDir, 'pg_bsd_indent');
4847
if (fs.existsSync(pgBsdIndent)) {
49-
await utils.execShell(
50-
'make', ['clean'],
51-
{cwd: pgBsdIndentDir},
52-
);
48+
cp.spawnSync('make', ['clean'], {cwd: pgBsdIndent});
5349
}
5450
});
5551

src/utils.ts

Lines changed: 0 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
11
import * as vscode from 'vscode';
22
import * as path from 'path';
3-
import * as cp from 'child_process';
43
import * as https from 'https';
54
import * as os from 'os';
6-
import { PghhError } from './error';
75
import * as crypto from 'crypto';
86
import { VsCodeSettings } from './configuration';
97

@@ -74,80 +72,6 @@ export async function createTempFile(template: string, content: string) {
7472
return tempFile;
7573
}
7674

77-
export class ShellExecError extends PghhError {
78-
constructor(public command: string,
79-
public stderr: string,
80-
public stdout: string,
81-
public code: number) {
82-
super(`command "${command}" failed to execute: ${stderr}`);
83-
}
84-
}
85-
86-
interface ShellExecResult {
87-
code: number,
88-
stdout: string,
89-
stderr: string,
90-
};
91-
92-
export async function execShell(cmd: string, args?: string[],
93-
options?: { cwd?: string,
94-
throwOnError?: boolean,
95-
stdin?: string } ): Promise<ShellExecResult> {
96-
return await new Promise<ShellExecResult>((resolve, reject) => {
97-
const {cwd, throwOnError, stdin} = options || {};
98-
const child = cp.spawn(cmd, args, {cwd, shell: true});
99-
const stderr: string[] = [];
100-
const stdout: string[] = [];
101-
102-
child.on('error', (err) => {
103-
reject(err);
104-
});
105-
106-
child.stderr?.on('data', (chunk) => {
107-
stderr.push(chunk);
108-
});
109-
child.stdout?.on('data', (chunk) => {
110-
stdout.push(chunk);
111-
});
112-
113-
child.on('close', (code) => {
114-
if (code !== 0 && (throwOnError ?? true)) {
115-
const command = `${cmd} ${args?.join(' ')}`;
116-
reject(new ShellExecError(command, stderr.join(''), stdout.join(''), code ?? 1));
117-
} else {
118-
resolve({
119-
code: code ?? 0,
120-
stdout: stdout.join(''),
121-
stderr: stderr.join(''),
122-
});
123-
}
124-
});
125-
child.on('error', (err) => {
126-
reject(err);
127-
});
128-
129-
if (stdin) {
130-
child.stdin.write(stdin, (err) => {
131-
if (err) {
132-
reject(err);
133-
}
134-
});
135-
child.stdin.on('error', (err) => {
136-
if (err) {
137-
reject(err);
138-
}
139-
});
140-
}
141-
child.stdin.end();
142-
143-
setTimeout(() => {
144-
if (child.exitCode !== null) {
145-
child.kill('SIGKILL');
146-
}
147-
}, 60 * 1000);
148-
});
149-
}
150-
15175
export async function deleteFile(file: vscode.Uri) {
15276
await vscode.workspace.fs.delete(file, { useTrash: false });
15377
}

0 commit comments

Comments
 (0)