Skip to content
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

Make it easier to build an artifact and record its path #153

Open
jyn514 opened this issue Feb 26, 2021 · 3 comments
Open

Make it easier to build an artifact and record its path #153

jyn514 opened this issue Feb 26, 2021 · 3 comments

Comments

@jyn514
Copy link
Collaborator

jyn514 commented Feb 26, 2021

Right now, there's an example on the front page, which is much appreciated:

let mut command = Command::new("cargo")
    .args(&["build", "--message-format=json-render-diagnostics"])
    .stdout(Stdio::piped())
    .spawn()
    .unwrap();

let reader = std::io::BufReader::new(command.stdout.take().unwrap());
for message in cargo_metadata::Message::parse_stream(reader) {
    // ...
}
let output = command.wait().expect("Couldn't get cargo's exit status");

This has a few issues though:

It would be really useful for MetadataCommand to work for things other than cargo metadata itself. Maybe this is as simple as adding MetadataSubcommand(&mut self, cmd: String) -> Self, and replacing metadata --format-version=1 with that command? Everything else should work the same since other_options is public.

@jyn514
Copy link
Collaborator Author

jyn514 commented Feb 26, 2021

I guess this means exec() returning a Metadata no longer makes sense, it would have to remove Vec<Message> or something like that. Maybe you could play around with typestate somehow so the return type depends on the subcommand? I haven't thought about it in detail.

@jyn514
Copy link
Collaborator Author

jyn514 commented Feb 26, 2021

If it helps, this is how I adapted the example:

    // First, build `threenp1` and record the generated executable
    // Adapted from the example at https://docs.rs/cargo_metadata/0.12.3/cargo_metadata/#examples.
    // TODO: I opened https://github.com/oli-obk/cargo_metadata/issues/153 to hopefully require less copy/pasting in the future.
    let mut command = Command::new(std::env::var("CARGO").unwrap_or("cargo"))
        .args(&["build", "--example=threenp1", "--message-format=json-render-diagnostics"])
        .stdout(Stdio::piped())
        .spawn()
        .unwrap();
    let reader = std::io::BufReader::new(command.stdout.take().unwrap());
    let threenp1 = cargo_metadata::Message::parse_stream(reader).find_map(|message| {
        // original jq script: `select(.reason == "compiler-artifact" and (.target.kind[] | contains("example"))) | .executable`
        if let Message::CompilerArtifact(Artifact { executable, target, .. }) = message {
            if target.kind.contains("example") {
                return executable;
            }
        }
        None
    }).unwrap();
    let output = command.wait().unwrap();
    assert!(output.status.success(), "failed to run `cargo build`");

@oli-obk
Copy link
Owner

oli-obk commented Mar 1, 2021

We could certainly start exposing more helpers (e.g. for getting a cargo command), or just use something like escargot and reexport things, but I'm not sure how much sugar we should add on top of this crate. I can totally see adding a cargo_metadata::Message::from_cmd_stdout that you can pass a Command to and that will take care of setting stdout, running the thing and using bufreaders and all. Since cargo is such a common use case, just having a from_cargo that takes a list of arguments would also be ok.

I'm less sold on the builder/typestate solution, but maybe I'm just not actually seeing what you are envisioning.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants