11// Copyright (c) Microsoft Corporation. All rights reserved.
22// Licensed under the MIT License.
33
4+ import { uniqBy } from 'lodash' ;
45import * as path from 'path' ;
5- import {
6- Options , REG_SZ , Registry , RegistryItem ,
7- } from 'winreg' ;
8- import { traceVerbose } from '../../common/logger' ;
9- import { createDeferred } from '../../common/utils/async' ;
6+ import { traceError , traceVerbose } from '../../common/logger' ;
7+ import { HKCU , HKLM , IRegistryKey , IRegistryValue , readRegistryKeys , readRegistryValues , REG_SZ } from './windowsRegistry' ;
108
119// tslint:disable-next-line: no-single-line-block-comment
1210/* eslint-disable global-require */
@@ -16,7 +14,7 @@ import { createDeferred } from '../../common/utils/async';
1614 * @param {string } interpreterPath : Path to python interpreter.
1715 * @returns {boolean } : Returns true if the path matches pattern for windows python executable.
1816 */
19- export function isWindowsPythonExe ( interpreterPath :string ) : boolean {
17+ export function isWindowsPythonExe ( interpreterPath : string ) : boolean {
2018 /**
2119 * This Reg-ex matches following file names:
2220 * python.exe
@@ -29,69 +27,25 @@ export function isWindowsPythonExe(interpreterPath:string): boolean {
2927 return windowsPythonExes . test ( path . basename ( interpreterPath ) ) ;
3028}
3129
32- export interface IRegistryKey {
33- hive :string ;
34- arch :string ;
35- key :string ;
36- parentKey ?:IRegistryKey ;
37- }
38-
39- export interface IRegistryValue {
40- hive :string ;
41- arch :string ;
42- key :string ;
43- name :string ;
44- type :string ;
45- value :string ;
46- }
47-
48- export async function readRegistryValues ( options : Options ) : Promise < IRegistryValue [ ] > {
49- // tslint:disable-next-line:no-require-imports
50- const WinReg = require ( 'winreg' ) ;
51- const regKey = new WinReg ( options ) ;
52- const deferred = createDeferred < RegistryItem [ ] > ( ) ;
53- regKey . values ( ( err :Error , res :RegistryItem [ ] ) => {
54- if ( err ) {
55- deferred . reject ( err ) ;
56- }
57- deferred . resolve ( res ) ;
58- } ) ;
59- return deferred . promise ;
60- }
61-
62- export async function readRegistryKeys ( options : Options ) : Promise < IRegistryKey [ ] > {
63- // tslint:disable-next-line:no-require-imports
64- const WinReg = require ( 'winreg' ) ;
65- const regKey = new WinReg ( options ) ;
66- const deferred = createDeferred < Registry [ ] > ( ) ;
67- regKey . keys ( ( err :Error , res :Registry [ ] ) => {
68- if ( err ) {
69- deferred . reject ( err ) ;
70- }
71- deferred . resolve ( res ) ;
72- } ) ;
73- return deferred . promise ;
74- }
75-
76- export interface IRegistryInterpreterData {
30+ export interface IRegistryInterpreterData {
7731 interpreterPath : string ;
7832 versionStr ?: string ;
79- sysVersionStr ?:string ;
33+ sysVersionStr ?: string ;
8034 bitnessStr ?: string ;
8135 displayName ?: string ;
8236 distroOrgName ?: string ;
8337}
8438
8539async function getInterpreterDataFromKey (
86- { arch, hive, key } :IRegistryKey ,
87- distroOrgName :string ,
40+ { arch, hive, key } : IRegistryKey ,
41+ distroOrgName : string ,
8842) : Promise < IRegistryInterpreterData | undefined > {
89- const result :IRegistryInterpreterData = {
43+ const result : IRegistryInterpreterData = {
9044 interpreterPath : '' ,
9145 distroOrgName,
9246 } ;
9347
94- const values :IRegistryValue [ ] = await readRegistryValues ( { arch, hive, key } ) ;
48+ const values : IRegistryValue [ ] = await readRegistryValues ( { arch, hive, key } ) ;
9549 for ( const value of values ) {
9650 switch ( value . name ) {
9751 case 'SysArchitecture' :
@@ -111,10 +65,10 @@ async function getInterpreterDataFromKey(
11165 }
11266 }
11367
114- const subKeys :IRegistryKey [ ] = await readRegistryKeys ( { arch, hive, key } ) ;
68+ const subKeys : IRegistryKey [ ] = await readRegistryKeys ( { arch, hive, key } ) ;
11569 const subKey = subKeys . map ( ( s ) => s . key ) . find ( ( s ) => s . endsWith ( 'InstallPath' ) ) ;
11670 if ( subKey ) {
117- const subKeyValues :IRegistryValue [ ] = await readRegistryValues ( { arch, hive, key : subKey } ) ;
71+ const subKeyValues : IRegistryValue [ ] = await readRegistryValues ( { arch, hive, key : subKey } ) ;
11872 const value = subKeyValues . find ( ( v ) => v . name === 'ExecutablePath' ) ;
11973 if ( value ) {
12074 result . interpreterPath = value . value ;
@@ -131,12 +85,34 @@ async function getInterpreterDataFromKey(
13185}
13286
13387export async function getInterpreterDataFromRegistry (
134- arch :string ,
135- hive :string ,
136- key :string ,
88+ arch : string ,
89+ hive : string ,
90+ key : string ,
13791) : Promise < IRegistryInterpreterData [ ] > {
13892 const subKeys = await readRegistryKeys ( { arch, hive, key } ) ;
13993 const distroOrgName = key . substr ( key . lastIndexOf ( '\\' ) + 1 ) ;
14094 const allData = await Promise . all ( subKeys . map ( ( subKey ) => getInterpreterDataFromKey ( subKey , distroOrgName ) ) ) ;
14195 return ( allData . filter ( ( data ) => data !== undefined ) || [ ] ) as IRegistryInterpreterData [ ] ;
14296}
97+
98+ export async function getRegistryInterpreters ( ) : Promise < IRegistryInterpreterData [ ] > {
99+ let registryData : IRegistryInterpreterData [ ] = [ ] ;
100+
101+ for ( const arch of [ 'x64' , 'x86' ] ) {
102+ for ( const hive of [ HKLM , HKCU ] ) {
103+ const root = '\\SOFTWARE\\Python' ;
104+ let keys : string [ ] = [ ] ;
105+ try {
106+ keys = ( await readRegistryKeys ( { arch, hive, key : root } ) ) . map ( ( k ) => k . key ) ;
107+ } catch ( ex ) {
108+ traceError ( `Failed to access Registry: ${ arch } \\${ hive } \\${ root } ` , ex ) ;
109+ }
110+
111+ for ( const key of keys ) {
112+ registryData = registryData . concat ( await getInterpreterDataFromRegistry ( arch , hive , key ) ) ;
113+ }
114+ }
115+ }
116+
117+ return uniqBy ( registryData , ( r : IRegistryInterpreterData ) => r . interpreterPath ) ;
118+ }
0 commit comments