Search code examples
rustrust-cargo

Is there any way to get the list of installable versions of a Rust crate by command?


I'd like to get the list of installable versions of a Rust crate in a script.

I want to get not the installed version but installable versions.

You can see the list of installable versions on https://crates.io .

e.g. https://crates.io/crates/skim/versions

I'd like to get the list in a script.

I checked cargo's sub commands and command line options, but I couldn't find any command and option that I want.


Solution

  • I couldn't find any similar command in cargo documentation either. But It seems like there is an API endpoint(/api/v1/crates/<crate_name>/versions) available to get all the installable versions of a crate. Since you are looking for a cargo command, You can extend cargo with your own custom command.

    Extending Cargo with Custom Commands

    Cargo is designed so you can extend it with new subcommands without having to modify Cargo. If a binary in your $PATH is named cargo-something, you can run it as if it was a Cargo subcommand by running cargo something. Custom commands like this are also listed when you run cargo --list. Being able to use cargo install to install extensions and then run them just like the built-in Cargo tools is a super convenient benefit of Cargo’s design.

    To do that first create a new project:

    $ cargo new cargo-list-installable-versions --bin
    

    Please note that the project name should be of the format cargo-YOUR_SUB_COMMAND_NAME. Now add these two dependencies to Cargo.toml file.

    reqwest = { version = "0.11.18", features = ["blocking", "json"] }
    serde_json = "1.0.96"
    

    Now in main.rs you can implement the logic to get the versions from the API endpoint /api/v1/crates/<crate_name>/versions.

    Here is the very basic implementation.

    use std::env;
    
    fn main() {
        if let Some(package_name) = env::args().nth(2) {
            let client = reqwest::blocking::Client::builder()
                .user_agent("YOUR_USER_AGENT")
                .build()
                .unwrap();
            let api_url = format!(
                "https://crates.io/api/v1/crates/{}/versions",
                package_name.trim()
            );
            let resp = client
                .get(api_url)
                .send()
                .unwrap()
                .json::<serde_json::Value>()
                .unwrap();
            if let Some(installable_versions) = resp["versions"].as_array() {
                for version in installable_versions {
                    println!("{}", version["num"])
                }
            }
        } else {
            eprintln!("package name is missing")
        }
    }
    

    Now build & release the project. Make sure to add the release folder to the $PATH environment variable.

    $ cargo build --release
    $ export PATH="PATH_TO_YOUR_RELEASE_FOLDER:$PATH"
    

    Now you are ready to consume your subcommand. If you configured everything correctly you can see list-installable-versions subcommand under cargo --list. To actually run it you can use

    $ cargo list-installable-versions <crate_name>
    

    This will print all installable-versions of the <crate_name>.