#channel #metadata #release

rust_release_channel

A data structure for Rust release channel metadata

3 releases (breaking)

Uses old Rust 2015

0.3.0 Jul 17, 2018
0.2.0 Jun 26, 2018
0.1.0 Apr 2, 2018

#47 in #release

MIT/Apache

70KB
1K SLoC

rust_release_channel: a data structure for Rust release channel metadata

Repository: https://gitlab.com/Screwtapello/rust_release_channel/

Documentation: https://docs.rs/rust_release_channel

TODO

  • Store hashes as bytes rather than hex-encoded bytes?
    • might make it easier to compare with the results of other hash functions
  • make impl Display for Channel format as TOML, instead of the current human-readable output? That way we can replace our custom .to_string() method with the actual ToString trait, which might be less surprising.

lib.rs:

A data structure for Rust release channel metadata

Introduction

New versions of the Rust toolchain are released on a regular six-week cycle. Each version is described in a release-channel metadata file in a known location, allowing automated tools to detect new releases and find the tools and components for each supported platform.

The data structures in this library represent the information present in each metadata file, organised to help you pull out the specific information you need.

This library is designed to handle version 2 of the manifest file format.

The most important class is Channel, so you'll want to start there.

First Example

 extern crate rust_release_channel;
 use std::error::Error;

 fn dump_manifest_info(input: &str) -> Result<(), Box<Error>> {
     // Parse the manifest into a data structure.
     let channel: rust_release_channel::Channel = input.parse()?;

     // Check the manifest is sensible before we use it.
     let errors = channel.validate();
     if errors.is_empty() {
         // Dump a summary of the manifest data
         println!(
             "Channel manifest created on {}",
             channel.date,
         );
         println!("Included packages:");
         for (name, pkg) in channel.pkg.iter() {
             println!("  - {} version {}", name, pkg.version);
         }
     } else {
         println!("Channel has problems:");
         for each in errors {
             println!("  - {}", each);
         }
     }

     Ok(())
 }

Capabilities

Reading manifests

If you can read the content of an existing manifest file, you can turn it into a queryable, explorable data structure with the .parse() method (courtesy of the standard FromStr trait).

 # extern crate rust_release_channel;
 # use std::error::Error;
 # fn example1() -> Result<(), Box<Error>> {
 # let my_str = r#"metadata-version = "2"\ndate = "2018-02-26"\n"#;
 use rust_release_channel::Channel;

 let channel: Channel = my_str.parse()?;
 # Ok(())
 # }

After reading a manifest, you should call .validate() to see if the data makes sense before trusting it.

Querying manifests

All the content of the manifest is available to inspect, as native-feeling Rust data structures. For example, where the native manifest file-format models different available file-formats as differently-named keys with the same meaning (url vs. xz_url, hash vs. xz_hash), rust_release_channel gives you a mapping from ArchiveFormat to ArchiveSource.

 # extern crate rust_release_channel;
 # use std::error::Error;
 # fn example2() -> Result<(), Box<Error>> {
 # let my_str = r#"metadata-version = "2"\ndate = "2018-02-26"\n"#;
 # let channel: rust_release_channel::Channel = my_str.parse()?;
 use rust_release_channel::{ArtefactQuery, ArchiveFormat};

 let rust_for_aarch64_url = channel.lookup_artefact(
         ArtefactQuery::new("rust", "aarch64-unknown-linux-gnu"),
     )
     .and_then(|artefact| {
          artefact.standalone.get(&ArchiveFormat::TarGzip)
     })
     .map(|archive| { &archive.url });
 # Ok(())
 # }

Creating fresh manifests

You can also create manifest data completely from scratch, in case you need to create test-data for another system.

 # extern crate rust_release_channel;
 # extern crate chrono;
 # use std::error::Error;
 # fn example3() -> Result<(), Box<Error>> {
 use rust_release_channel::{
     Channel,
     Package,
     Artefact,
     ArchiveFormat,
     ArchiveSource,
 };

 let source = ArchiveSource::new(
     "https://example.com/rust/mypackage-linux-x86.tar.gz".parse()?,
     "aa0a89d80329fec6f9e84b79c1674c5427034408630c35da1be442c7da6d2364"
         .into(),
 );

 let mut artefact = Artefact::new();
 artefact.standalone.insert(ArchiveFormat::TarGzip, source);

 let mut mypackage = Package::new("1.2.3 (abc1234 2018-02-26)".into());
 mypackage.target.insert("x86_64-unknown-linux-gnu".into(), artefact);

 let mut channel = Channel::new();
 channel.pkg.insert("mypackage".into(), mypackage);
 # Ok(())
 # }

Writing manifests

You can turn manifest data back into a string with the .to_string() method. If you serialize a Channel and deserialize it again, the result should be identical to the original.

 # extern crate rust_release_channel;
 # use std::error::Error;
 # fn example3() -> Result<(), Box<Error>> {
 # let channel = rust_release_channel::Channel::new();
 let manifest_string = channel.to_string()?;
 # Ok(())
 # }

Before writing a manifest, you should call .validate() to check you haven't left the metadata in an inconsistent state.

Dependencies

~3–4MB
~108K SLoC