Skip to content
This repository was archived by the owner on Nov 18, 2022. It is now read-only.

Use local active toolchain as default for rust-client.channel #220

Merged
merged 2 commits into from
Jan 15, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -165,8 +165,11 @@
"description": "Update the RLS whenever the extension starts up."
},
"rust-client.channel": {
"type": "string",
"default": "nightly",
"type": [
"string",
"null"
],
"default": null,
"description": "Rust channel to install RLS from."
},
"rust-client.rls-name": {
Expand Down
27 changes: 26 additions & 1 deletion src/configuration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
import { workspace, WorkspaceConfiguration } from 'vscode';
import { RevealOutputChannelOn } from 'vscode-languageclient';

import { getActiveChannel } from './rustup';

function fromStringToRevealOutputChannelOn(value: string): RevealOutputChannelOn {
switch (value && value.toLowerCase()) {
case 'info':
Expand Down Expand Up @@ -58,15 +60,38 @@ export class RLSConfiguration {
this.revealOutputChannelOn = RLSConfiguration.readRevealOutputChannelOn(configuration);
this.updateOnStartup = configuration.get<boolean>('rust-client.updateOnStartup', true);

this.channel = configuration.get('rust-client.channel', 'nightly');
this.channel = RLSConfiguration.readChannel(this.rustupPath, configuration);
this.componentName = configuration.get('rust-client.rls-name', 'rls');

// Hidden options that are not exposed to the user
this.rlsPath = configuration.get('rls.path', null);
this.rlsRoot = configuration.get('rls.root', null);
}

private static readRevealOutputChannelOn(configuration: WorkspaceConfiguration) {
const setting = configuration.get<string>('rust-client.revealOutputChannelOn', 'never');
return fromStringToRevealOutputChannelOn(setting);
}

/**
* Tries to fetch the `rust-client.channel` configuration value. If missing,
* falls back on active toolchain specified by rustup (at `rustupPath`),
* finally defaulting to `nightly` if all fails.
*/
private static readChannel(rustupPath: string, configuration: WorkspaceConfiguration): string {
const channel = configuration.get<string | null>('rust-client.channel', null);
if (channel !== null) {
return channel;
} else {
try {
return getActiveChannel(rustupPath);
}
// rustup might not be installed at the time the configuration is
// initially loaded, so silently ignore the error and return a default value
catch (e) {
return 'nightly';
}

}
}
}
2 changes: 2 additions & 0 deletions src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ import { commands, ExtensionContext, IndentAction, languages, TextEditor,
import { LanguageClient, LanguageClientOptions, Location, NotificationType,
ServerOptions } from 'vscode-languageclient';

// FIXME(#233): Don't only rely on lazily initializing it once on startup,
// handle possible `rust-client.*` value changes while extension is running
export const CONFIGURATION = RLSConfiguration.loadFromWorkspace();

function getSysroot(env: Object): string | Error {
Expand Down
43 changes: 41 additions & 2 deletions src/rustup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
'use strict';

import * as child_process from 'child_process';
import { window } from 'vscode';
import { window, workspace } from 'vscode';

import { execChildProcess } from './utils/child_process';
import { startSpinner, stopSpinner } from './spinner';
Expand Down Expand Up @@ -172,4 +172,43 @@ async function installRls(): Promise<void> {
}

stopSpinner('RLS components installed successfully');
}
}

/**
* Parses given output of `rustup show` and retrieves the local active toolchain.
*/
export function parseActiveToolchain(rustupOutput: string): string {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This isn't async, since it needs to finish to return a value with which global RLSConfiguration is created.
For the same reason it only parses the result and it's not a complete function that uses CONFIGURATION.rustupPath value, since it's called during CONFIGURATION construction.

As a side note, the configuration probably will need to be redesigned later on, as currently it's a global that's lazily constructed once and doesn't handle 'rust-client.*' value changes

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you add the 'side note' as a FIXME or file an issue please?

// There may a default entry under 'installed toolchains' section, so search
// for currently active/overridden one only under 'active toolchain' section
const activeToolchainsIndex = rustupOutput.search('active toolchain');
if (activeToolchainsIndex === -1) {
throw new Error(`couldn't find active toolchains`);
}

rustupOutput = rustupOutput.substr(activeToolchainsIndex);

const matchActiveChannel = new RegExp(/^(\S*) \((?:default|overridden)/gm);
const match = matchActiveChannel.exec(rustupOutput);
if (match === null) {
throw new Error(`couldn't find active toolchain under 'active toolchains'`);
} else if (match.length > 2) {
throw new Error(`multiple active toolchains found under 'active toolchains'`);
}

return match[1];
}

/**
* Returns active (including local overrides) toolchain, as specified by rustup.
* May throw if rustup at specified path can't be executed.
*/
export function getActiveChannel(rustupPath: string, cwd = workspace.rootPath): string {
// rustup info might differ depending on where it's executed
// (e.g. when a toolchain is locally overriden), so executing it
// under our current workspace root should give us close enough result
const output = child_process.execSync(`${rustupPath} show`, {cwd: cwd}).toString();

const activeChannel = parseActiveToolchain(output);
console.info(`Detected active channel: ${activeChannel} (since 'rust-client.channel' is unspecified)`);
return activeChannel;
}