1+ import * as path from 'path' ;
2+ import * as os from 'os' ;
3+ import * as cp from 'child_process' ;
4+
15import * as vscode from 'vscode' ;
2- import { languages } from 'vscode' ;
6+
37import * as utils from './utils' ;
48import { Log as logger } from './logger' ;
59import { getWellKnownBuiltinContribs } from './constants' ;
6- import { Configuration , getWorkspaceFolder , VsCodeSettings } from './configuration' ;
10+ import { Configuration ,
11+ getWorkspaceFolder ,
12+ VsCodeSettings } from './configuration' ;
713import { PghhError } from './error' ;
8- import * as path from 'path' ;
9- import * as os from 'os' ;
1014
1115class 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+
1376function 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
531594export 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 ) ;
0 commit comments