Skip to content
This repository has been archived by the owner on Dec 8, 2020. It is now read-only.

Commit

Permalink
Use the nightly toolchain of rustup (#246)
Browse files Browse the repository at this point in the history
  • Loading branch information
KalitaAlexey authored May 19, 2017
1 parent 0e1fc2c commit 9e15f1b
Show file tree
Hide file tree
Showing 2 changed files with 87 additions and 60 deletions.
48 changes: 24 additions & 24 deletions src/components/configuration/Configuration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,18 +81,16 @@ export class Configuration {
* @param logger a logger to log messages
*/
public static async create(logger: ChildLogger): Promise<Configuration> {
const rustcSysRoot: string | undefined = await this.loadRustcSysRoot();
const createRustInstallationPromise = async () => {
if (!rustcSysRoot) {
return undefined;
}
if (Rustup.doesManageRustcSysRoot(rustcSysRoot)) {
return await Rustup.create(logger.createChildLogger('Rustup: '), rustcSysRoot);
} else {
return new NotRustup(rustcSysRoot);
const rustup: Rustup | undefined = await Rustup.create(logger.createChildLogger('Rustup: '));
let rustInstallation: Rustup | NotRustup | undefined = undefined;
if (rustup) {
rustInstallation = rustup;
} else {
const rustcSysRoot: string | undefined = await this.loadRustcSysRoot();
if (rustcSysRoot) {
rustInstallation = new NotRustup(rustcSysRoot);
}
};
const rustInstallation: Rustup | NotRustup | undefined = await createRustInstallationPromise();
}
const pathToRustSourceCodeSpecifiedByUser = await this.checkPathToRustSourceCodeSpecifiedByUser();
const configuration = new Configuration(
logger,
Expand Down Expand Up @@ -176,16 +174,13 @@ export class Configuration {
if (this.rlsPathSpecifiedByUser) {
return this.rlsPathSpecifiedByUser;
}

if (this.rustInstallation instanceof Rustup) {
const pathToRlsExecutable = this.rustInstallation.getPathToRlsExecutable();

if (pathToRlsExecutable) {
return pathToRlsExecutable;
}
if (!(this.rustInstallation instanceof Rustup)) {
return undefined;
}

return undefined;
if (!this.rustInstallation.isRlsInstalled()) {
return undefined;
}
return 'rustup';
}

/**
Expand All @@ -198,16 +193,21 @@ export class Configuration {
const getRlsArgsSpecifiedByUser = () => {
const rlsConfiguration: any = this.getRlsConfiguration();
if (!rlsConfiguration) {
return undefined;
return [];
}
const rlsArgsSpecifiedByUser: any = rlsConfiguration.args;
if (!rlsArgsSpecifiedByUser) {
return undefined;
return [];
}
return rlsArgsSpecifiedByUser;
};
const rlsArgs = getRlsArgsSpecifiedByUser() || [];
return rlsArgs;
if (!(this.rustInstallation instanceof Rustup)) {
return getRlsArgsSpecifiedByUser();
}
if (!this.rustInstallation.isRlsInstalled()) {
return getRlsArgsSpecifiedByUser();
}
return ['run', 'nightly', 'rls'].concat(getRlsArgsSpecifiedByUser());
}

/**
Expand Down
99 changes: 63 additions & 36 deletions src/components/configuration/Rustup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,9 +62,12 @@ export class Rustup {
* The method is asynchronous because it tries to find Rust's source code
* @param pathToRustcSysRoot A path to Rust's installation root
*/
public static async create(logger: ChildLogger, pathToRustcSysRoot: string): Promise<Rustup> {
logger.createChildLogger('create: ').debug(`sysroot=${pathToRustcSysRoot}`);
const rustup = new Rustup(logger, pathToRustcSysRoot, undefined, undefined);
public static async create(logger: ChildLogger): Promise<Rustup | undefined> {
const sysrootPath: string | undefined = await this.invokeGettingSysrootPath('nightly', logger);
if (!sysrootPath) {
return undefined;
}
const rustup = new Rustup(logger, sysrootPath, undefined, undefined);
await rustup.updatePathToRustSourceCodePath();
await rustup.updateComponents();
await rustup.updatePathToRlsExecutable();
Expand Down Expand Up @@ -125,7 +128,7 @@ export class Rustup {
*/
public async updateComponents(): Promise<void> {
const logger = this.logger.createChildLogger('updateComponents: ');
const stdoutData: string | undefined = await this.invokeRustup(['component', 'list']);
const stdoutData: string | undefined = await Rustup.invoke(['component', 'list', '--toolchain', 'nightly'], logger);
if (!stdoutData) {
logger.error(`stdoutData=${stdoutData}`);
return undefined;
Expand Down Expand Up @@ -192,6 +195,14 @@ export class Rustup {
return true;
}

/**
* Returns if RLS is installed
* @return true if RLS is installed otherwise false
*/
public isRlsInstalled(): boolean {
return this.isComponentInstalled(Rustup.getRlsComponentName());
}

/**
* Returns true if the component `rust-analysis` can be installed otherwise false.
* If the component is already installed, the method returns false
Expand Down Expand Up @@ -233,6 +244,52 @@ export class Rustup {
return ' (installed)';
}

/**
* Invokes rustup to get the path to the sysroot of the specified toolchain.
* Checks if the invocation exited successfully and returns the output of the invocation
* @param toolchain The toolchain to get the path to the sysroot for
* @param logger The logger to log messages
* @return The output of the invocation if the invocation exited successfully otherwise undefined
*/
private static async invokeGettingSysrootPath(toolchain: string, logger: ChildLogger): Promise<string | undefined> {
const output: string | undefined = await this.invokeRun(toolchain, ['rustc', '--print', 'sysroot'], logger);
if (!output) {
return undefined;
}
return output.trim();
}

/**
* Invokes `rustup run...` with the specified toolchain and arguments, checks if it exited successfully and returns its output
* @param toolchain The toolchain to invoke rustup with
* @param args The arguments to invoke rustup with
* @param logger The logger to log messages
*/
private static async invokeRun(toolchain: string, args: string[], logger: ChildLogger): Promise<string | undefined> {
return await this.invoke(['run', toolchain, ...args], logger);
}

/**
* Invokes Rustup with specified arguments, checks if it exited successfully and returns its output
* @param args Arguments to invoke Rustup with
* @param logger The logger to log messages
* @returns an output if invocation exited successfully otherwise undefined
*/
private static async invoke(args: string[], logger: ChildLogger): Promise<string | undefined> {
const rustupExe = Rustup.getRustupExecutable();
const functionLogger = logger.createChildLogger(`invoke: rustupExe=${rustupExe}, args=${JSON.stringify(args)}: `);
const result = await OutputtingProcess.spawn(rustupExe, args, undefined);
if (!result.success) {
functionLogger.error('failed');
return undefined;
}
if (result.exitCode !== 0) {
functionLogger.error(`exited unexpectedly; exitCode=${result.exitCode}, stderrData=${result.stderrData}`);
return undefined;
}
return result.stdoutData;
}

/**
* Constructs a new instance of the class.
* The constructor is private because creating a new instance should be done via the method `create`
Expand All @@ -258,36 +315,6 @@ export class Rustup {
this.components = [];
}

/**
* Invokes Rustup with specified arguments, checks it exited successfully and returns its output
* @param args Arguments to invoke Rustup with
* @returns an output if invokation Rustup exited successfully otherwise undefined
*/
private async invokeRustup(args: string[]): Promise<string | undefined> {
const logger = this.logger.createChildLogger('invokeRustup: ');

const rustupExe = Rustup.getRustupExecutable();

// We assume that the executable of Rustup can be called since usually both `rustc` and `rustup` are placed in the same directory
const result = await OutputtingProcess.spawn(rustupExe, args, undefined);

if (!result.success) {
// It actually shouldn't happen.
// If it happens, then there is some problem and we need to know about it
logger.error(`failed to execute ${rustupExe}. This should not have happened`);

return undefined;
}

if (result.exitCode !== 0) {
logger.error(`${rustupExe} ${args.join(' ')} exited with code=${result.exitCode}, but zero is expected. This should not have happened. stderrData=${result.stderrData}`);

return undefined;
}

return result.stdoutData;
}

/**
* Takes from the field `components` only installed components
* @returns a list of installed components
Expand Down Expand Up @@ -317,8 +344,8 @@ export class Rustup {
// We return true because the component is installed, but anyway it is an exceptional situation
return true;
}
const args = ['component', 'add', componentName];
const stdoutData: string | undefined = await this.invokeRustup(args);
const args = ['component', 'add', componentName, '--toolchain', 'nightly'];
const stdoutData: string | undefined = await Rustup.invoke(args, logger);
// Some error occurred. It is already logged in the method invokeRustup.
// So we just need to notify a caller that the installation failed
if (stdoutData === undefined) {
Expand Down

0 comments on commit 9e15f1b

Please sign in to comment.