Abbaye

at bd5ed90

use miette::Result;
use serde::{Deserialize, Serialize};
use std::path::PathBuf;

pub mod archive;
pub mod cargo;

use archive::{ArchiveBuilder, ArchiveBuilderConfig};
use cargo::{CargoBuilder, CargoBuilderConfig, CargoDocBuilder, CargoDocBuilderConfig};

#[derive(Debug, Clone, Deserialize, Serialize)]
#[serde(tag = "type", rename_all = "snake_case")]
pub enum AnyBuilder {
    /// Creates a `.tar.gz` archive of the source tree, automatically excluding
    /// files and directories matched by any `.gitignore` found in the hierarchy.
    ///
    /// ```toml
    /// [[builders]]
    /// type = "archive"
    /// source_dir = "."                      # optional, defaults to CWD
    /// output = "myproject-1.0.0.tar.gz"     # optional, defaults to source.tar.gz
    /// prefix = "myproject-1.0.0"            # optional, defaults to source_dir name
    /// ```
    Archive(ArchiveBuilderConfig),

    /// Compiles the crate in release mode with `cargo build --release`.
    /// One or more target triples can be specified for cross-compilation;
    /// omitting `targets` builds for the host platform.
    ///
    /// ```toml
    /// [[builders]]
    /// type = "cargo"
    /// targets = ["x86_64-unknown-linux-musl", "aarch64-unknown-linux-musl"]
    /// manifest_path = "Cargo.toml"          # optional
    /// ```
    Cargo(CargoBuilderConfig),

    /// Generates API documentation with `cargo doc`.
    /// Returns the per-crate doc directory (e.g. `target/doc/my_crate`) as an
    /// artifact so it can be published or archived by a later pipeline step.
    ///
    /// ```toml
    /// [[builders]]
    /// type = "cargo_doc"
    /// no_deps = true                        # optional, skip dependency docs
    /// manifest_path = "Cargo.toml"          # optional
    /// ```
    CargoDoc(CargoDocBuilderConfig),
}

impl AnyBuilder {
    pub async fn build(&self) -> Result<Vec<ArtifactPath>> {
        match self {
            Self::Archive(config) => ArchiveBuilder.build(config.clone()).await,
            Self::Cargo(config) => CargoBuilder.build(config.clone()).await,
            Self::CargoDoc(config) => CargoDocBuilder.build(config.clone()).await,
        }
    }
}

pub struct ArtifactPath {
    pub path: PathBuf,
    pub name: String,
    /// Lowercase hexadecimal SHA1 digest of the artifact's contents, if computed.
    pub hash: Option<String>,
}

#[allow(async_fn_in_trait)]
pub trait Builder {
    type ConfigType: Default + for<'de> Deserialize<'de> + Clone;

    async fn build(&self, config: Self::ConfigType) -> Result<Vec<ArtifactPath>>;
}