@theia/process 1.53.0-next.55 → 1.53.0-next.64
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +30 -30
- package/lib/common/shell-command-builder.slow-spec.js +4 -4
- package/package.json +3 -3
- package/src/common/process-common-module.ts +22 -22
- package/src/common/process-manager-types.ts +58 -58
- package/src/common/shell-command-builder.slow-spec.ts +486 -486
- package/src/common/shell-command-builder.ts +187 -187
- package/src/common/shell-quoting.spec.ts +176 -176
- package/src/common/shell-quoting.ts +236 -236
- package/src/common/tests/$weird(),file=name.js +1 -1
- package/src/common/tests/white space.js +1 -1
- package/src/node/dev-null-stream.ts +47 -47
- package/src/node/index.ts +22 -22
- package/src/node/multi-ring-buffer.spec.ts +486 -486
- package/src/node/multi-ring-buffer.ts +348 -348
- package/src/node/process-backend-module.ts +67 -67
- package/src/node/process-manager.ts +107 -107
- package/src/node/process.ts +207 -207
- package/src/node/pseudo-pty.ts +56 -56
- package/src/node/raw-process.spec.ts +199 -199
- package/src/node/raw-process.ts +156 -156
- package/src/node/string-argv.d.ts +21 -21
- package/src/node/task-terminal-process.ts +41 -41
- package/src/node/terminal-process.spec.ts +121 -121
- package/src/node/terminal-process.ts +290 -290
- package/src/node/test/process-fork-test.js +22 -22
- package/src/node/test/process-test-container.ts +27 -27
- package/src/node/utils.ts +79 -79
|
@@ -1,199 +1,199 @@
|
|
|
1
|
-
// *****************************************************************************
|
|
2
|
-
// Copyright (C) 2017 Ericsson and others.
|
|
3
|
-
//
|
|
4
|
-
// This program and the accompanying materials are made available under the
|
|
5
|
-
// terms of the Eclipse Public License v. 2.0 which is available at
|
|
6
|
-
// http://www.eclipse.org/legal/epl-2.0.
|
|
7
|
-
//
|
|
8
|
-
// This Source Code may also be made available under the following Secondary
|
|
9
|
-
// Licenses when the conditions for such availability set forth in the Eclipse
|
|
10
|
-
// Public License v. 2.0 are satisfied: GNU General Public License, version 2
|
|
11
|
-
// with the GNU Classpath Exception which is available at
|
|
12
|
-
// https://www.gnu.org/software/classpath/license.html.
|
|
13
|
-
//
|
|
14
|
-
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
|
|
15
|
-
// *****************************************************************************
|
|
16
|
-
import * as chai from 'chai';
|
|
17
|
-
import * as process from 'process';
|
|
18
|
-
import * as stream from 'stream';
|
|
19
|
-
import { createProcessTestContainer } from './test/process-test-container';
|
|
20
|
-
import { RawProcessFactory } from './raw-process';
|
|
21
|
-
import * as temp from 'temp';
|
|
22
|
-
import * as fs from 'fs';
|
|
23
|
-
import * as path from 'path';
|
|
24
|
-
import { isWindows } from '@theia/core';
|
|
25
|
-
import { IProcessStartEvent, ProcessErrorEvent } from './process';
|
|
26
|
-
|
|
27
|
-
/* Allow to create temporary files, but delete them when we're done. */
|
|
28
|
-
const track = temp.track();
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* Globals
|
|
32
|
-
*/
|
|
33
|
-
|
|
34
|
-
const expect = chai.expect;
|
|
35
|
-
const FORK_TEST_FILE = path.join(__dirname, '../../src/node/test/process-fork-test.js');
|
|
36
|
-
|
|
37
|
-
describe('RawProcess', function (): void {
|
|
38
|
-
|
|
39
|
-
this.timeout(20_000);
|
|
40
|
-
|
|
41
|
-
let rawProcessFactory: RawProcessFactory;
|
|
42
|
-
|
|
43
|
-
beforeEach(() => {
|
|
44
|
-
rawProcessFactory = createProcessTestContainer().get<RawProcessFactory>(RawProcessFactory);
|
|
45
|
-
});
|
|
46
|
-
|
|
47
|
-
after(() => {
|
|
48
|
-
track.cleanupSync();
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
it('test error on non-existent path', async function (): Promise<void> {
|
|
52
|
-
const error = await new Promise<ProcessErrorEvent>((resolve, reject) => {
|
|
53
|
-
const proc = rawProcessFactory({ command: '/non-existent' });
|
|
54
|
-
proc.onStart(reject);
|
|
55
|
-
proc.onError(resolve);
|
|
56
|
-
proc.onExit(reject);
|
|
57
|
-
});
|
|
58
|
-
|
|
59
|
-
expect(error.code).eq('ENOENT');
|
|
60
|
-
});
|
|
61
|
-
|
|
62
|
-
it('test error on non-executable path', async function (): Promise<void> {
|
|
63
|
-
// Create a non-executable file.
|
|
64
|
-
const f = track.openSync('non-executable');
|
|
65
|
-
fs.writeSync(f.fd, 'echo bob');
|
|
66
|
-
|
|
67
|
-
// Make really sure it's non-executable.
|
|
68
|
-
let mode = fs.fstatSync(f.fd).mode;
|
|
69
|
-
mode &= ~fs.constants.S_IXUSR;
|
|
70
|
-
mode &= ~fs.constants.S_IXGRP;
|
|
71
|
-
mode &= ~fs.constants.S_IXOTH;
|
|
72
|
-
fs.fchmodSync(f.fd, mode);
|
|
73
|
-
|
|
74
|
-
fs.closeSync(f.fd);
|
|
75
|
-
|
|
76
|
-
const error = await new Promise<ProcessErrorEvent>((resolve, reject) => {
|
|
77
|
-
const proc = rawProcessFactory({ command: f.path });
|
|
78
|
-
proc.onStart(reject);
|
|
79
|
-
proc.onError(resolve);
|
|
80
|
-
proc.onExit(reject);
|
|
81
|
-
});
|
|
82
|
-
|
|
83
|
-
// On Windows, we get 'UNKNOWN'.
|
|
84
|
-
const expectedCode = isWindows ? 'UNKNOWN' : 'EACCES';
|
|
85
|
-
|
|
86
|
-
expect(error.code).eq(expectedCode);
|
|
87
|
-
});
|
|
88
|
-
|
|
89
|
-
it('test start event', function (): Promise<IProcessStartEvent> {
|
|
90
|
-
return new Promise<IProcessStartEvent>(async (resolve, reject) => {
|
|
91
|
-
const args = ['-e', 'process.exit(3)'];
|
|
92
|
-
const rawProcess = rawProcessFactory({ command: process.execPath, 'args': args });
|
|
93
|
-
rawProcess.onStart(resolve);
|
|
94
|
-
rawProcess.onError(reject);
|
|
95
|
-
rawProcess.onExit(reject);
|
|
96
|
-
});
|
|
97
|
-
});
|
|
98
|
-
|
|
99
|
-
it('test exit', async function (): Promise<void> {
|
|
100
|
-
const args = ['--version'];
|
|
101
|
-
const rawProcess = rawProcessFactory({ command: process.execPath, 'args': args });
|
|
102
|
-
const p = new Promise<number>((resolve, reject) => {
|
|
103
|
-
rawProcess.onError(reject);
|
|
104
|
-
rawProcess.onExit(event => {
|
|
105
|
-
if (event.code === undefined) {
|
|
106
|
-
reject(new Error('event.code is undefined'));
|
|
107
|
-
} else {
|
|
108
|
-
resolve(event.code);
|
|
109
|
-
}
|
|
110
|
-
});
|
|
111
|
-
});
|
|
112
|
-
|
|
113
|
-
const exitCode = await p;
|
|
114
|
-
expect(exitCode).equal(0);
|
|
115
|
-
});
|
|
116
|
-
|
|
117
|
-
it('test pipe stdout stream', async function (): Promise<void> {
|
|
118
|
-
const output = await new Promise<string>(async (resolve, reject) => {
|
|
119
|
-
const args = ['-e', 'console.log("text to stdout")'];
|
|
120
|
-
const outStream = new stream.PassThrough();
|
|
121
|
-
const rawProcess = rawProcessFactory({ command: process.execPath, 'args': args });
|
|
122
|
-
rawProcess.onError(reject);
|
|
123
|
-
|
|
124
|
-
rawProcess.outputStream.pipe(outStream);
|
|
125
|
-
|
|
126
|
-
let buf = '';
|
|
127
|
-
outStream.on('data', data => {
|
|
128
|
-
buf += data.toString();
|
|
129
|
-
});
|
|
130
|
-
outStream.on('end', () => {
|
|
131
|
-
resolve(buf.trim());
|
|
132
|
-
});
|
|
133
|
-
});
|
|
134
|
-
|
|
135
|
-
expect(output).to.be.equal('text to stdout');
|
|
136
|
-
});
|
|
137
|
-
|
|
138
|
-
it('test pipe stderr stream', async function (): Promise<void> {
|
|
139
|
-
const output = await new Promise<string>(async (resolve, reject) => {
|
|
140
|
-
const args = ['-e', 'console.error("text to stderr")'];
|
|
141
|
-
const outStream = new stream.PassThrough();
|
|
142
|
-
const rawProcess = rawProcessFactory({ command: process.execPath, 'args': args });
|
|
143
|
-
rawProcess.onError(reject);
|
|
144
|
-
|
|
145
|
-
rawProcess.errorStream.pipe(outStream);
|
|
146
|
-
|
|
147
|
-
let buf = '';
|
|
148
|
-
outStream.on('data', data => {
|
|
149
|
-
buf += data.toString();
|
|
150
|
-
});
|
|
151
|
-
outStream.on('end', () => {
|
|
152
|
-
resolve(buf.trim());
|
|
153
|
-
});
|
|
154
|
-
});
|
|
155
|
-
|
|
156
|
-
expect(output).to.be.equal('text to stderr');
|
|
157
|
-
});
|
|
158
|
-
|
|
159
|
-
it('test forked pipe stdout stream', async function (): Promise<void> {
|
|
160
|
-
const args = ['version'];
|
|
161
|
-
const rawProcess = rawProcessFactory({ modulePath: FORK_TEST_FILE, args, options: { stdio: 'pipe' } });
|
|
162
|
-
|
|
163
|
-
const outStream = new stream.PassThrough();
|
|
164
|
-
|
|
165
|
-
const p = new Promise<string>((resolve, reject) => {
|
|
166
|
-
let version = '';
|
|
167
|
-
outStream.on('data', data => {
|
|
168
|
-
version += data.toString();
|
|
169
|
-
});
|
|
170
|
-
outStream.on('end', () => {
|
|
171
|
-
resolve(version.trim());
|
|
172
|
-
});
|
|
173
|
-
});
|
|
174
|
-
|
|
175
|
-
rawProcess.outputStream.pipe(outStream);
|
|
176
|
-
|
|
177
|
-
expect(await p).to.be.equal('1.0.0');
|
|
178
|
-
});
|
|
179
|
-
|
|
180
|
-
it('test forked pipe stderr stream', async function (): Promise<void> {
|
|
181
|
-
const rawProcess = rawProcessFactory({ modulePath: FORK_TEST_FILE, args: [], options: { stdio: 'pipe' } });
|
|
182
|
-
|
|
183
|
-
const outStream = new stream.PassThrough();
|
|
184
|
-
|
|
185
|
-
const p = new Promise<string>((resolve, reject) => {
|
|
186
|
-
let version = '';
|
|
187
|
-
outStream.on('data', data => {
|
|
188
|
-
version += data.toString();
|
|
189
|
-
});
|
|
190
|
-
outStream.on('end', () => {
|
|
191
|
-
resolve(version.trim());
|
|
192
|
-
});
|
|
193
|
-
});
|
|
194
|
-
|
|
195
|
-
rawProcess.errorStream.pipe(outStream);
|
|
196
|
-
|
|
197
|
-
expect(await p).to.have.string('Error');
|
|
198
|
-
});
|
|
199
|
-
});
|
|
1
|
+
// *****************************************************************************
|
|
2
|
+
// Copyright (C) 2017 Ericsson and others.
|
|
3
|
+
//
|
|
4
|
+
// This program and the accompanying materials are made available under the
|
|
5
|
+
// terms of the Eclipse Public License v. 2.0 which is available at
|
|
6
|
+
// http://www.eclipse.org/legal/epl-2.0.
|
|
7
|
+
//
|
|
8
|
+
// This Source Code may also be made available under the following Secondary
|
|
9
|
+
// Licenses when the conditions for such availability set forth in the Eclipse
|
|
10
|
+
// Public License v. 2.0 are satisfied: GNU General Public License, version 2
|
|
11
|
+
// with the GNU Classpath Exception which is available at
|
|
12
|
+
// https://www.gnu.org/software/classpath/license.html.
|
|
13
|
+
//
|
|
14
|
+
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
|
|
15
|
+
// *****************************************************************************
|
|
16
|
+
import * as chai from 'chai';
|
|
17
|
+
import * as process from 'process';
|
|
18
|
+
import * as stream from 'stream';
|
|
19
|
+
import { createProcessTestContainer } from './test/process-test-container';
|
|
20
|
+
import { RawProcessFactory } from './raw-process';
|
|
21
|
+
import * as temp from 'temp';
|
|
22
|
+
import * as fs from 'fs';
|
|
23
|
+
import * as path from 'path';
|
|
24
|
+
import { isWindows } from '@theia/core';
|
|
25
|
+
import { IProcessStartEvent, ProcessErrorEvent } from './process';
|
|
26
|
+
|
|
27
|
+
/* Allow to create temporary files, but delete them when we're done. */
|
|
28
|
+
const track = temp.track();
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Globals
|
|
32
|
+
*/
|
|
33
|
+
|
|
34
|
+
const expect = chai.expect;
|
|
35
|
+
const FORK_TEST_FILE = path.join(__dirname, '../../src/node/test/process-fork-test.js');
|
|
36
|
+
|
|
37
|
+
describe('RawProcess', function (): void {
|
|
38
|
+
|
|
39
|
+
this.timeout(20_000);
|
|
40
|
+
|
|
41
|
+
let rawProcessFactory: RawProcessFactory;
|
|
42
|
+
|
|
43
|
+
beforeEach(() => {
|
|
44
|
+
rawProcessFactory = createProcessTestContainer().get<RawProcessFactory>(RawProcessFactory);
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
after(() => {
|
|
48
|
+
track.cleanupSync();
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
it('test error on non-existent path', async function (): Promise<void> {
|
|
52
|
+
const error = await new Promise<ProcessErrorEvent>((resolve, reject) => {
|
|
53
|
+
const proc = rawProcessFactory({ command: '/non-existent' });
|
|
54
|
+
proc.onStart(reject);
|
|
55
|
+
proc.onError(resolve);
|
|
56
|
+
proc.onExit(reject);
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
expect(error.code).eq('ENOENT');
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
it('test error on non-executable path', async function (): Promise<void> {
|
|
63
|
+
// Create a non-executable file.
|
|
64
|
+
const f = track.openSync('non-executable');
|
|
65
|
+
fs.writeSync(f.fd, 'echo bob');
|
|
66
|
+
|
|
67
|
+
// Make really sure it's non-executable.
|
|
68
|
+
let mode = fs.fstatSync(f.fd).mode;
|
|
69
|
+
mode &= ~fs.constants.S_IXUSR;
|
|
70
|
+
mode &= ~fs.constants.S_IXGRP;
|
|
71
|
+
mode &= ~fs.constants.S_IXOTH;
|
|
72
|
+
fs.fchmodSync(f.fd, mode);
|
|
73
|
+
|
|
74
|
+
fs.closeSync(f.fd);
|
|
75
|
+
|
|
76
|
+
const error = await new Promise<ProcessErrorEvent>((resolve, reject) => {
|
|
77
|
+
const proc = rawProcessFactory({ command: f.path });
|
|
78
|
+
proc.onStart(reject);
|
|
79
|
+
proc.onError(resolve);
|
|
80
|
+
proc.onExit(reject);
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
// On Windows, we get 'UNKNOWN'.
|
|
84
|
+
const expectedCode = isWindows ? 'UNKNOWN' : 'EACCES';
|
|
85
|
+
|
|
86
|
+
expect(error.code).eq(expectedCode);
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
it('test start event', function (): Promise<IProcessStartEvent> {
|
|
90
|
+
return new Promise<IProcessStartEvent>(async (resolve, reject) => {
|
|
91
|
+
const args = ['-e', 'process.exit(3)'];
|
|
92
|
+
const rawProcess = rawProcessFactory({ command: process.execPath, 'args': args });
|
|
93
|
+
rawProcess.onStart(resolve);
|
|
94
|
+
rawProcess.onError(reject);
|
|
95
|
+
rawProcess.onExit(reject);
|
|
96
|
+
});
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
it('test exit', async function (): Promise<void> {
|
|
100
|
+
const args = ['--version'];
|
|
101
|
+
const rawProcess = rawProcessFactory({ command: process.execPath, 'args': args });
|
|
102
|
+
const p = new Promise<number>((resolve, reject) => {
|
|
103
|
+
rawProcess.onError(reject);
|
|
104
|
+
rawProcess.onExit(event => {
|
|
105
|
+
if (event.code === undefined) {
|
|
106
|
+
reject(new Error('event.code is undefined'));
|
|
107
|
+
} else {
|
|
108
|
+
resolve(event.code);
|
|
109
|
+
}
|
|
110
|
+
});
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
const exitCode = await p;
|
|
114
|
+
expect(exitCode).equal(0);
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
it('test pipe stdout stream', async function (): Promise<void> {
|
|
118
|
+
const output = await new Promise<string>(async (resolve, reject) => {
|
|
119
|
+
const args = ['-e', 'console.log("text to stdout")'];
|
|
120
|
+
const outStream = new stream.PassThrough();
|
|
121
|
+
const rawProcess = rawProcessFactory({ command: process.execPath, 'args': args });
|
|
122
|
+
rawProcess.onError(reject);
|
|
123
|
+
|
|
124
|
+
rawProcess.outputStream.pipe(outStream);
|
|
125
|
+
|
|
126
|
+
let buf = '';
|
|
127
|
+
outStream.on('data', data => {
|
|
128
|
+
buf += data.toString();
|
|
129
|
+
});
|
|
130
|
+
outStream.on('end', () => {
|
|
131
|
+
resolve(buf.trim());
|
|
132
|
+
});
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
expect(output).to.be.equal('text to stdout');
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
it('test pipe stderr stream', async function (): Promise<void> {
|
|
139
|
+
const output = await new Promise<string>(async (resolve, reject) => {
|
|
140
|
+
const args = ['-e', 'console.error("text to stderr")'];
|
|
141
|
+
const outStream = new stream.PassThrough();
|
|
142
|
+
const rawProcess = rawProcessFactory({ command: process.execPath, 'args': args });
|
|
143
|
+
rawProcess.onError(reject);
|
|
144
|
+
|
|
145
|
+
rawProcess.errorStream.pipe(outStream);
|
|
146
|
+
|
|
147
|
+
let buf = '';
|
|
148
|
+
outStream.on('data', data => {
|
|
149
|
+
buf += data.toString();
|
|
150
|
+
});
|
|
151
|
+
outStream.on('end', () => {
|
|
152
|
+
resolve(buf.trim());
|
|
153
|
+
});
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
expect(output).to.be.equal('text to stderr');
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
it('test forked pipe stdout stream', async function (): Promise<void> {
|
|
160
|
+
const args = ['version'];
|
|
161
|
+
const rawProcess = rawProcessFactory({ modulePath: FORK_TEST_FILE, args, options: { stdio: 'pipe' } });
|
|
162
|
+
|
|
163
|
+
const outStream = new stream.PassThrough();
|
|
164
|
+
|
|
165
|
+
const p = new Promise<string>((resolve, reject) => {
|
|
166
|
+
let version = '';
|
|
167
|
+
outStream.on('data', data => {
|
|
168
|
+
version += data.toString();
|
|
169
|
+
});
|
|
170
|
+
outStream.on('end', () => {
|
|
171
|
+
resolve(version.trim());
|
|
172
|
+
});
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
rawProcess.outputStream.pipe(outStream);
|
|
176
|
+
|
|
177
|
+
expect(await p).to.be.equal('1.0.0');
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
it('test forked pipe stderr stream', async function (): Promise<void> {
|
|
181
|
+
const rawProcess = rawProcessFactory({ modulePath: FORK_TEST_FILE, args: [], options: { stdio: 'pipe' } });
|
|
182
|
+
|
|
183
|
+
const outStream = new stream.PassThrough();
|
|
184
|
+
|
|
185
|
+
const p = new Promise<string>((resolve, reject) => {
|
|
186
|
+
let version = '';
|
|
187
|
+
outStream.on('data', data => {
|
|
188
|
+
version += data.toString();
|
|
189
|
+
});
|
|
190
|
+
outStream.on('end', () => {
|
|
191
|
+
resolve(version.trim());
|
|
192
|
+
});
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
rawProcess.errorStream.pipe(outStream);
|
|
196
|
+
|
|
197
|
+
expect(await p).to.have.string('Error');
|
|
198
|
+
});
|
|
199
|
+
});
|