-
Notifications
You must be signed in to change notification settings - Fork 1.6k
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
Extend TargetSpec
functionality to rust-project.json
#16135
Extend TargetSpec
functionality to rust-project.json
#16135
Conversation
20733f6
to
8903c89
Compare
☔ The latest upstream changes (presumably #16066) made this pull request unmergeable. Please resolve the merge conflicts. |
8903c89
to
d91586f
Compare
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.
Overall implementation wise it looks good to me, al though I am still a bit on the fence wrt to having flycheck be in here. I am personally still of the opinion that flycheck should not be a direct part of r-a (but a separate extension altogether). Adding it to this file makes that less clear of a separation.
pub enum TargetKindData { | ||
Bin, | ||
/// Any kind of Cargo lib crate-type (dylib, rlib, proc-macro, ...). | ||
Lib, | ||
Example, | ||
Test, | ||
Bench, | ||
BuildScript, | ||
Other, | ||
} |
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 ties the cargo workspace architecture into project-json, I'm not sure that this was something @matklad had in mind when giving this alternative format for project descriptions.
Is there a need for things like BuildScript
and Example
? Bin
, Lib
and Test
(and Other
ofc) seem fine as they are rather general.
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 think #16135 (comment) answers this, but, yeah good catch of the specific smell 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.
They're not really needed, no—they were meant to try and make project-json
more Cargo-like. I only really need Bin
, Lib
and Test
if this PR doesn't take the approach that matklad suggested in his comment.
/// [`project_manifest`] corresponds to the file defining a crate. With Cargo, | ||
/// this will be a Cargo.toml, but with a non-Cargo build system, this might be | ||
/// a `TARGETS` or `BUCK` file. Multiple, distinct crates can share a | ||
/// single `project_manifest`. |
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 comment confuses me given where its placed, this is the field of a CargoTargetSpec
, so this should always be a Cargo.toml
.
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.
Ah—the intention behind this comment is to communicate that a non-Cargo project can also have a TargetSpec
(née CargoTargetSpec
), with the intention of trying to make non-Cargo build systems be more Cargo-like in order to reduce the maintenance burden on rust-analyzer
, but as mentioned elsewhere, that might be a design bug.
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 get that, it's just that the location for this command seems ill placed (as it talks about this struct, but also the copy, yet we are in the docs on the field), though i don't have a better spot for it either aside from somewhere in the module documentation.
@@ -372,7 +372,7 @@ interface Runnable { | |||
} | |||
``` | |||
|
|||
rust-analyzer supports only one `kind`, `"cargo"`. The `args` for `"cargo"` look like this: | |||
rust-analyzer supports two `kind`s of runnables, `"cargo"` and `"rustproject"`. The `args` for `"cargo"` look like 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.
projectjson
, not rustproject
right?
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.
Yes, sorry! I get the two switched up in my head.
@@ -385,6 +385,16 @@ rust-analyzer supports only one `kind`, `"cargo"`. The `args` for `"cargo"` look | |||
} | |||
``` | |||
|
|||
The args for `"jsonproject"` look like: |
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.
projectjson
args: args.slice(1), | ||
cwd: projectJsonRunnableArgs.workspaceRoot, | ||
env: prepareEnv(runnable, config.runnablesExtraEnv), | ||
overrideCargo: "buck2", |
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.
Does this mean only buck2
is supported for projectjson runnables?
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.
Yeah, ideally we'd fetch buck2
string from projectJsonRunnableArgs
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.
Oh, yeah, sorry—I meant to pull this string from configuration. Didn’t realize I left it here.
@@ -202,6 +243,8 @@ struct CrateData { | |||
is_proc_macro: bool, | |||
#[serde(default)] | |||
repository: Option<String>, | |||
#[serde(default)] | |||
target_spec: Option<TargetSpecData>, |
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.
Some notes on JSON side of things here:
I'd maybe call the top-level thing build_info
, as thre might be multiple targets (in buck2 sense) concerning a single crate. And, well, target is already overloaded, so it's better to avoid pilling more meanings onto that poor word.
I think the core feature here should be an inclusion of opaque blob of data, which is transmitted over LSP so that the custom client may interpret this. So, I'd say the basis should look like
build_info: Option<BuildInfo>
struct BuildInfo {
data: serde_json::Value
}
Eg, one can imagine a situation where all builds are remote, and the way you "run" software is by issueing an HTTP request to a remote execution server, and opening a page in the web-browser with results. In this situation, the data
would be an URL to call, and the client-side extension would take care of HTTPing.
But we also should support "standard" workflows where you just run some command line.
So, something like (pardon my TypeScript)
struct BuildInfo {
data: serde_json::Value
runnables: Vec<Runnable>
}
struct Runnable {
kind: "build" | "check" | "test" | "run" | string,
label: string,
argv: string[],
cwd: string
}
This shouldn't use a json map, but rather an array, to be more flexible. Eg, in the future we might want to add --release
and non---release
versions of tests, and with a list it should be simpler. More generally, I've recently read some JSON API guidlines somewhere (don't remember whether though), and one guideline that stuck with me is that you should represent maps in JSON as arrays (assoc lists). I think that's a good guideline and something we should be using in gerneral.
Then, the kind
should be a semi-open enum. rust-analyzer should treat build
, run
, check
and test
specially, but it should also be able to show other tasks in GUI. Eg, you can imagine a "flush" task for an embedded build system, or some such.
We might want to split check
into two --- one check that is run for the user and displays errors in the terminal, and another check that runs with message-format=json and is used for flycheck. I guess we could call those check
and flycheck
?
For tests, we need to think how to enable filtering. The core feature is that you can run a single test using cargo test -- $TEST_NAME
, and all tests using cargo test
. Note that this might be very different in non-cargo build systems. Eg, it could be builder test
and builder test --test-filter=$TEST_NAME
, where builder test --test-filter=''
would run zero tests, rather than all tests. So I think for test, we should also split it into two: "testall" and "testone". And, for "testone", I think we want to make argv
a template. That is, argv could look like
["builder", "test", "--test-filter=$$TEST_NAME$$", "./buildfile.b"]
We shouldn't assume that filter is always last, and that its always a separate argument.
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.
Thanks for the feedback here!
I'd maybe call the top-level thing
build_info
, as thre might be multiple targets (in buck2 sense) concerning a single crate. And, well, target is already overloaded, so it's better to avoid pilling more meanings onto that poor word.
That's a fair point. I didn't intend for the naming to be Buck/Bazel-esque "targets", I mean to invoke the target concept in Cargo, of all things. In any case, target
is too overloaded and I'll move over to build_info
.
I think the core feature here should be an inclusion of opaque blob of data, which is transmitted over LSP so that the custom client may interpret this.
Is the idea that a companion extension to rust-lang.rust-analyzer
(e.g., something for Buck or Bazel) would be responsible for assembling that opaque blob of data into a some sort of meaningful runnable command or is more that since I'm making this change now, I should make it more futureproof ("[B]ut we also should support "standard" workflows where you just run some command line.")? I ask since I'm working on a variable interpreter/template thingy, which—I think—should make expressing arbitrary build/test commands a lot easier in rust-analyzer itself, which reduces the pressure/need for end-users to install other extensions for runnables.
This shouldn't use a json map, but rather an array, to be more flexible. Eg, in the future we might want to add
--release
and non---release
versions of tests, and with a list it should be simpler. More generally, I've recently read some JSON API guidlines somewhere (don't remember whether though), and one guideline that stuck with me is that you should represent maps in JSON as arrays (assoc lists). I think that's a good guideline and something we should be using in gerneral.
That seems reasonable to me! I was considering how to tackle this for Buck1 and this seems like a good approach.
Then, the
kind
should be a semi-open enum. rust-analyzer should treatbuild
,run
,check
andtest
specially, but it should also be able to show other tasks in GUI. Eg, you can imagine a "flush" task for an embedded build system, or some such.
Yeah, that seems smart.
We might want to split
check
into two --- onecheck
that is run for the user and displays errors in the terminal, and another check that runs withmessage-format=json
and is used for flycheck. I guess we could call thosecheck
andflycheck
?
I think now's a good time to make this change, especially if the new runnable API is a breaking change.
For tests, we need to think how to enable filtering. The core feature is that you can run a single test using cargo test -- $TEST_NAME
, and all tests using cargo test
. Note that this might be very different in non-cargo build systems. Eg, it could be builder test
and builder test --test-filter=$TEST_NAME
, where builder test --test-filter=''
would run zero tests, rather than all tests. So I think for test, we should also split it into two: "testall"
and "testone"
. And, for "testone"
, I think we want to make argv
a template. That is, argv could look like: [redacted for quoting ease]
I don't think I've fully gotten this into my head yet (sorry, lots of travel!) but I think I see the utility of a change like this.
I think I'd like like a debug
variant as well, but I haven't really through this specific aspect through.
Footnotes
-
For context, buck2 is moving to a modifier-style approach. A user can write
buck2 build repo//foo:bar?linux,release
, which translate to "build repo//foo:bar
for Linux usingrelease
". there's a more verbose--modifier
-style API, but I suspect that both options can work when called from rust-analyzer or I suspect the Buck team will be flexible in implementing this. ↩
I guess whether the format has that or not makes little difference, the command itself is heavily tied into the rest of the specification here whether it is supported by a separate extension or r-a. |
While I agree with you that flycheck is a hack, I've found myself of the opinion that And yeah, I think the command's specification is largely immaterial to where it runs, or at the very least, it's not a binding commitment in one direction or another. |
☔ The latest upstream changes (presumably #16398) made this pull request unmergeable. Please resolve the merge conflicts. |
d91586f
to
ec581f9
Compare
☔ The latest upstream changes (presumably #16612) made this pull request unmergeable. Please resolve the merge conflicts. |
ec581f9
to
11c7eac
Compare
☔ The latest upstream changes (presumably #16845) made this pull request unmergeable. Please resolve the merge conflicts. |
Refactor extension to support arbitrary shell command runnables Currently, the extension assumes that all runnables invoke cargo. Arguments are sometimes full CLI arguments, and sometimes arguments passed to a cargo subcommand. Refactor the extension so that tasks are just a `program` and a list of strings `args`, and rename `CargoTask` to `RustTask` to make it generic. (This was factored out of #16135 and tidied.)
089a35d
to
843626e
Compare
☔ The latest upstream changes (presumably #16971) made this pull request unmergeable. Please resolve the merge conflicts. |
843626e
to
4c8759c
Compare
☔ The latest upstream changes (presumably #16970) made this pull request unmergeable. Please resolve the merge conflicts. |
Allow rust-project.json to include arbitrary shell commands for runnables This is a follow-up on #16135, resolving the feedback raised :) Allow rust-project.json to include shell runnables, of the form: ``` { "build_info": { "label": "//project/foo:my-crate", "target_kind": "bin", "shell_runnables": [ { "kind": "run", "program": "buck2", "args": ["run", "//project/foo:my-crate"] }, { "kind": "test_one", "program": "test_runner", "args": ["--name=$$TEST_NAME$$"] } ] } } ``` If these runnable configs are present for the current crate in rust-project.json, offer them as runnables in VS Code. This PR required some boring changes to APIs that previously only handled cargo situations. I've split out these changes as commits labelled 'refactor', so it's easy to see the interesting changes.
Resolves #15892.
This PR, as structured, adds runnable support to
rust-project.json
-based workspaces, and that works pretty nicely. It's not as polished as I'd like it to be (namely: interpolation oftest_id
feels a bit janky and undocumented, the), but I'm opening this PR as a draft for general direction/feedback.I think that this approach can also make #15476 unnecessary by adding a
flycheck_command
torust-project.json
while also extending similar functionality to Cargo only build the impacted crate.