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

Do not start racer if it is known that it is not installed #189

Merged
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
70 changes: 50 additions & 20 deletions src/components/completion/completion_manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,6 @@ export default class CompletionManager {
private tmpFile: string;
private providers: Disposable[];
private listeners: Disposable[];
private racerPath: string;
private typeMap: { [type: string]: CompletionItemKind } = {
'Struct': CompletionItemKind.Class,
'Module': CompletionItemKind.Module,
Expand Down Expand Up @@ -110,14 +109,29 @@ export default class CompletionManager {
}

/**
* Starts itself at first time
* Starts itself at first time.
* Starting fails if a user does not have either racer or Rust's source code
*/
public initialStart(): void {
public async initialStart(): Promise<void> {
const logger = this.logger.createChildLogger('initialStart: ');

const pathToRacer: string | undefined = this.configuration.getPathToRacer();

if (!pathToRacer) {
logger.createChildLogger('racer is not installed');

return;
}

const isSourceCodeAvailable: boolean = this.ensureSourceCodeIsAvailable();

if (isSourceCodeAvailable) {
this.start();
if (!isSourceCodeAvailable) {
logger.createChildLogger('Rust\'s source is not installed');

return;
}

this.start(pathToRacer);
}

/**
Expand Down Expand Up @@ -146,8 +160,9 @@ export default class CompletionManager {

/**
* Starts Racer as a daemon, adds itself as definition, completion, hover, signature provider
* @param pathToRacer A path to the executable of racer which does exist
*/
private start(): void {
private start(pathToRacer: string): void {
const logger = this.logger.createChildLogger('start: ');

logger.debug('enter');
Expand All @@ -159,9 +174,7 @@ export default class CompletionManager {
this.lastCommand = '';
this.providers = [];

this.racerPath = this.configuration.getRacerPath();

logger.debug(`racerPath=${this.racerPath}`);
logger.debug(`racerPath=${pathToRacer}`);

this.racerStatusBarItem.showTurnedOn();
const cargoHomePath = this.configuration.getCargoHomePath();
Expand All @@ -184,7 +197,7 @@ export default class CompletionManager {
logger.debug(`ENV[RUST_SRC_PATH] = ${racerSpawnOptions.env['RUST_SRC_PATH']}`);

this.racerDaemon = spawn(
this.racerPath,
pathToRacer,
['--interface=tab-text', 'daemon'],
racerSpawnOptions
);
Expand All @@ -198,7 +211,7 @@ export default class CompletionManager {
} else {
this.racerStatusBarItem.showCrashed();

this.scheduleRestart();
this.scheduleRestart(pathToRacer);
}
});
this.racerDaemon.on('close', (code: number, signal: string) => {
Expand All @@ -211,7 +224,7 @@ export default class CompletionManager {
} else {
this.racerStatusBarItem.showCrashed();

this.scheduleRestart();
this.scheduleRestart(pathToRacer);
}
});

Expand All @@ -225,11 +238,13 @@ export default class CompletionManager {

this.hookCapabilities();

this.listeners.push(workspace.onDidChangeConfiguration(() => {
const newPath = this.configuration.getRacerPath();
this.listeners.push(workspace.onDidChangeConfiguration(async () => {
await this.configuration.updatePathToRacer();

if (this.racerPath !== newPath) {
this.restart();
const newPathToRacer: string | undefined = this.configuration.getPathToRacer();

if (pathToRacer !== newPathToRacer) {
this.restart(newPathToRacer);
}
}));
}
Expand All @@ -243,15 +258,30 @@ export default class CompletionManager {
this.clearCommandCallbacks();
}

public restart(): void {
/**
* Stops the current running instance of racer and starts a new one if a path is defined
* @param pathToRacer A path to the executable of racer
*/
public restart(pathToRacer: string | undefined): void {
this.logger.warning('restart');

this.stop();
this.start();

if (pathToRacer) {
this.start(pathToRacer);
}
}

private scheduleRestart(): void {
setTimeout(this.restart.bind(this), 3000);
/**
* Schedules a restart after some time
* @param pathToRacer A path to the executable of racer
*/
private scheduleRestart(pathToRacer: string): void {
const onTimeout = () => {
this.restart(pathToRacer);
};

setTimeout(onTimeout, 3000);
}

private stopDaemon(): void {
Expand Down
73 changes: 66 additions & 7 deletions src/components/configuration/Configuration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,15 @@ export class Configuration {
*/
private pathToRlsSpecifiedByUser: string | undefined;

/**
* A path to the executable of racer.
* It contains a value of either:
* - the configuration parameter `rust.racerPath`
* - a path found in any of directories specified in the envirionment variable PATH
* The configuration parameter has higher priority than automatically found path
*/
private pathToRacer: string | undefined;

/**
* Creates a new instance of the class.
* This method is asynchronous because it works with the file system
Expand Down Expand Up @@ -83,6 +92,7 @@ export class Configuration {
logger,
rustInstallation,
pathToRustSourceCodeSpecifiedByUser,
undefined,
undefined
);

Expand All @@ -91,6 +101,57 @@ export class Configuration {
return configuration;
}

/**
* Updates the value of the field `pathToRacer`.
* It checks if a user specified any path in the configuration.
* If no path specified or a specified path can't be used, it finds in directories specified in the environment variable PATH.
* This method is asynchronous because it checks if a path exists before setting it to the field
*/
public async updatePathToRacer(): Promise<void> {
const logger = this.logger.createChildLogger('updatePathToRacer: ');

this.pathToRacer = undefined;

const pathToRacerSpecifiedByUser: string | undefined = Configuration.getPathConfigParameter('racerPath');

const doesPathToRacerSpecifiedByUserExist: boolean = pathToRacerSpecifiedByUser
? await FileSystem.doesFileOrDirectoryExists(pathToRacerSpecifiedByUser)
: false;

if (doesPathToRacerSpecifiedByUserExist) {
// A user specified existing path, we will use it

logger.debug(`Path specified by a user exists. Path=${pathToRacerSpecifiedByUser}`);

this.pathToRacer = pathToRacerSpecifiedByUser;

return;
}

// Either a user specified an invalid path or a user specified nothing
// Let's try to find a path to the executable of racer
const foundPathToRacer: string | undefined = await FileSystem.findExecutablePath('racer');

if (!foundPathToRacer) {
// We couldn't find any executable of Racer

logger.debug('Failed to find racer in PATH');

return;
}

logger.debug(`Found racer=${foundPathToRacer}`);

this.pathToRacer = foundPathToRacer;
}

/**
* Returns a value of the field `pathToRacer`
*/
public getPathToRacer(): string | undefined {
return this.pathToRacer;
}

/**
* Returns either a path to the executable of RLS or undefined
*/
Expand Down Expand Up @@ -257,12 +318,6 @@ export class Configuration {
return configPath || envPath || undefined;
}

public getRacerPath(): string {
const racerPath = Configuration.getPathConfigParameter('racerPath');

return racerPath || 'racer';
}

public getRustfmtPath(): string {
const rustfmtPath = Configuration.getPathConfigParameter('rustfmtPath');

Expand Down Expand Up @@ -424,12 +479,14 @@ export class Configuration {
* @param rustInstallation A value for the field `rustInstallation`
* @param pathToRustSourceCodeSpecifiedByUser A value for the field `pathToRustSourceCodeSpecifiedByUser`
* @param pathToRlsSpecifiedByUser A value for the field `pathToRlsSpecifiedByUser`
* @param pathToRacer A value for the field `pathToRacer`
*/
private constructor(
logger: ChildLogger,
rustInstallation: Rustup | NotRustup | undefined,
pathToRustSourceCodeSpecifiedByUser: string | undefined,
pathToRlsSpecifiedByUser: string | undefined
pathToRlsSpecifiedByUser: string | undefined,
pathToRacer: string | undefined
) {
this.logger = logger;

Expand All @@ -438,6 +495,8 @@ export class Configuration {
this.pathToRustSourceCodeSpecifiedByUser = pathToRustSourceCodeSpecifiedByUser;

this.pathToRlsSpecifiedByUser = pathToRlsSpecifiedByUser;

this.pathToRacer = pathToRacer;
}

private static getStringParameter(parameterName: string): string | null {
Expand Down
11 changes: 9 additions & 2 deletions src/components/tools_installation/installator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,8 +92,8 @@ export default class Installator {

logger.debug(`pathDirectories=${JSON.stringify(pathDirectories)}`);

const tools: { [tool: string]: string } = {
'racer': this.configuration.getRacerPath(),
const tools: { [tool: string]: string | undefined } = {
'racer': this.configuration.getPathToRacer(),
'rustfmt': this.configuration.getRustfmtPath(),
'rustsym': this.configuration.getRustsymPath()
};
Expand All @@ -105,6 +105,13 @@ export default class Installator {
const missingTools = keys.map(tool => {
// Check if the path exists as-is.
let userPath = tools[tool];

if (!userPath) {
// A path is undefined, so a tool is missing

return tool;
}

if (existsSync(userPath)) {
logger.debug(`${tool}'s path=${userPath}`);

Expand Down
8 changes: 4 additions & 4 deletions src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,7 @@ export async function activate(ctx: ExtensionContext): Promise<void> {
logger.createChildLogger('Cargo Manager: ')
);

chooseModeAndRun(ctx, logger, configuration, currentWorkingDirectoryManager);
await chooseModeAndRun(ctx, logger, configuration, currentWorkingDirectoryManager);

addExecutingActionOnSave(ctx, configuration, cargoManager);
}
Expand Down Expand Up @@ -243,12 +243,12 @@ function runInRlsMode(
languageClientManager.initialStart();
}

function chooseModeAndRun(
async function chooseModeAndRun(
context: ExtensionContext,
logger: RootLogger,
configuration: Configuration,
currentWorkingDirectoryManager: CurrentWorkingDirectoryManager
): void {
): Promise<void> {
const pathToRlsExecutable = configuration.getPathToRlsExecutable();

if (pathToRlsExecutable) {
Expand All @@ -261,7 +261,7 @@ function chooseModeAndRun(
logger.createChildLogger('Legacy Mode Manager: ')
);

legacyModeManager.start();
await legacyModeManager.start();
}
}

Expand Down
14 changes: 11 additions & 3 deletions src/legacy_mode_manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ import MissingToolsInstallator from './components/tools_installation/installator
export default class LegacyModeManager {
private context: ExtensionContext;

private configuration: Configuration;

private completionManager: CompletionManager;

private formattingManager: FormattingManager;
Expand All @@ -40,6 +42,8 @@ export default class LegacyModeManager {
) {
this.context = context;

this.configuration = configuration;

this.completionManager = new CompletionManager(
context,
configuration,
Expand All @@ -64,11 +68,15 @@ export default class LegacyModeManager {
configuration,
logger.createChildLogger('MissingToolsInstallator: ')
);
this.missingToolsInstallator.addStatusBarItemIfSomeToolsAreMissing();
}

public start(): void {
public async start(): Promise<void> {
this.context.subscriptions.push(this.completionManager.disposable());
this.completionManager.initialStart();

await this.configuration.updatePathToRacer();

await this.missingToolsInstallator.addStatusBarItemIfSomeToolsAreMissing();

await this.completionManager.initialStart();
}
}