substrait 0.64.0

Cross-Language Serialization for Relational Algebra
Documentation
// SPDX-License-Identifier: Apache-2.0

use std::{env, error::Error, fs, path::PathBuf};

/// The dependency whose version pin encodes the Substrait spec version this
/// crate is built against.
const SUBSTRAIT_DEP: &str = "substrait-prost";

/// Derive the Substrait version from the exact version pin of the
/// [`SUBSTRAIT_DEP`] dependency in this crate's `Cargo.toml`.
///
/// The packaged Substrait crates are versioned to track the spec tag (e.g.
/// `substrait-prost 0.87.0` corresponds to Substrait `v0.87.0`), and we
/// pin them to an exact version, so the requirement in `Cargo.toml` equals the
/// resolved version. `Cargo.toml` is always present at `CARGO_MANIFEST_DIR`
/// (including when this crate is consumed as a dependency), which makes this
/// robust where reading `Cargo.lock` would not be.
fn substrait_version() -> Result<semver::Version, Box<dyn Error>> {
    let manifest_dir = PathBuf::from(env::var("CARGO_MANIFEST_DIR")?);
    let manifest_path = manifest_dir.join("Cargo.toml");

    // Rerun if the pin changes.
    println!("cargo:rerun-if-changed={}", manifest_path.display());

    let manifest = fs::read_to_string(&manifest_path)?.parse::<toml::Table>()?;
    let requirement = manifest
        .get("dependencies")
        .and_then(toml::Value::as_table)
        .and_then(|deps| deps.get(SUBSTRAIT_DEP))
        .and_then(|dep| match dep {
            // `substrait-prost = "=0.87.0"`
            toml::Value::String(version) => Some(version.as_str()),
            // `substrait-prost = { version = "=0.87.0", ... }`
            toml::Value::Table(table) => table.get("version").and_then(toml::Value::as_str),
            _ => None,
        })
        .ok_or_else(|| {
            format!("missing `{SUBSTRAIT_DEP}` dependency version in {manifest_path:?}")
        })?;

    // Strip any leading comparator (`=`, `^`, `~`, `>=`, ...) to parse the exact
    // version. The pin is exact, so this is the resolved version.
    let version = requirement.trim_start_matches(['=', '^', '~', '>', '<', ' ']);
    Ok(semver::Version::parse(version)?)
}

fn main() -> Result<(), Box<dyn Error>> {
    // for use in docker build where file changes can be wonky
    println!("cargo:rerun-if-env-changed=FORCE_REBUILD");

    let version = substrait_version()?;
    let semver::Version {
        major,
        minor,
        patch,
        ..
    } = version;

    let out_dir = PathBuf::from(env::var("OUT_DIR")?);
    fs::write(
        out_dir.join("version.in"),
        format!(
            r#"// SPDX-License-Identifier: Apache-2.0

// Note that this file is auto-generated by `build.rs` from the pinned
// `{SUBSTRAIT_DEP}` version. It is included in `version.rs`.

/// The major version of Substrait used to build this crate
pub const SUBSTRAIT_MAJOR_VERSION: u32 = {major};

/// The minor version of Substrait used to build this crate
pub const SUBSTRAIT_MINOR_VERSION: u32 = {minor};

/// The patch version of Substrait used to build this crate
pub const SUBSTRAIT_PATCH_VERSION: u32 = {patch};

/// The Git SHA (lower hex) of Substrait used to build this crate.
///
/// Empty: the Substrait version is derived from the packaged crate version, not
/// a git checkout.
pub const SUBSTRAIT_GIT_SHA: &str = "";

/// The `git describe`-style output of the Substrait version used to build this
/// crate.
pub const SUBSTRAIT_GIT_DESCRIBE: &str = "v{major}.{minor}.{patch}";

/// The amount of commits between the latest tag and the version of Substrait
/// used to build this crate. Always `0`: a tagged, packaged release is used.
pub const SUBSTRAIT_GIT_DEPTH: u32 = 0;

/// The dirty state of the Substrait version used to build this crate. Always
/// `false`: a tagged, packaged release is used.
pub const SUBSTRAIT_GIT_DIRTY: bool = false;

/// A constant with the Substrait version as name, to trigger semver bumps when
/// the Substrait version changes.
pub const SUBSTRAIT_{major}_{minor}_{patch}: () = ();
"#
        ),
    )?;

    Ok(())
}