@@ -8,11 +8,9 @@ import * as fs from 'fs';
88import  *  as  fsExtra  from  'fs-extra' ; 
99import  *  as  os  from  'os' ; 
1010import  *  as  path  from  'path' ; 
11- import  {  CancellationToken ,  Range ,  TextDocument ,  Uri  }  from  'vscode' ; 
11+ import  {  Position ,  Range ,  TextDocument ,  Uri  }  from  'vscode' ; 
1212import  *  as  settings  from  './configSettings' ; 
13- import  {  mergeEnvVariables ,  parseEnvFile  }  from  './envFileParser' ; 
14- import  {  isNotInstalledError  }  from  './helpers' ; 
15- import  {  InterpreterInfoCache  }  from  './interpreterInfoCache' ; 
13+ import  {  parseEnvFile  }  from  './envFileParser' ; 
1614
1715export  const  IS_WINDOWS  =  / ^ w i n / . test ( process . platform ) ; 
1816export  const  Is_64Bit  =  os . arch ( )  ===  'x64' ; 
@@ -53,51 +51,6 @@ export function fsReaddirAsync(root: string): Promise<string[]> {
5351 } ) ; 
5452} 
5553
56- async  function  getPythonInterpreterDirectory ( resource ?: Uri ) : Promise < string >  { 
57-  const  cache  =  InterpreterInfoCache . get ( resource ) ; 
58-  const  pythonFileName  =  settings . PythonSettings . getInstance ( resource ) . pythonPath ; 
59- 
60-  // If we already have it and the python path hasn't changed, yay 
61-  if  ( cache . pythonInterpreterDirectory  &&  cache . pythonInterpreterDirectory . length  >  0 
62-  &&  cache . pythonSettingsPath  ===  pythonFileName )  { 
63-  return  cache . pythonInterpreterDirectory ; 
64-  } 
65- 
66-  // Check if we have the path 
67-  if  ( path . basename ( pythonFileName )  ===  pythonFileName )  { 
68-  try  { 
69-  const  pythonInterpreterPath  =  await  getPathFromPythonCommand ( pythonFileName ) ; 
70-  const  pythonInterpreterDirectory  =  path . dirname ( pythonInterpreterPath ) ; 
71-  InterpreterInfoCache . setPaths ( resource ,  pythonFileName ,  pythonInterpreterPath ,  pythonInterpreterDirectory ) ; 
72-  return  pythonInterpreterDirectory ; 
73-  // tslint:disable-next-line:variable-name 
74-  }  catch  ( _ex )  { 
75-  InterpreterInfoCache . setPaths ( resource ,  pythonFileName ,  pythonFileName ,  '' ) ; 
76-  return  '' ; 
77-  } 
78-  } 
79- 
80-  return  new  Promise < string > ( resolve  =>  { 
81-  // If we can execute the python, then get the path from the fully qualified name 
82-  child_process . execFile ( pythonFileName ,  [ '-c' ,  'print(1234)' ] ,  ( error ,  stdout ,  stderr )  =>  { 
83-  // Yes this is a valid python path 
84-  if  ( stdout . startsWith ( '1234' ) )  { 
85-  const  pythonInterpreterDirectory  =  path . dirname ( pythonFileName ) ; 
86-  InterpreterInfoCache . setPaths ( resource ,  pythonFileName ,  pythonFileName ,  pythonInterpreterDirectory ) ; 
87-  resolve ( pythonInterpreterDirectory ) ; 
88-  }  else  { 
89-  // No idea, didn't work, hence don't reject, but return empty path 
90-  InterpreterInfoCache . setPaths ( resource ,  pythonFileName ,  pythonFileName ,  '' ) ; 
91-  resolve ( '' ) ; 
92-  } 
93-  } ) ; 
94-  } ) ; 
95- } 
96- export  async  function  getFullyQualifiedPythonInterpreterPath ( resource ?: Uri ) : Promise < string >  { 
97-  const  pyDir  =  await  getPythonInterpreterDirectory ( resource ) ; 
98-  const  cache  =  InterpreterInfoCache . get ( resource ) ; 
99-  return  cache . pythonInterpreterPath ; 
100- } 
10154export  async  function  getPathFromPythonCommand ( pythonPath : string ) : Promise < string >  { 
10255 return  await  new  Promise < string > ( ( resolve ,  reject )  =>  { 
10356 child_process . execFile ( pythonPath ,  [ '-c' ,  'import sys;print(sys.executable)' ] ,  ( _ ,  stdout )  =>  { 
@@ -110,197 +63,6 @@ export async function getPathFromPythonCommand(pythonPath: string): Promise<stri
11063 } ) ; 
11164 } ) ; 
11265} 
113- async  function  getEnvVariables ( resource ?: Uri ) : Promise < { } >  { 
114-  const  cache  =  InterpreterInfoCache . get ( resource ) ; 
115-  if  ( cache . customEnvVariables )  { 
116-  return  cache . customEnvVariables ; 
117-  } 
118- 
119-  const  pyPath  =  await  getPythonInterpreterDirectory ( resource ) ; 
120-  let  customEnvVariables  =  await  getCustomEnvVars ( resource )  ||  { } ; 
121- 
122-  if  ( pyPath . length  >  0 )  { 
123-  // Ensure to include the path of the current python. 
124-  let  newPath  =  '' ; 
125-  const  currentPath  =  typeof  customEnvVariables [ PATH_VARIABLE_NAME ]  ===  'string'  ? customEnvVariables [ PATH_VARIABLE_NAME ]  : process . env [ PATH_VARIABLE_NAME ] ; 
126-  if  ( IS_WINDOWS )  { 
127-  newPath  =  `${ pyPath } ${ path . delimiter } ${ path . join ( pyPath ,  'Scripts\\' ) } ${ path . delimiter } ${ currentPath }  ; 
128-  // This needs to be done for windows. 
129-  process . env [ PATH_VARIABLE_NAME ]  =  newPath ; 
130-  }  else  { 
131-  newPath  =  `${ pyPath } ${ path . delimiter } ${ currentPath }  ; 
132-  } 
133-  customEnvVariables  =  mergeEnvVariables ( customEnvVariables ,  process . env ) ; 
134-  customEnvVariables [ PATH_VARIABLE_NAME ]  =  newPath ; 
135-  } 
136- 
137-  InterpreterInfoCache . setCustomEnvVariables ( resource ,  customEnvVariables ) ; 
138-  return  customEnvVariables ; 
139- } 
140- export  async  function  execPythonFile ( resource : string  |  Uri  |  undefined ,  file : string ,  args : string [ ] ,  cwd : string ,  includeErrorAsResponse : boolean  =  false ,  stdOut : ( line : string )  =>  void =  null ,  token ?: CancellationToken ) : Promise < string >  { 
141-  const  resourceUri  =  typeof  resource  ===  'string'  ? Uri . file ( resource )  : resource ; 
142-  const  env  =  await  getEnvVariables ( resourceUri ) ; 
143-  const  options  =  {  cwd,  env } ; 
144- 
145-  if  ( stdOut )  { 
146-  return  spawnFileInternal ( file ,  args ,  options ,  includeErrorAsResponse ,  stdOut ,  token ) ; 
147-  } 
148- 
149-  const  fileIsPythonInterpreter  =  ( file . toUpperCase ( )  ===  'PYTHON'  ||  file  ===  settings . PythonSettings . getInstance ( resourceUri ) . pythonPath ) ; 
150-  const  execAsModule  =  fileIsPythonInterpreter  &&  args . length  >  0  &&  args [ 0 ]  ===  '-m' ; 
151- 
152-  if  ( execAsModule )  { 
153-  return  getFullyQualifiedPythonInterpreterPath ( resourceUri ) 
154-  . then ( p  =>  execPythonModule ( p ,  args ,  options ,  includeErrorAsResponse ,  token ) ) ; 
155-  } 
156-  return  execFileInternal ( file ,  args ,  options ,  includeErrorAsResponse ,  token ) ; 
157- } 
158- 
159- function  handleResponse ( file : string ,  includeErrorAsResponse : boolean ,  error : Error ,  stdout : string ,  stderr : string ,  token ?: CancellationToken ) : Promise < string >  { 
160-  if  ( token  &&  token . isCancellationRequested )  { 
161-  return  Promise . resolve ( undefined ) ; 
162-  } 
163-  if  ( isNotInstalledError ( error ) )  { 
164-  return  Promise . reject ( error ) ; 
165-  } 
166- 
167-  // pylint: 
168-  // In the case of pylint we have some messages (such as config file not found and using default etc...) being returned in stderr 
169-  // These error messages are useless when using pylint 
170-  if  ( includeErrorAsResponse  &&  ( stdout . length  >  0  ||  stderr . length  >  0 ) )  { 
171-  return  Promise . resolve ( stdout  +  '\n'  +  stderr ) ; 
172-  } 
173- 
174-  let  hasErrors  =  ( error  &&  error . message . length  >  0 )  ||  ( stderr  &&  stderr . length  >  0 ) ; 
175-  if  ( hasErrors  &&  ( typeof  stdout  !==  'string'  ||  stdout . length  ===  0 ) )  { 
176-  let  errorMsg  =  ( error  &&  error . message )  ? error . message  : ( stderr  &&  stderr . length  >  0  ? stderr  +  ''  : '' ) ; 
177-  return  Promise . reject ( errorMsg ) ; 
178-  } 
179-  else  { 
180-  return  Promise . resolve ( stdout  +  '' ) ; 
181-  } 
182- } 
183- function  handlePythonModuleResponse ( includeErrorAsResponse : boolean ,  error : Error ,  stdout : string ,  stderr : string ,  token ?: CancellationToken ) : Promise < string >  { 
184-  if  ( token  &&  token . isCancellationRequested )  { 
185-  return  Promise . resolve ( undefined ) ; 
186-  } 
187-  if  ( isNotInstalledError ( error ) )  { 
188-  return  Promise . reject ( error ) ; 
189-  } 
190- 
191-  // pylint: 
192-  // In the case of pylint we have some messages (such as config file not found and using default etc...) being returned in stderr 
193-  // These error messages are useless when using pylint 
194-  if  ( includeErrorAsResponse  &&  ( stdout . length  >  0  ||  stderr . length  >  0 ) )  { 
195-  return  Promise . resolve ( stdout  +  '\n'  +  stderr ) ; 
196-  } 
197-  if  ( ! includeErrorAsResponse  &&  stderr . length  >  0 )  { 
198-  return  Promise . reject ( stderr ) ; 
199-  } 
200- 
201-  return  Promise . resolve ( stdout  +  '' ) ; 
202- } 
203- function  execPythonModule ( file : string ,  args : string [ ] ,  options : child_process . ExecFileOptions ,  includeErrorAsResponse : boolean ,  token ?: CancellationToken ) : Promise < string >  { 
204-  options . maxBuffer  =  options . maxBuffer  ? options . maxBuffer  : 1024  *  102400 ; 
205-  return  new  Promise < string > ( ( resolve ,  reject )  =>  { 
206-  let  proc  =  child_process . execFile ( file ,  args ,  options ,  ( error ,  stdout ,  stderr )  =>  { 
207-  handlePythonModuleResponse ( includeErrorAsResponse ,  error ,  stdout ,  stderr ,  token ) 
208-  . then ( resolve ) 
209-  . catch ( reject ) ; 
210-  } ) ; 
211-  if  ( token  &&  token . onCancellationRequested )  { 
212-  token . onCancellationRequested ( ( )  =>  { 
213-  if  ( proc )  { 
214-  proc . kill ( ) ; 
215-  proc  =  null ; 
216-  } 
217-  } ) ; 
218-  } 
219-  } ) ; 
220- } 
221- 
222- function  execFileInternal ( file : string ,  args : string [ ] ,  options : child_process . ExecFileOptions ,  includeErrorAsResponse : boolean ,  token ?: CancellationToken ) : Promise < string >  { 
223-  options . maxBuffer  =  options . maxBuffer  ? options . maxBuffer  : 1024  *  102400 ; 
224-  return  new  Promise < string > ( ( resolve ,  reject )  =>  { 
225-  let  proc  =  child_process . execFile ( file ,  args ,  options ,  ( error ,  stdout ,  stderr )  =>  { 
226-  handleResponse ( file ,  includeErrorAsResponse ,  error ,  stdout ,  stderr ,  token ) 
227-  . then ( data  =>  resolve ( data ) ) 
228-  . catch ( err  =>  reject ( err ) ) ; 
229-  } ) ; 
230-  if  ( token  &&  token . onCancellationRequested )  { 
231-  token . onCancellationRequested ( ( )  =>  { 
232-  if  ( proc )  { 
233-  proc . kill ( ) ; 
234-  proc  =  null ; 
235-  } 
236-  } ) ; 
237-  } 
238-  } ) ; 
239- } 
240- function  spawnFileInternal ( file : string ,  args : string [ ] ,  options : child_process . ExecFileOptions ,  includeErrorAsResponse : boolean ,  stdOut : ( line : string )  =>  void ,  token ?: CancellationToken ) : Promise < string >  { 
241-  return  new  Promise < string > ( ( resolve ,  reject )  =>  { 
242-  options . env  =  options . env  ||  { } ; 
243-  options . env [ 'PYTHONIOENCODING' ]  =  'UTF-8' ; 
244-  let  proc  =  child_process . spawn ( file ,  args ,  options ) ; 
245-  let  error  =  '' ; 
246-  let  exited  =  false ; 
247-  if  ( token  &&  token . onCancellationRequested )  { 
248-  token . onCancellationRequested ( ( )  =>  { 
249-  if  ( ! exited  &&  proc )  { 
250-  proc . kill ( ) ; 
251-  proc  =  null ; 
252-  } 
253-  } ) ; 
254-  } 
255-  proc . on ( 'error' ,  error  =>  { 
256-  reject ( error ) ; 
257-  } ) ; 
258-  proc . stdout . setEncoding ( 'utf8' ) ; 
259-  proc . stderr . setEncoding ( 'utf8' ) ; 
260-  proc . stdout . on ( 'data' ,  function  ( data : string )  { 
261-  if  ( token  &&  token . isCancellationRequested )  { 
262-  return ; 
263-  } 
264-  stdOut ( data ) ; 
265-  } ) ; 
266- 
267-  proc . stderr . on ( 'data' ,  function  ( data : string )  { 
268-  if  ( token  &&  token . isCancellationRequested )  { 
269-  return ; 
270-  } 
271-  if  ( includeErrorAsResponse )  { 
272-  stdOut ( data ) ; 
273-  } 
274-  else  { 
275-  error  +=  data ; 
276-  } 
277-  } ) ; 
278- 
279-  proc . on ( 'exit' ,  function  ( code )  { 
280-  exited  =  true ; 
281- 
282-  if  ( token  &&  token . isCancellationRequested )  { 
283-  return  reject ( ) ; 
284-  } 
285-  if  ( error . length  >  0 )  { 
286-  return  reject ( error ) ; 
287-  } 
288- 
289-  resolve ( ) ; 
290-  } ) ; 
291- 
292-  } ) ; 
293- } 
294- function  execInternal ( command : string ,  args : string [ ] ,  options : child_process . ExecFileOptions ,  includeErrorAsResponse : boolean ) : Promise < string >  { 
295-  return  new  Promise < string > ( ( resolve ,  reject )  =>  { 
296-  child_process . exec ( [ command ] . concat ( args ) . join ( ' ' ) ,  options ,  ( error ,  stdout ,  stderr )  =>  { 
297-  handleResponse ( command ,  includeErrorAsResponse ,  error ,  stdout ,  stderr ) 
298-  . then ( data  =>  resolve ( data ) ) 
299-  . catch ( err  =>  reject ( err ) ) ; 
300-  } ) ; 
301-  } ) ; 
302- } 
303- 
30466export  function  formatErrorForLogging ( error : Error  |  string ) : string  { 
30567 let  message : string  =  '' ; 
30668 if  ( typeof  error  ===  'string' )  { 
@@ -332,7 +94,7 @@ export function getSubDirectories(rootDir: string): Promise<string[]> {
33294 if  ( error )  { 
33395 return  resolve ( [ ] ) ; 
33496 } 
335-  const  subDirs  =  [ ] ; 
97+  const  subDirs :  string [ ]  =  [ ] ; 
33698 files . forEach ( name  =>  { 
33799 const  fullPath  =  path . join ( rootDir ,  name ) ; 
338100 try  { 
@@ -341,7 +103,7 @@ export function getSubDirectories(rootDir: string): Promise<string[]> {
341103 } 
342104 } 
343105 // tslint:disable-next-line:no-empty 
344-  catch  ( ex )  { } 
106+  catch  ( ex )  {   } 
345107 } ) ; 
346108 resolve ( subDirs ) ; 
347109 } ) ; 
@@ -396,7 +158,7 @@ export function getWindowsLineEndingCount(document: TextDocument, offset: Number
396158 // In order to prevent the one-time loading of large files from taking up too much memory 
397159 for  ( let  pos  =  0 ;  pos  <  offset ;  pos  +=  readBlock )  { 
398160 let  startAt  =  document . positionAt ( pos ) ; 
399-  let  endAt   =   null ; 
161+  let  endAt :  Position ; 
400162
401163 if  ( offsetDiff  >=  readBlock )  { 
402164 endAt  =  document . positionAt ( pos  +  readBlock ) ; 
@@ -405,7 +167,7 @@ export function getWindowsLineEndingCount(document: TextDocument, offset: Number
405167 endAt  =  document . positionAt ( pos  +  offsetDiff ) ; 
406168 } 
407169
408-  let  text  =  document . getText ( new  Range ( startAt ,  endAt ) ) ; 
170+  let  text  =  document . getText ( new  Range ( startAt ,  endAt ! ) ) ; 
409171 let  cr  =  text . match ( eolPattern ) ; 
410172
411173 count  +=  cr  ? cr . length  : 0 ; 
@@ -422,13 +184,3 @@ export function arePathsSame(path1: string, path2: string) {
422184 return  path1  ===  path2 ; 
423185 } 
424186} 
425- 
426- export  async  function  getInterpreterVersion ( pythonPath : string )  { 
427-  return  await  new  Promise < string > ( ( resolve ,  reject )  =>  { 
428-  child_process . execFile ( pythonPath ,  [ '--version' ] ,  ( error ,  stdout ,  stdErr )  =>  { 
429-  const  out  =  ( typeof  stdErr  ===  'string'  ? stdErr  : '' )  +  os . EOL  +  ( typeof  stdout  ===  'string'  ? stdout  : '' ) ; 
430-  const  lines  =  out . split ( / \r ? \n / g) . map ( line  =>  line . trim ( ) ) . filter ( line  =>  line . length  >  0 ) ; 
431-  resolve ( lines . length  >  0  ? lines [ 0 ]  : '' ) ; 
432-  } ) ; 
433-  } ) ; 
434- } 
0 commit comments