forked from facebookarchive/nuclide
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
After hitting Buck build button, the relevant save-analysis Buck build is performed and RLS is supplied with a dummy build command to retrieve necessary save-analysis indexing files. Things left to do/worth noting: * We should detect if Buck is an appropriate build system for a given LSP service and if not, not override RLS' external build command * Until path remapping lands in rustc (rust-lang/rust#53110) the index-based features (find refs, goto def etc.) only work for source files in the buck-out/**/$TARGET#save-analysis-container source files. * RLS needs some bugfixin' since currently external build command does not properly refresh file dirty state, leading to an endless build loop.
- Loading branch information
Showing
4 changed files
with
144 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
/** | ||
* Copyright (c) 2015-present, Facebook, Inc. | ||
* All rights reserved. | ||
* | ||
* This source code is licensed under the license found in the LICENSE file in | ||
* the root directory of this source tree. | ||
* | ||
* @flow | ||
* @format | ||
*/ | ||
|
||
import type {TaskInfo} from '../../nuclide-buck/lib/types'; | ||
import type { | ||
AtomLanguageService, | ||
LanguageService, | ||
} from '../../nuclide-language-service'; | ||
|
||
import invariant from 'invariant'; | ||
import {getLogger} from 'log4js'; | ||
import fsPromise from 'nuclide-commons/fsPromise'; | ||
import nuclideUri from 'nuclide-commons/nuclideUri'; | ||
import {getRustInputs, getSaveAnalysisTargets, normalizeNameForBuckQuery} from './BuckUtils'; | ||
|
||
import * as BuckService from '../../nuclide-buck-rpc'; | ||
|
||
const logger = getLogger('nuclide-rust'); | ||
|
||
export async function updateRlsBuildForTask( | ||
task: TaskInfo, | ||
service: AtomLanguageService<LanguageService>, | ||
) { | ||
const buildTarget = normalizeNameForBuckQuery(task.buildTarget); | ||
|
||
const files = await getRustInputs(task.buckRoot, buildTarget); | ||
// Probably not a Rust build target, ignore | ||
if (files.length == 0) | ||
return; | ||
// We need only to pick a representative file to get a related lang service | ||
const fileUri = task.buckRoot + '/' + files[0]; | ||
atom.notifications.addInfo(`fileUri: ${fileUri}`); | ||
|
||
const langService = await service.getLanguageServiceForUri(fileUri); | ||
invariant(langService != null); | ||
|
||
// Since `buck` execution is not trivial - the command may be overriden, needs | ||
// to inherit the environment, passes internal FB USER to env etc. the RLS | ||
// can't just invoke that. | ||
// Instead, we build now, copy paths to resulting .json analysis artifacts to | ||
// a temp file and just use `cat $TMPFILE` as a dummy build command. | ||
const analysisTargets = await getSaveAnalysisTargets(task.buckRoot, buildTarget); | ||
logger.debug(`analysisTargets: ${analysisTargets.join('\n')}`); | ||
let artifacts: Array<string> = []; | ||
|
||
const buildReport = await BuckService.build(task.buckRoot, analysisTargets); | ||
if (buildReport.success === false) { | ||
atom.notifications.addError("save-analysis build failed"); | ||
return; | ||
} | ||
|
||
Object.values(buildReport.results) | ||
// TODO: https://buckbuild.com/command/build.html specifies that for | ||
// FETCHED_FROM_CACHE we might not get an output file - can we force it | ||
// somehow? Or we always locally produce a save-analysis .json file? | ||
.forEach((targetReport: any) => artifacts.push(targetReport.output)); | ||
|
||
const tempfile = await fsPromise.tempfile(); | ||
await fsPromise.writeFile(tempfile, artifacts.join('\n')); | ||
|
||
// TODO: Windows? | ||
const buildCommand = `cat ${tempfile}`; | ||
|
||
logger.debug(`Built SA artifacts: ${artifacts.join('\n')}`); | ||
logger.debug(`buildCommand: ${buildCommand}`); | ||
|
||
langService.sendLspNotification(fileUri, 'workspace/didChangeConfiguration', | ||
{ | ||
settings: { | ||
rust: { | ||
unstable_features: true, // Required for build_command | ||
build_on_save: true, | ||
build_command: buildCommand, // TODO: Only in RLS branch: https://github.com/Xanewok/rls/tree/external-build | ||
} | ||
} | ||
}); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
/** | ||
* Copyright (c) 2015-present, Facebook, Inc. | ||
* All rights reserved. | ||
* | ||
* This source code is licensed under the license found in the LICENSE file in | ||
* the root directory of this source tree. | ||
* | ||
* @flow strict-local | ||
* @format | ||
*/ | ||
|
||
import type {TaskInfo} from '../../nuclide-buck/lib/types'; | ||
|
||
import * as BuckService from '../../nuclide-buck-rpc'; | ||
|
||
export function getRustInputs(buckRoot: string, buildTarget: BuildTarget): Promise<Array<string>> { | ||
return BuckService. | ||
query(buckRoot, `filter('.*\\.rs$', inputs('${buildTarget}'))`, []); | ||
} | ||
|
||
export function getSaveAnalysisTargets(buckRoot: string, buildTarget: BuildTarget): Promise<Array<string>> { | ||
// Save-analysis build flavor is only supported by rust_{binary, library} | ||
// kinds (so exclude prebuilt_rust_library kind) | ||
const query: string = `kind('^rust_.*', deps(${buildTarget}))`; | ||
|
||
return BuckService.query(buckRoot, query, []).then(deps => | ||
deps.map(dep => dep + '#save-analysis'), | ||
); | ||
} | ||
|
||
export type BuildTarget = string; | ||
|
||
// FIXME: Copied from nuclide-buck-rpc | ||
// Buck query doesn't allow omitting // or adding # for flavors, this needs to be fixed in buck. | ||
export function normalizeNameForBuckQuery(aliasOrTarget: string): BuildTarget { | ||
let canonicalName = aliasOrTarget; | ||
// Don't prepend // for aliases (aliases will not have colons or .) | ||
if ( | ||
(canonicalName.indexOf(':') !== -1 || canonicalName.indexOf('.') !== -1) && | ||
canonicalName.indexOf('//') === -1 | ||
) { | ||
canonicalName = '//' + canonicalName; | ||
} | ||
// Strip flavor string | ||
const flavorIndex = canonicalName.indexOf('#'); | ||
if (flavorIndex !== -1) { | ||
canonicalName = canonicalName.substr(0, flavorIndex); | ||
} | ||
return canonicalName; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters