@@ -62,9 +62,12 @@ export class Rustup {
62
62
* The method is asynchronous because it tries to find Rust's source code
63
63
* @param pathToRustcSysRoot A path to Rust's installation root
64
64
*/
65
- public static async create ( logger : ChildLogger , pathToRustcSysRoot : string ) : Promise < Rustup > {
66
- logger . createChildLogger ( 'create: ' ) . debug ( `sysroot=${ pathToRustcSysRoot } ` ) ;
67
- const rustup = new Rustup ( logger , pathToRustcSysRoot , undefined , undefined ) ;
65
+ public static async create ( logger : ChildLogger ) : Promise < Rustup | undefined > {
66
+ const sysrootPath : string | undefined = await this . invokeGettingSysrootPath ( 'nightly' , logger ) ;
67
+ if ( ! sysrootPath ) {
68
+ return undefined ;
69
+ }
70
+ const rustup = new Rustup ( logger , sysrootPath , undefined , undefined ) ;
68
71
await rustup . updatePathToRustSourceCodePath ( ) ;
69
72
await rustup . updateComponents ( ) ;
70
73
await rustup . updatePathToRlsExecutable ( ) ;
@@ -125,7 +128,7 @@ export class Rustup {
125
128
*/
126
129
public async updateComponents ( ) : Promise < void > {
127
130
const logger = this . logger . createChildLogger ( 'updateComponents: ' ) ;
128
- const stdoutData : string | undefined = await this . invokeRustup ( [ 'component' , 'list' ] ) ;
131
+ const stdoutData : string | undefined = await Rustup . invoke ( [ 'component' , 'list' , '--toolchain' , 'nightly' ] , logger ) ;
129
132
if ( ! stdoutData ) {
130
133
logger . error ( `stdoutData=${ stdoutData } ` ) ;
131
134
return undefined ;
@@ -192,6 +195,14 @@ export class Rustup {
192
195
return true ;
193
196
}
194
197
198
+ /**
199
+ * Returns if RLS is installed
200
+ * @return true if RLS is installed otherwise false
201
+ */
202
+ public isRlsInstalled ( ) : boolean {
203
+ return this . isComponentInstalled ( Rustup . getRlsComponentName ( ) ) ;
204
+ }
205
+
195
206
/**
196
207
* Returns true if the component `rust-analysis` can be installed otherwise false.
197
208
* If the component is already installed, the method returns false
@@ -233,6 +244,52 @@ export class Rustup {
233
244
return ' (installed)' ;
234
245
}
235
246
247
+ /**
248
+ * Invokes rustup to get the path to the sysroot of the specified toolchain.
249
+ * Checks if the invocation exited successfully and returns the output of the invocation
250
+ * @param toolchain The toolchain to get the path to the sysroot for
251
+ * @param logger The logger to log messages
252
+ * @return The output of the invocation if the invocation exited successfully otherwise undefined
253
+ */
254
+ private static async invokeGettingSysrootPath ( toolchain : string , logger : ChildLogger ) : Promise < string | undefined > {
255
+ const output : string | undefined = await this . invokeRun ( toolchain , [ 'rustc' , '--print' , 'sysroot' ] , logger ) ;
256
+ if ( ! output ) {
257
+ return undefined ;
258
+ }
259
+ return output . trim ( ) ;
260
+ }
261
+
262
+ /**
263
+ * Invokes `rustup run...` with the specified toolchain and arguments, checks if it exited successfully and returns its output
264
+ * @param toolchain The toolchain to invoke rustup with
265
+ * @param args The arguments to invoke rustup with
266
+ * @param logger The logger to log messages
267
+ */
268
+ private static async invokeRun ( toolchain : string , args : string [ ] , logger : ChildLogger ) : Promise < string | undefined > {
269
+ return await this . invoke ( [ 'run' , toolchain , ...args ] , logger ) ;
270
+ }
271
+
272
+ /**
273
+ * Invokes Rustup with specified arguments, checks if it exited successfully and returns its output
274
+ * @param args Arguments to invoke Rustup with
275
+ * @param logger The logger to log messages
276
+ * @returns an output if invocation exited successfully otherwise undefined
277
+ */
278
+ private static async invoke ( args : string [ ] , logger : ChildLogger ) : Promise < string | undefined > {
279
+ const rustupExe = Rustup . getRustupExecutable ( ) ;
280
+ const functionLogger = logger . createChildLogger ( `invoke: rustupExe=${ rustupExe } , args=${ JSON . stringify ( args ) } : ` ) ;
281
+ const result = await OutputtingProcess . spawn ( rustupExe , args , undefined ) ;
282
+ if ( ! result . success ) {
283
+ functionLogger . error ( 'failed' ) ;
284
+ return undefined ;
285
+ }
286
+ if ( result . exitCode !== 0 ) {
287
+ functionLogger . error ( `exited unexpectedly; exitCode=${ result . exitCode } , stderrData=${ result . stderrData } ` ) ;
288
+ return undefined ;
289
+ }
290
+ return result . stdoutData ;
291
+ }
292
+
236
293
/**
237
294
* Constructs a new instance of the class.
238
295
* The constructor is private because creating a new instance should be done via the method `create`
@@ -258,36 +315,6 @@ export class Rustup {
258
315
this . components = [ ] ;
259
316
}
260
317
261
- /**
262
- * Invokes Rustup with specified arguments, checks it exited successfully and returns its output
263
- * @param args Arguments to invoke Rustup with
264
- * @returns an output if invokation Rustup exited successfully otherwise undefined
265
- */
266
- private async invokeRustup ( args : string [ ] ) : Promise < string | undefined > {
267
- const logger = this . logger . createChildLogger ( 'invokeRustup: ' ) ;
268
-
269
- const rustupExe = Rustup . getRustupExecutable ( ) ;
270
-
271
- // We assume that the executable of Rustup can be called since usually both `rustc` and `rustup` are placed in the same directory
272
- const result = await OutputtingProcess . spawn ( rustupExe , args , undefined ) ;
273
-
274
- if ( ! result . success ) {
275
- // It actually shouldn't happen.
276
- // If it happens, then there is some problem and we need to know about it
277
- logger . error ( `failed to execute ${ rustupExe } . This should not have happened` ) ;
278
-
279
- return undefined ;
280
- }
281
-
282
- if ( result . exitCode !== 0 ) {
283
- logger . error ( `${ rustupExe } ${ args . join ( ' ' ) } exited with code=${ result . exitCode } , but zero is expected. This should not have happened. stderrData=${ result . stderrData } ` ) ;
284
-
285
- return undefined ;
286
- }
287
-
288
- return result . stdoutData ;
289
- }
290
-
291
318
/**
292
319
* Takes from the field `components` only installed components
293
320
* @returns a list of installed components
@@ -317,8 +344,8 @@ export class Rustup {
317
344
// We return true because the component is installed, but anyway it is an exceptional situation
318
345
return true ;
319
346
}
320
- const args = [ 'component' , 'add' , componentName ] ;
321
- const stdoutData : string | undefined = await this . invokeRustup ( args ) ;
347
+ const args = [ 'component' , 'add' , componentName , '--toolchain' , 'nightly' ] ;
348
+ const stdoutData : string | undefined = await Rustup . invoke ( args , logger ) ;
322
349
// Some error occurred. It is already logged in the method invokeRustup.
323
350
// So we just need to notify a caller that the installation failed
324
351
if ( stdoutData === undefined ) {
0 commit comments