mirror of
https://gitlab.redox-os.org/redox-os/redox.git
synced 2026-06-24 05:44:17 +08:00
268 lines
8.0 KiB
Rust
268 lines
8.0 KiB
Rust
use std::{
|
|
fs,
|
|
path::{Path, PathBuf},
|
|
};
|
|
|
|
use serde::{Deserialize, Serialize};
|
|
|
|
use crate::recipe_find::recipe_find;
|
|
|
|
/// Specifies how to download the source for a recipe
|
|
#[derive(Debug, Deserialize, PartialEq, Serialize)]
|
|
#[serde(untagged)]
|
|
pub enum SourceRecipe {
|
|
/// Reuse the source directory of another package
|
|
///
|
|
/// This is useful when a single source repo contains multiple projects which each have their
|
|
/// own recipe to build them.
|
|
SameAs {
|
|
/// Relative path to the package for which to reuse the source dir
|
|
same_as: String,
|
|
},
|
|
/// Path source
|
|
Path {
|
|
/// The path to the source
|
|
path: String,
|
|
},
|
|
/// A git repository source
|
|
Git {
|
|
/// The URL for the git repository, such as https://gitlab.redox-os.org/redox-os/ion.git
|
|
git: String,
|
|
/// The URL for an upstream repository
|
|
upstream: Option<String>,
|
|
/// The optional branch of the git repository to track, such as master. Please specify to
|
|
/// make updates to the rev easier
|
|
branch: Option<String>,
|
|
/// The optional revision of the git repository to use for builds. Please specify for
|
|
/// reproducible builds
|
|
rev: Option<String>,
|
|
/// A list of patch files to apply to the source
|
|
#[serde(default)]
|
|
patches: Vec<String>,
|
|
/// Optional script to run to prepare the source
|
|
script: Option<String>,
|
|
},
|
|
/// A tar file source
|
|
Tar {
|
|
/// The URL of a tar source
|
|
tar: String,
|
|
/// The optional blake3 sum of the tar file. Please specify this to make reproducible
|
|
/// builds more reliable
|
|
blake3: Option<String>,
|
|
/// A list of patch files to apply to the source
|
|
#[serde(default)]
|
|
patches: Vec<String>,
|
|
/// Optional script to run to prepare the source, such as ./autogen.sh
|
|
script: Option<String>,
|
|
},
|
|
}
|
|
|
|
/// Specifies how to build a recipe
|
|
#[derive(Debug, Deserialize, PartialEq, Serialize)]
|
|
#[serde(tag = "template")]
|
|
pub enum BuildKind {
|
|
/// Will build and install using cargo
|
|
#[serde(rename = "cargo")]
|
|
Cargo {
|
|
#[serde(default)]
|
|
package_path: Option<String>,
|
|
|
|
#[serde(default)]
|
|
cargoflags: String,
|
|
},
|
|
/// Will build and install using configure and make
|
|
#[serde(rename = "configure")]
|
|
Configure,
|
|
/// Will build and install using custom commands
|
|
#[serde(rename = "custom")]
|
|
Custom { script: String },
|
|
}
|
|
|
|
#[derive(Debug, Deserialize, PartialEq, Serialize)]
|
|
pub struct BuildRecipe {
|
|
#[serde(flatten)]
|
|
pub kind: BuildKind,
|
|
#[serde(default)]
|
|
pub dependencies: Vec<String>,
|
|
}
|
|
|
|
#[derive(Debug, Default, Deserialize, PartialEq, Serialize)]
|
|
pub struct PackageRecipe {
|
|
#[serde(default)]
|
|
pub dependencies: Vec<String>,
|
|
}
|
|
|
|
/// Everything required to build a Redox package
|
|
#[derive(Debug, Deserialize, PartialEq, Serialize)]
|
|
pub struct Recipe {
|
|
/// Specifies how to donload the source for this recipe
|
|
pub source: Option<SourceRecipe>,
|
|
/// Specifies how to build this recipe
|
|
pub build: BuildRecipe,
|
|
/// Specifies how to package this recipe
|
|
#[serde(default)]
|
|
pub package: PackageRecipe,
|
|
}
|
|
|
|
#[derive(Debug, PartialEq)]
|
|
pub struct CookRecipe {
|
|
pub name: String,
|
|
pub dir: PathBuf,
|
|
pub recipe: Recipe,
|
|
}
|
|
|
|
impl CookRecipe {
|
|
pub fn new(name: String) -> Result<Self, String> {
|
|
//TODO: sanitize recipe name?
|
|
let dir = recipe_find(&name, Path::new("recipes"))?;
|
|
if dir.is_none() {
|
|
return Err(format!("failed to find recipe directory '{}'", name));
|
|
}
|
|
let dir = dir.unwrap();
|
|
let file = dir.join("recipe.toml");
|
|
if !file.is_file() {
|
|
return Err(format!("failed to find recipe file '{}'", file.display()));
|
|
}
|
|
|
|
let toml = fs::read_to_string(&file).map_err(|err| {
|
|
format!(
|
|
"failed to read recipe file '{}': {}\n{:#?}",
|
|
file.display(),
|
|
err,
|
|
err
|
|
)
|
|
})?;
|
|
|
|
let recipe: Recipe = toml::from_str(&toml).map_err(|err| {
|
|
format!(
|
|
"failed to parse recipe file '{}': {}\n{:#?}",
|
|
file.display(),
|
|
err,
|
|
err
|
|
)
|
|
})?;
|
|
|
|
Ok(Self { name, dir, recipe })
|
|
}
|
|
|
|
pub fn new_recursive(names: &[String], recursion: usize) -> Result<Vec<Self>, String> {
|
|
if recursion == 0 {
|
|
return Err(format!(
|
|
"recursion limit while processing build dependencies: {:#?}",
|
|
names
|
|
));
|
|
}
|
|
|
|
let mut recipes = Vec::new();
|
|
for name in names {
|
|
let recipe = Self::new(name.clone())?;
|
|
|
|
let dependencies =
|
|
Self::new_recursive(&recipe.recipe.build.dependencies, recursion - 1).map_err(
|
|
|err| format!("{}: failed on loading build dependencies:\n{}", name, err),
|
|
)?;
|
|
|
|
for dependency in dependencies {
|
|
if !recipes.contains(&dependency) {
|
|
recipes.push(dependency);
|
|
}
|
|
}
|
|
|
|
if !recipes.contains(&recipe) {
|
|
recipes.push(recipe);
|
|
}
|
|
}
|
|
|
|
Ok(recipes)
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
#[test]
|
|
fn git_cargo_recipe() {
|
|
use crate::recipe::{BuildKind, BuildRecipe, PackageRecipe, Recipe, SourceRecipe};
|
|
|
|
let recipe: Recipe = toml::from_str(
|
|
r#"
|
|
[source]
|
|
git = "https://gitlab.redox-os.org/redox-os/acid.git"
|
|
branch = "master"
|
|
rev = "06344744d3d55a5ac9a62a6059cb363d40699bbc"
|
|
|
|
[build]
|
|
template = "cargo"
|
|
"#,
|
|
)
|
|
.unwrap();
|
|
|
|
assert_eq!(
|
|
recipe,
|
|
Recipe {
|
|
source: Some(SourceRecipe::Git {
|
|
git: "https://gitlab.redox-os.org/redox-os/acid.git".to_string(),
|
|
upstream: None,
|
|
branch: Some("master".to_string()),
|
|
rev: Some("06344744d3d55a5ac9a62a6059cb363d40699bbc".to_string()),
|
|
patches: Vec::new(),
|
|
script: None,
|
|
}),
|
|
build: BuildRecipe {
|
|
kind: BuildKind::Cargo {
|
|
package_path: None,
|
|
cargoflags: String::new(),
|
|
},
|
|
dependencies: Vec::new(),
|
|
},
|
|
package: PackageRecipe {
|
|
dependencies: Vec::new(),
|
|
shared_deps: Vec::new(),
|
|
},
|
|
}
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn tar_custom_recipe() {
|
|
use crate::recipe::{BuildKind, BuildRecipe, PackageRecipe, Recipe, SourceRecipe};
|
|
|
|
let recipe: Recipe = toml::from_str(
|
|
r#"
|
|
[source]
|
|
tar = "http://downloads.xiph.org/releases/ogg/libogg-1.3.3.tar.xz"
|
|
blake3 = "8220c0e4082fa26c07b10bfe31f641d2e33ebe1d1bb0b20221b7016bc8b78a3a"
|
|
|
|
[build]
|
|
template = "custom"
|
|
script = "make"
|
|
"#,
|
|
)
|
|
.unwrap();
|
|
|
|
assert_eq!(
|
|
recipe,
|
|
Recipe {
|
|
source: Some(SourceRecipe::Tar {
|
|
tar: "http://downloads.xiph.org/releases/ogg/libogg-1.3.3.tar.xz".to_string(),
|
|
blake3: Some(
|
|
"8220c0e4082fa26c07b10bfe31f641d2e33ebe1d1bb0b20221b7016bc8b78a3a"
|
|
.to_string()
|
|
),
|
|
patches: Vec::new(),
|
|
script: None,
|
|
}),
|
|
build: BuildRecipe {
|
|
kind: BuildKind::Custom {
|
|
script: "make".to_string()
|
|
},
|
|
dependencies: Vec::new(),
|
|
},
|
|
package: PackageRecipe {
|
|
dependencies: Vec::new(),
|
|
shared_deps: Vec::new(),
|
|
},
|
|
}
|
|
);
|
|
}
|
|
}
|