2
2
// Licensed under the MIT License.
3
3
4
4
import * 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' ;
10
+
11
+ // tslint:disable-next-line: no-single-line-block-comment
12
+ /* eslint-disable global-require */
5
13
6
14
/**
7
15
* Checks if a given path ends with python*.exe
@@ -20,3 +28,99 @@ export function isWindowsPythonExe(interpreterPath:string): boolean {
20
28
21
29
return windowsPythonExes . test ( path . basename ( interpreterPath ) ) ;
22
30
}
31
+
32
+ export async function readRegistryValues ( options : Options ) : Promise < RegistryItem [ ] > {
33
+ // tslint:disable-next-line:no-require-imports
34
+ const WinReg = require ( 'winreg' ) ;
35
+ const regKey = new WinReg ( options ) ;
36
+ const deferred = createDeferred < RegistryItem [ ] > ( ) ;
37
+ regKey . values ( ( err :Error , res :RegistryItem [ ] ) => {
38
+ if ( err ) {
39
+ deferred . reject ( err ) ;
40
+ }
41
+ deferred . resolve ( res ) ;
42
+ } ) ;
43
+ return deferred . promise ;
44
+ }
45
+
46
+ export async function readRegistryKeys ( options : Options ) : Promise < Registry [ ] > {
47
+ // tslint:disable-next-line:no-require-imports
48
+ const WinReg = require ( 'winreg' ) ;
49
+ const regKey = new WinReg ( options ) ;
50
+ const deferred = createDeferred < Registry [ ] > ( ) ;
51
+ regKey . keys ( ( err :Error , res :Registry [ ] ) => {
52
+ if ( err ) {
53
+ deferred . reject ( err ) ;
54
+ }
55
+ deferred . resolve ( res ) ;
56
+ } ) ;
57
+ return deferred . promise ;
58
+ }
59
+
60
+ export interface IRegistryInterpreterData {
61
+ interpreterPath : string ;
62
+ versionStr ?: string ;
63
+ sysVersionStr ?:string ;
64
+ bitnessStr ?: string ;
65
+ displayName ?: string ;
66
+ distroOrgName ?: string ;
67
+ }
68
+
69
+ async function getInterpreterDataFromKey (
70
+ { arch, hive, key } :Registry ,
71
+ distroOrgName :string ,
72
+ ) : Promise < IRegistryInterpreterData | undefined > {
73
+ const result :IRegistryInterpreterData = {
74
+ interpreterPath : '' ,
75
+ distroOrgName,
76
+ } ;
77
+
78
+ const values :RegistryItem [ ] = await readRegistryValues ( { arch, hive, key } ) ;
79
+ for ( const value of values ) {
80
+ switch ( value . name ) {
81
+ case 'SysArchitecture' :
82
+ result . bitnessStr = value . value ;
83
+ break ;
84
+ case 'SysVersion' :
85
+ result . sysVersionStr = value . value ;
86
+ break ;
87
+ case 'Version' :
88
+ result . versionStr = value . value ;
89
+ break ;
90
+ case 'DisplayName' :
91
+ result . displayName = value . value ;
92
+ break ;
93
+ default :
94
+ break ;
95
+ }
96
+ }
97
+
98
+ const subKeys :Registry [ ] = await readRegistryKeys ( { arch, hive, key } ) ;
99
+ const subKey = subKeys . map ( ( s ) => s . key ) . find ( ( s ) => s . endsWith ( 'InstallPath' ) ) ;
100
+ if ( subKey ) {
101
+ const subKeyValues :RegistryItem [ ] = await readRegistryValues ( { arch, hive, key : subKey } ) ;
102
+ const value = subKeyValues . find ( ( v ) => v . name === 'ExecutablePath' ) ;
103
+ if ( value ) {
104
+ result . interpreterPath = value . value ;
105
+ if ( value . type !== REG_SZ ) {
106
+ traceVerbose ( `Registry interpreter path type [${ value . type } ]: ${ value . value } ` ) ;
107
+ }
108
+ }
109
+ }
110
+
111
+ if ( result . interpreterPath . length > 0 ) {
112
+ return result ;
113
+ }
114
+ return undefined ;
115
+ }
116
+
117
+ export async function getInterpreterDataFromRegistry (
118
+ arch :string ,
119
+ hive :string ,
120
+ key :string ,
121
+ ) : Promise < IRegistryInterpreterData [ ] > {
122
+ const subKeys = await readRegistryKeys ( { arch, hive, key } ) ;
123
+ const distroOrgName = key . substr ( key . lastIndexOf ( '\\' ) + 1 ) ;
124
+ const allData = await Promise . all ( subKeys . map ( ( subKey ) => getInterpreterDataFromKey ( subKey , distroOrgName ) ) ) ;
125
+ return ( allData . filter ( ( data ) => data !== undefined ) || [ ] ) as IRegistryInterpreterData [ ] ;
126
+ }
0 commit comments