-
Notifications
You must be signed in to change notification settings - Fork 682
Add support for Rust #1606
base: master
Are you sure you want to change the base?
Add support for Rust #1606
Conversation
Thank you for your pull request and welcome to our community. We require contributors to sign our Contributor License Agreement, and we don't seem to have you on file. In order for us to review and merge your code, please sign up at https://code.facebook.com/cla. If you are contributing on behalf of someone else (eg your employer), the individual CLA may not be sufficient and your employer may need the corporate CLA signed. If you have received this in error or have any questions, please contact us at cla@fb.com. Thanks! |
const buildTarget = normalizeNameForBuckQuery(task.buildTarget); | ||
|
||
// TODO: Filter by known Rust build targets | ||
const files = await getRustInputs(task.buckRoot, buildTarget); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This still requires explicit filtering for rust_*
target kinds.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
please do this filtering to avoid calling the expensive buck query
unless we're sure this is a rust target & this call will have value.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done in 8d4772f. Forgot to remove the comment, sorry!
@Xanewok I think its OK as a placeholder. I hope we can get something more elegant in the longer term though. |
Definitely, I am conviced this will not be an issue anymore once the RLS natively supports custom build systems. Update: rust-lang/rust#53870 has been merged and the newest Rust nightly (2018-09-04) contains the RLS binary supporting external simple build systems (needed for this) out of box, as well as external Rustfmt. |
const buildTarget = normalizeNameForBuckQuery(task.buildTarget); | ||
|
||
// TODO: Filter by known Rust build targets | ||
const files = await getRustInputs(task.buckRoot, buildTarget); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
please do this filtering to avoid calling the expensive buck query
unless we're sure this is a rust target & this call will have value.
pkg/nuclide-rust/lib/BuckUtils.js
Outdated
); | ||
} | ||
|
||
export function getSaveAnalysisTargets( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
change to use async / await :
export async function getSaveAnalysisTargets(
...
const deps = await BuckService.query(buckRoot, query, []);
return deps.map(dep => dep + '#save-analysis');
}
logger.debug(`analysisTargets: ${analysisTargets.join('\n')}`); | ||
const artifacts: Array<string> = []; | ||
|
||
const buildReport = await BuckService.build(task.buckRoot, analysisTargets); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
how long does this typically take for large rust targets? do we need to report its progress?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It depends; using cargo check
as example, complete check build can even take a minute or two; rechecking the leaf only shouldn't take longer than a couple of seconds. Third party deps are vendored and pre-compiled from what I understand, so this should also further cut down compilation time. @jsgf would know more about how long exactly these #save-analysis
builds take in the Buck environment.
It would certainly be good to report the progress - do you know if it's possible to pass a callback or report the progress gracefully using the Buck API here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changed this to display a busy spinner indicator while the save-analysis build executes.
const fileUri = task.buckRoot + '/' + files[0]; | ||
logger.debug(`fileUri: ${fileUri}`); | ||
|
||
const langService = await service.getLanguageServiceForUri(fileUri); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's an invalid assumption here that the multi-project language service will only have one LSP server that we need to update its build command (while in reality there can be multiple buck roots, each having a different LSP server -- according to the project files config below).
Do you need to getAllLanguageServices
or observeLanguageServices
?
Can you test with multiple buck roots to see if things work properly?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I understood that MultiLspLanguageService spawn separate LSP server per appropriate 'top-level' project config files like .hhconfig and that calling this seems like a good way to retrieve a handle to appropriate LSP server that's responsible for the fileUri we're building.
However, I did assume there's going to be a single Buck root; I'll see if it works with multiple ones.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@mostafaeweda sorry it took so long! Just tested this with multiple buck roots, using https://github.com/Xanewok/rust-buck-skeleton and building both //server:server
and nested//:nested
. This correctly retrieved the LSP server at root dir and nested/, respectively, so this looks good so far =)
pkg/nuclide-rust/lib/main.js
Outdated
|
||
class Activation { | ||
_rustLanguageService: AtomLanguageService<LanguageService>; | ||
_buckTaskRunnerService: ?BuckTaskRunnerService; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we don't seem to need this to be an instance variable, right?
pkg/nuclide-rust/lib/main.js
Outdated
} | ||
|
||
consumeBuckTaskRunner(service: BuckTaskRunnerService): IDisposable { | ||
service.onDidCompleteTask(task => |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
that's a non disposed registration, maybe this function should just:
return service.onDidCompleteTask...
Also consume Buck task service to later rebuild index on save
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.
For example, running `buck build cell//:target` will create output with paths relative to the cell, and not the current Buck root.
I could've sworn it worked with relative directories - it boiled down to ```js const buildFile = ...; // relative return fsPromise.findNearestFile('.buckconfig', buildFile); ``` which *should* work for relative files, I believe?
cb2ee59
to
384c616
Compare
@mostafaeweda @jsgf Rebased and pushed two changes: one being displaying busy indicator while the Buck builds the save-analysis build and the other one working around a Buck bug (9f64faf), where outputs are relative to the cell, even when these are executed from the outer Buck root. Does this still need more work or can we land it as the 1st increment? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seems ready to roll 🥇(the only comment I have here is trying to avoid unnecessary buck queries if the build task completed isn't actually a rust target).
@jsgf to land this diff, you'd need to click 'Import to Phabricator' and once landed internally (source of truth), in 5 minutes, it'll sync the changes to github.
Thank you for signing our Contributor License Agreement. We can now accept your code for this (and any) Facebook open source project. Thanks! |
@jsgf signed the CLA here, just in case. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
mostafaeweda has imported this pull request. If you are a Facebook employee, you can view this diff on Phabricator.
This sets up preliminary support for Rust in Buck.
It uses the Rust Language Server (RLS) LSP server to provide necessary IDE features.
Since RLS and Cargo (the Rust package manager) don't support custom build systems out of box yet, this uses a hacky workaround for the moment. The user has to explicitly build a Rust target in Buck using the Buck toolbar - this in turn executes the
#save-analysis
flavor build and passes location of the resulting JSON save-analysis (index) files to the RLS. For this, the files should be saved first, before executing the build.Until rust-lang/rust#53870 lands and the updated RLS will ship with a Rust toolchain, it has to be built manually using recent Rust nightly compiler and to have its executable pointed at by the user.
Currently the workflow is fragile - if the users starts editing the files without the explicit build first, the RLS can crash because how much it's currently tied to Cargo. This should be fixed when rust-lang/rls#1026 is implemented (at least stop it from crashing).
cc @jsgf @mostafaeweda @sunshowers