7
7
import { expect } from 'chai' ;
8
8
import { exec } from 'child_process' ;
9
9
import * as path from 'path' ;
10
+ import { promisify } from 'util' ;
10
11
import { Uri } from 'vscode' ;
11
12
import '../../../client/common/extensions' ;
12
13
import { createDeferredFromPromise , Deferred } from '../../../client/common/utils/async' ;
@@ -24,16 +25,66 @@ import { IS_MULTI_ROOT_TEST } from '../../constants';
24
25
import { sleep } from '../../core' ;
25
26
import { initialize , multirootPath } from '../../initialize' ;
26
27
28
+ const execAsync = promisify ( exec ) ;
29
+ async function run ( argv : string [ ] , cwd : string ) {
30
+ const cmdline = argv . join ( ' ' ) ;
31
+ const { stderr } = await execAsync ( cmdline , {
32
+ cwd : cwd
33
+ } ) ;
34
+ if ( stderr && stderr . length > 0 ) {
35
+ throw Error ( stderr ) ;
36
+ }
37
+ }
38
+
39
+ class Venvs {
40
+ constructor (
41
+ private readonly cwd : string ,
42
+ private readonly prefix = '.venv-'
43
+ ) { }
44
+
45
+ public async create ( name : string ) : Promise < string > {
46
+ const venvRoot = this . resolve ( name ) ;
47
+ const argv = [
48
+ PYTHON_PATH . fileToCommandArgument ( ) ,
49
+ '-m' , 'venv' ,
50
+ venvRoot
51
+ ] ;
52
+ try {
53
+ await run ( argv , this . cwd ) ;
54
+ } catch ( err ) {
55
+ throw new Error ( `Failed to create Env ${ path . basename ( venvRoot ) } , ${ PYTHON_PATH } , Error: ${ err } ` ) ;
56
+ }
57
+ return venvRoot ;
58
+ }
59
+
60
+ public async cleanUp ( ) {
61
+ const globPattern = path . join ( this . cwd , `${ this . prefix } *` ) ;
62
+ await deleteFiles ( globPattern ) ;
63
+ }
64
+
65
+ private getID ( name : string ) : string {
66
+ // Ensure env is random to avoid conflicts in tests (currupting test data).
67
+ const now = new Date ( ) . getTime ( ) . toString ( ) ;
68
+ return `${ this . prefix } ${ name } ${ now } ` ;
69
+ }
70
+
71
+ private resolve ( name : string ) : string {
72
+ const id = this . getID ( name ) ;
73
+ return path . join ( this . cwd , id ) ;
74
+ }
75
+ }
76
+
27
77
const timeoutMs = IS_CI_SERVER ? 60_000 : 15_000 ;
28
78
suite ( 'Interpreters - Workspace VirtualEnv Service' , function ( ) {
29
79
this . timeout ( timeoutMs ) ;
30
80
this . retries ( 0 ) ;
31
81
32
- let locator : IInterpreterLocatorService ;
33
82
const workspaceUri = IS_MULTI_ROOT_TEST ? Uri . file ( path . join ( multirootPath , 'workspace3' ) ) : rootWorkspaceUri ! ;
34
83
const workspace4 = Uri . file ( path . join ( multirootPath , 'workspace4' ) ) ;
35
- const venvPrefix = '.venv' ;
84
+ const venvs = new Venvs ( workspaceUri . fsPath ) ;
85
+
36
86
let serviceContainer : IServiceContainer ;
87
+ let locator : IInterpreterLocatorService ;
37
88
38
89
async function manuallyTriggerFSWatcher ( deferred : Deferred < void > ) {
39
90
// Monitoring files on virtualized environments can be finicky...
@@ -51,7 +102,8 @@ suite('Interpreters - Workspace VirtualEnv Service', function() {
51
102
await sleep ( 1000 ) ;
52
103
}
53
104
}
54
- async function waitForInterpreterToBeDetected ( envNameToLookFor : string ) {
105
+ async function waitForInterpreterToBeDetected ( venvRoot : string ) {
106
+ const envNameToLookFor = path . basename ( venvRoot ) ;
55
107
const predicate = async ( ) => {
56
108
const items = await locator . getInterpreters ( workspaceUri ) ;
57
109
return items . some ( item => item . envName === envNameToLookFor ) ;
@@ -66,24 +118,7 @@ suite('Interpreters - Workspace VirtualEnv Service', function() {
66
118
await deferred . promise ;
67
119
}
68
120
async function createVirtualEnvironment ( envSuffix : string ) {
69
- // Ensure env is random to avoid conflicts in tests (currupting test data).
70
- const envName = `${ venvPrefix } ${ envSuffix } ${ new Date ( ) . getTime ( ) . toString ( ) } ` ;
71
- return new Promise < string > ( ( resolve , reject ) => {
72
- exec (
73
- `${ PYTHON_PATH . fileToCommandArgument ( ) } -m venv ${ envName } ` ,
74
- { cwd : workspaceUri . fsPath } ,
75
- ( ex , _ , stderr ) => {
76
- if ( ex ) {
77
- return reject ( ex ) ;
78
- }
79
- if ( stderr && stderr . length > 0 ) {
80
- reject ( new Error ( `Failed to create Env ${ envName } , ${ PYTHON_PATH } , Error: ${ stderr } ` ) ) ;
81
- } else {
82
- resolve ( envName ) ;
83
- }
84
- }
85
- ) ;
86
- } ) ;
121
+ return venvs . create ( envSuffix ) ;
87
122
}
88
123
89
124
suiteSetup ( async function ( ) {
@@ -99,12 +134,12 @@ suite('Interpreters - Workspace VirtualEnv Service', function() {
99
134
) ;
100
135
// This test is required, we need to wait for interpreter listing completes,
101
136
// before proceeding with other tests.
102
- await deleteFiles ( path . join ( workspaceUri . fsPath , ` ${ venvPrefix } *` ) ) ;
137
+ await venvs . cleanUp ( ) ;
103
138
await locator . getInterpreters ( workspaceUri ) ;
104
139
} ) ;
105
140
106
- suiteTeardown ( async ( ) => deleteFiles ( path . join ( workspaceUri . fsPath , ` ${ venvPrefix } *` ) ) ) ;
107
- teardown ( async ( ) => deleteFiles ( path . join ( workspaceUri . fsPath , ` ${ venvPrefix } *` ) ) ) ;
141
+ suiteTeardown ( async ( ) => venvs . cleanUp ( ) ) ;
142
+ teardown ( async ( ) => venvs . cleanUp ( ) ) ;
108
143
109
144
test ( 'Detect Virtual Environment' , async ( ) => {
110
145
const envName = await createVirtualEnvironment ( 'one' ) ;
@@ -132,7 +167,10 @@ suite('Interpreters - Workspace VirtualEnv Service', function() {
132
167
createVirtualEnvironment ( 'first3' ) ,
133
168
createVirtualEnvironment ( 'second3' )
134
169
] ) ;
135
- await Promise . all ( [ waitForInterpreterToBeDetected ( env1 ) , waitForInterpreterToBeDetected ( env2 ) ] ) ;
170
+ await Promise . all ( [
171
+ waitForInterpreterToBeDetected ( env1 ) ,
172
+ waitForInterpreterToBeDetected ( env2 )
173
+ ] ) ;
136
174
137
175
// Workspace4 should still not have any interpreters.
138
176
items4 = await locator . getInterpreters ( workspace4 ) ;
0 commit comments