-
Notifications
You must be signed in to change notification settings - Fork 442
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
rust-analyzer
discoverConfig integration
#3073
base: main
Are you sure you want to change the base?
Conversation
Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA). View this failed invocation of the CLA check for more information. For the most up to date status, view the checks section at the bottom of the pull request. |
267aa69
to
ea06599
Compare
@sam-mccall I noticed you've been working on things adjacent to this in other recent PRs. Just adding you here for visibility reasons. Any advice you can offer regarding the PR is more than welcome. |
Thanks! Yes I had a draft version running locally that I'd planned to clean up and send, but I'm happy you got there first. This PR combines a few logically-separate changes. I get it - there are a bunch of details that all need to be right for this to work end-to-end. (I ran into some overlapping-but-different set of these myself). I'll try to understand them all and provide high-level comments first, and then let you figure out whether to split them out and land the more "obvious" stuff first. (e.g. having a separate output-base and injecting blaze configuration are useful, but different users will have different needs here). (I did spot this last friday and started to review, but have been unwell this week...) |
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 is great stuff, really thorough job! Some parts of the protocol (logging & runnables) were totally new to me.
High level:
- starlark changes (proc macros & build scripts) are good. Related: rust_analyzer: generate more reqired sources #3031 includes some other generated files.
- A separate binary for
discover
sounds good to me (I had this as a flag ongen_rust_project
, but it's messy) - this is background infra that should "do what I mean", as such we want fewer flags and more detection.
- some things we will eventually want should inform flags/detection:
- become a standalone binary (not invoked through
blaze run
) - automatically select an
output_base
- become a standalone binary (not invoked through
- a
BlazeSpec
(argv0, workspace, execroot, ...) would be a useful abstraction, replacingConfig
and long param lists - clearer split between main (config + protocol) and library (build+query+describe) would make the code easier to follow.
Let me know what you think - as I said I'm not an owner here. I can nag one to get you a stamp :-) but also feel free to get a second opinion instead.
If you're interested, this could be a few PRs - might go quicker, but totally up to you:
- proc macros + build scripts
- refactor current bin+lib to make lib reusable
- add discover tool
- runnables
@@ -108,6 +223,31 @@ pub fn generate_rust_project( | |||
sysroot: Some(sysroot.into()), | |||
sysroot_src: Some(sysroot_src.into()), | |||
crates: Vec::new(), | |||
runnables: vec![ |
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.
(no action needed) runnables
is not documented in the rust-project.json
spec, we should fix that.
@@ -108,6 +223,31 @@ pub fn generate_rust_project( | |||
sysroot: Some(sysroot.into()), | |||
sysroot_src: Some(sysroot_src.into()), | |||
crates: Vec::new(), | |||
runnables: vec![ | |||
Runnable { |
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.
What's the intended use of build
?
If it's to get diagnostics (which RunnableKind::Check
suggests), it's not clear to me if we should pass --config
, --output_base
etc as we're a tool, or not pass them as we're acting as a simple proxy for the user.
I'm fine with either answer but let's say why in a comment.
Part of this is: are we expecting --config
to be something like --config=generate_simplified_sources_for_rust_analyzer
(should be ignored) or --config=macos
(should be passed)?
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.
What's the intended use of build?
Don't laugh, but I have absolutely no idea. I can't find any place where it is used in rust-analyzer
so it might be a leftover. I initially just copied this from the buck2 implementation, only refining it later. I don't see a reason to keep it, to be honest.
But I think the best course of action would be to raise some issue with rust-analyzer
and see if this serves any purpose before removing it, just to ensure we're not omitting something 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.
Regarding passing --config
and other args, I'm not entirely sure either. It's a very good question so thanks for spotting this, I missed it.
From the top of my head, I'd argue that we should not pass them. The main idea behind the flags are to get the tool itself running in a way that does not obstruct regular usage, like building, running or testing targets. Runnables, while invoked by the tool, do qualify as "regular usage", I think. It's just that instead of typing a command in the terminal you invoke them through the IDE code lens.
No strong opinions here though.
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.
Don't laugh, but I have absolutely no idea
That's perfectly reasonable!
I see TestOne
and Bin
used in rust-analyzer/src/target_spec.rs
, but not Check
, so maybe drop Check
?
For explicit user actions (--test
) I agree we don't need to take any workspace-related shortcuts. Sometimes' there's code that doesn't build in the default config at all, though. In any case, if we punt on --config
for now we can leave this :-)
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.
Note that I ended up removing the --config_group
CLI argument to err on the side of simplicity.
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.
Regarding the RunnableKind::Check
variant, it seems that it was recently added here: rust-lang/rust-analyzer@71a78a9. If I were to guess, this is perhaps meant to help with the implementation of cargo check
like support.
I have no strong opinions, though. We could remove this entirely, simply comment it out or leave it in preparation for better flycheck support for non-cargo projects from rust-analyzer
's side.
tools/rust_analyzer/lib.rs
Outdated
.env_remove("BAZELISK_SKIP_WRAPPER") | ||
.env_remove("BUILD_WORKING_DIRECTORY") | ||
.env_remove("BUILD_WORKSPACE_DIRECTORY") | ||
.arg(format!("--output_base={output_base}")) | ||
.arg("build") |
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.
(no action needed) When we're running in the background, we want to be as forgiving as possible if the user's current state is broken. So eventually we should have --nocheck_visibility
here and possibly elsewhere.
@sam-mccall Sorry for the delay and thank you for the thorough review! I'm not going to have access to my laptop for a few more days but I plan to address all of this after Christmas. Happy holidays :)! |
98aa3b9
to
543cefa
Compare
@sam-mccall My apologies for the delay. Winter break wasn't as restful as I hoped it would be so I got delayed a bit 🙃 . Nevertheless, I addressed the bulk of your concerns. While all your ideas are great, I do feel though that some of them might be out of scope for this PR. In my opinion, the main objective here is getting a working solution for project auto-discovery. While some of the design decisions are questionable, I think an iterative approach might be better, considering that a few issues pertain to code that already existed or was simply moved around for the sake of DRY. In particular, the points revolving around a
Hah, I know what you mean. When I started out on this I attempted the same thing but, while do-able, it only led to convoluted code and pain 😂 .
I think that multiple PR's would've been better if done from the start. However I only worked with bazel for a couple of months and I'm slightly afraid that if we'd be breaking this down now there's a risk of me missing individual pieces that all have to come together for this to work correctly. With the bulk of the work done and all being present here, I find it a easier to just march on with this single PR. If that's not acceptable, for any reason, do let me know.
Perhaps it might be valuable to get a code owner to review this as well, especially since some of your questions are related to pre-existent code. |
No worries at all! I hope you got some time off at least :-)
Yes, fair enough! I'm happy if we can find ways to reduce the scope here. We should be mindful this isn't a small change: it's more than doubling the size of tools/rust_analyzer, and reusing code across binaries. When adding a lot of complexity, we will need to spend some effort improving design. On the command-line interface: I think if we're adding a new tool, it should not expose unnecessary options. That is, copying over the flags/knobs from This interface is important - I think more so than the code that implements it. Once released, it will be difficult to remove features from it, as we cannot see or reason about the callers. Each option is a constraint that makes maintenance harder. (Concrete example:
DRY is library design. If we lift some single-use code into a reusable module, now changes to each user are constrained by the other, and by the module boundary. If we want to iterate cheaply, we should duplicate code and customize it, and defer generalization until later. (I think this is the right approach for the CLI).
Ok, summoning some owners: @UebelAndre @illicitonion @krasimirgg
|
@sam-mccall thanks for thinking about this. On a second thought I agree with you. I'll "duplicate" the config on each binary so we can tweak the discovery one without worrying about the impact on the |
941da7f
to
7e1c943
Compare
I split up the configs so each binary has its own, but I did factor out a I also removed the The Curious about what other people think regarding this. |
Thank you @bobozaur This is exciting! As an owner, I'm happy to go over this PR and help out with the review. On @sam-mccall 's questions:
Yes! I think this is a great feature to have.
Yes, I think you have a lot of good context on this and can provide some good feedback.
Unfortunately I'm not familiar with this part of the codebase... @hlopko might have some insights. My opinions:
It would be nice to set up some sort of a test that exercises the new workflow, since this work touches a lot of places and there are quite some nontrivial interactions that come into play to get this all to work. Maybe we can look up copying and adapting something of the pre-existing gen_rust_project tests. |
@krasimirgg I would like to point out that the structure between I'm on board with testing the |
@sam-mccall I keep thinking about this and the overall config situation. I'm wondering what you have in mind in terms of If you refer to some temp dir output base, I'm not sure that's a good idea. That's what I wanted to achieve with the EDIT: Also, another aspect to keep in mind is that the LATER EDIT: There's also the matter of autodiscovery in polyglot workspaces where no argument is being passed to the |
One other scenario popped up that might be worth considering (if not now, then in a future PR). Since the tool builds build scripts and proc macro targets to provide full support, if you are working on a proc macro crate or a build script and restart rust-analyzer, the build will fail and rust-analyzer will crash. This is, in my opinion, completely understandable. However, if you're using the split workspace approach (passing So, essentially, the aspect should not output the Are there better ideas for handling this? |
First my apologies - I had review comments on the previous revision, and then replied without sending them. (Why do we have that button?) I'm going to send them now, then go through your latest changes. My thoughts on the topics you raised below - mostly these are "let's not try to solve it in this patch".
The default output_base would be We don't need that feature in this PR. But I think it will be a good default, so until we have it I think we should refrain from offering other ways to configure the output base.
Please leave these out of this patch if you don't mind, it's already large enough. (Probably my favorite mechanism is allowing the user to specify extra flags for the bazel invocation. Then they can pass
The no-argument-passed-to-discoverconfig case creates a lot of ambiguity and problems. Why do we need to support it?
Workflows around this are interesting, and I don't understand them well. Ultimately, I think treating the directly-queried "active" package differently from its dependencies on is going to cause problems. Users edit code in multiple packages, different packages are "active" at different times, and we're going to get complex behavior based on sequencing and how rust-analyzer invalidates its cache.
It would be useful to have an end-to-end integration test, which creates a bazel workspace, runs the tool against a source file in it, and verifies the output is sensible. I think this should wait until we're able to run the tool as a standalone binary (rather than under |
#[clap(long, env = "OUTPUT_BASE")] | ||
output_base: Option<Utf8PathBuf>, | ||
|
||
/// The path to a Bazel binary. |
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 remove the bazel
flag, unless you have a strong reason to configure it this way.
I believe it was added to gen_rust_project
to support google's internal use ("blaze"), but in the context of autodiscovery this isn't a useful way to achieve that. We can solve it in another way later.
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.
May I ask what other solutions you have in mind?
I don't have a strong reason for configuring it this way, but it seems simpler to leave it in for now as the discoverConfig
command is configurable.
If we remove it, we'll have to hardcode it.
|
||
/// The path to a `bazelrc` configuration file. | ||
#[clap(long)] | ||
bazelrc: Option<Utf8PathBuf>, |
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.
as mentioned in the discussion - I'd prefer to leave configurability to a future patch if that's OK, it's not clear whether --bazelrc is the best mechanism - letting the user specify bazel flags might be simpler.
bazelrc: Option<Utf8PathBuf>, | ||
|
||
/// The argument that `rust-analyzer` can pass to the binary. | ||
rust_analyzer_argument: Option<RustAnalyzerArg>, |
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.
as mentioned above, I think this can be required, at least initially
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'm also answering here for visibility's sake. The explanation is in the other discussion. I strongly believe this should be supported and, in fact, the recommended way to use the tool. Users should fall back to passing the argument only if necessary.
13b3921
to
2488606
Compare
@sam-mccall Sorry it took longer to get back on this, last week was incredibly busy. Good news though is that I'm taking a longer break from commercial work so I'll have a lot more time to focus on this.
Ah, I misunderstood this then. Yeah, your suggestion sounds good. But I entirely agree with doing this later as this PR keeps growing.
If you strongly prefer doing this in a future PR, that's fine. But there are two points I'd like covered in this PR still:
I really like the extra flags idea, btw. Probably separating them in something like
Because that's the primary way the tool should be used and the way This however comes with limitations that do not exist when the whole codebase is part of the same workspace and indexed together. The main one is that
Sure, agreed. The PR is getting big as it is and this is not that important of a matter but more of a nice-to-have.
Alright, agreed. |
0058f38
to
cf55aff
Compare
Adds a target that can be used for project auto-discovery by using the
discoverConfig
settings as described in therust-analyzer
user manual.Unlike the
gen_rust_project
target, this can be used for dynamic project discovery, and passing{arg}
todiscoverConfig.command
can split big repositories into multiple, smaller workspaces thatrust-analyzer
switches between as needed. Large repositories can make it OOM.At amo, we've used a similar implementation for a while with great success, which is why we figured we might upstream it. The changes also include two additional output groups to ensure that proc-macros and build script targets are built, as
rust-analyzer
depends on these to provide complete IDE support.Additionally, the PR makes use of the
output_base
value inbazel
invocations. We found it helpful to have tools such asrust-analyzer
andclippy
run on a separate bazel server than the one used for building. And aconfig_group
argument was added to provide the ability to provide a config group tobazel
invocations.An attempt to get codelens actions to work was done as well, particularly around tests and binaries. They seem to work, but I'm not 100% sure whether the approach taken is the right one.
Closes #2755 .