mirror of
https://gitlab.redox-os.org/redox-os/redox.git
synced 2026-06-23 13:24:17 +08:00
Compiling with direct call to cook
This commit is contained in:
parent
97bef43ca0
commit
8e2ac316e4
@ -1,36 +1,17 @@
|
||||
use std::collections::BTreeSet;
|
||||
use std::path::Path;
|
||||
use std::{env, process};
|
||||
|
||||
use cookbook::WALK_DEPTH;
|
||||
use cookbook::cook::fetch::{fetch, fetch_offline};
|
||||
use cookbook::cook::fs::create_target_dir;
|
||||
use cookbook::cook::package::{package, package_toml};
|
||||
use cookbook::recipe::{BuildKind, CookRecipe, Recipe};
|
||||
use cookbook::cook::package::package;
|
||||
use cookbook::recipe::{CookRecipe, Recipe};
|
||||
use pkg::PackageName;
|
||||
|
||||
use cookbook::config::init_config;
|
||||
use cookbook::cook::cook_build::build;
|
||||
use termion::{color, style};
|
||||
|
||||
fn cook_meta(
|
||||
recipe_dir: &Path,
|
||||
name: &PackageName,
|
||||
recipe: &Recipe,
|
||||
fetch_only: bool,
|
||||
) -> Result<(), String> {
|
||||
if fetch_only {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let target_dir = create_target_dir(recipe_dir)?;
|
||||
let empty_deps = BTreeSet::new();
|
||||
let _package_file = package_toml(&target_dir, name, recipe, &empty_deps)
|
||||
.map_err(|err| format!("failed to package: {}", err))?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn cook(
|
||||
recipe_dir: &Path,
|
||||
name: &PackageName,
|
||||
@ -39,12 +20,9 @@ fn cook(
|
||||
fetch_only: bool,
|
||||
is_offline: bool,
|
||||
) -> Result<(), String> {
|
||||
if recipe.build.kind == BuildKind::None {
|
||||
return cook_meta(recipe_dir, name, recipe, fetch_only);
|
||||
}
|
||||
let source_dir = match is_offline {
|
||||
true => fetch_offline(recipe_dir, &recipe.source),
|
||||
false => fetch(recipe_dir, &recipe.source),
|
||||
true => fetch_offline(recipe_dir, recipe),
|
||||
false => fetch(recipe_dir, recipe),
|
||||
}
|
||||
.map_err(|err| format!("failed to fetch: {}", err))?;
|
||||
|
||||
@ -65,7 +43,7 @@ fn cook(
|
||||
)
|
||||
.map_err(|err| format!("failed to build: {}", err))?;
|
||||
|
||||
let _package_file = package(&stage_dir, &target_dir, name, recipe, &auto_deps)
|
||||
package(&stage_dir, &target_dir, name, recipe, &auto_deps)
|
||||
.map_err(|err| format!("failed to package: {}", err))?;
|
||||
|
||||
Ok(())
|
||||
|
||||
275
src/bin/repo.rs
275
src/bin/repo.rs
@ -1,9 +1,18 @@
|
||||
use std::collections::BTreeSet;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::process::{self, Command};
|
||||
use std::path::PathBuf;
|
||||
use std::process;
|
||||
use std::str::FromStr;
|
||||
use std::{env, fs};
|
||||
|
||||
use anyhow::{Context, anyhow};
|
||||
use anyhow::{Context, anyhow, bail};
|
||||
use cookbook::WALK_DEPTH;
|
||||
use cookbook::config::{CookConfig, get_config, init_config};
|
||||
use cookbook::cook::cook_build::build;
|
||||
use cookbook::cook::fetch::{fetch, fetch_offline};
|
||||
use cookbook::cook::fs::create_target_dir;
|
||||
use cookbook::cook::package::package;
|
||||
use cookbook::recipe::CookRecipe;
|
||||
use pkg::PackageName;
|
||||
use pkg::package::PackageError;
|
||||
|
||||
// A repo manager, to replace repo.sh
|
||||
|
||||
@ -36,16 +45,51 @@ struct CliConfig {
|
||||
repo_dir: PathBuf,
|
||||
sysroot_dir: PathBuf,
|
||||
with_package_deps: bool,
|
||||
offline: bool,
|
||||
nonstop: bool,
|
||||
all: bool,
|
||||
quiet: bool,
|
||||
cook: CookConfig,
|
||||
}
|
||||
|
||||
#[derive(PartialEq)]
|
||||
enum CliCommand {
|
||||
Fetch,
|
||||
Cook,
|
||||
Unfetch,
|
||||
Clean,
|
||||
Push,
|
||||
}
|
||||
|
||||
impl FromStr for CliCommand {
|
||||
type Err = anyhow::Error;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
match s {
|
||||
"fetch" => Ok(CliCommand::Fetch),
|
||||
"cook" => Ok(CliCommand::Cook),
|
||||
"unfetch" => Ok(CliCommand::Unfetch),
|
||||
"clean" => Ok(CliCommand::Clean),
|
||||
"push" => Ok(CliCommand::Push),
|
||||
_ => Err(anyhow!("Unknown command '{}'", s)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ToString for CliCommand {
|
||||
fn to_string(&self) -> String {
|
||||
match self {
|
||||
CliCommand::Fetch => "fetch".to_string(),
|
||||
CliCommand::Cook => "cook".to_string(),
|
||||
CliCommand::Unfetch => "unfetch".to_string(),
|
||||
CliCommand::Clean => "clean".to_string(),
|
||||
CliCommand::Push => "push".to_string(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl CliConfig {
|
||||
fn new() -> Result<Self, std::io::Error> {
|
||||
let current_dir = env::current_dir()?;
|
||||
Ok(CliConfig {
|
||||
//FIXME: This config is unused as redox-pkg harcoded this to $PWD/recipes
|
||||
cookbook_dir: current_dir.join("recipes"),
|
||||
repo_dir: current_dir.join("repo"),
|
||||
sysroot_dir: if cfg!(target_os = "redox") {
|
||||
@ -54,15 +98,14 @@ impl CliConfig {
|
||||
current_dir.join("sysroot")
|
||||
},
|
||||
with_package_deps: false,
|
||||
offline: false,
|
||||
nonstop: false,
|
||||
cook: get_config().cook.clone(),
|
||||
all: false,
|
||||
quiet: false,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
init_config();
|
||||
main_inner().unwrap();
|
||||
}
|
||||
|
||||
@ -74,10 +117,29 @@ fn main_inner() -> anyhow::Result<()> {
|
||||
process::exit(1);
|
||||
}
|
||||
|
||||
let (config, command, recipe_names) = parse_args(args)?;
|
||||
|
||||
for recipe in &recipe_names {
|
||||
match command {
|
||||
CliCommand::Fetch => handle_cook(recipe, &config, true, recipe.is_deps)?,
|
||||
CliCommand::Cook => handle_cook(recipe, &config, false, recipe.is_deps)?,
|
||||
CliCommand::Unfetch => handle_clean(recipe, &config, true, true)?,
|
||||
CliCommand::Clean => handle_clean(recipe, &config, false, true)?,
|
||||
CliCommand::Push => handle_push(recipe, &config)?,
|
||||
}
|
||||
}
|
||||
|
||||
println!(
|
||||
"\nCommand '{}' completed for all specified recipes.",
|
||||
command.to_string(),
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn parse_args(args: Vec<String>) -> anyhow::Result<(CliConfig, CliCommand, Vec<CookRecipe>)> {
|
||||
let mut config = CliConfig::new()?;
|
||||
let mut command: Option<String> = None;
|
||||
let mut recipe_paths: BTreeSet<PathBuf> = BTreeSet::new();
|
||||
|
||||
let mut recipe_names: Vec<PackageName> = Vec::new();
|
||||
for arg in args {
|
||||
if arg.starts_with("--") {
|
||||
if let Some((key, value)) = arg.split_once('=') {
|
||||
@ -93,10 +155,7 @@ fn main_inner() -> anyhow::Result<()> {
|
||||
} else {
|
||||
match arg.as_str() {
|
||||
"--with-package-deps" => config.with_package_deps = true,
|
||||
"--offline" => config.offline = true,
|
||||
"--nonstop" => config.nonstop = true,
|
||||
"--all" => config.all = true,
|
||||
"--quiet" => config.quiet = true,
|
||||
_ => {
|
||||
eprintln!("Error: Unknown flag: {}", arg);
|
||||
process::exit(1);
|
||||
@ -105,7 +164,6 @@ fn main_inner() -> anyhow::Result<()> {
|
||||
}
|
||||
} else if arg.starts_with('-') {
|
||||
match arg.as_str() {
|
||||
"-q" => config.quiet = true,
|
||||
_ => {
|
||||
eprintln!("Error: Unknown flag: {}", arg);
|
||||
process::exit(1);
|
||||
@ -116,122 +174,117 @@ fn main_inner() -> anyhow::Result<()> {
|
||||
command = Some(arg);
|
||||
} else {
|
||||
// Subsequent non-flag arguments are recipe names
|
||||
if let Some(path) = pkg::recipes::find(&arg) {
|
||||
recipe_paths.insert(path.to_owned());
|
||||
} else {
|
||||
panic!("Error: recipe not found '{arg}'");
|
||||
}
|
||||
recipe_names.push(arg.try_into().context("Invalid package name")?);
|
||||
}
|
||||
}
|
||||
|
||||
let command = command.ok_or("Error: No command specified.").unwrap();
|
||||
|
||||
if !config.all && recipe_paths.is_empty() {
|
||||
panic!("Error: No recipe names provided and --all flag was not used.");
|
||||
}
|
||||
if config.all && !recipe_paths.is_empty() {
|
||||
panic!("Error: Cannot specify recipe names when using the --all flag.");
|
||||
}
|
||||
|
||||
if config.all {
|
||||
recipe_paths = pkg::recipes::list("");
|
||||
}
|
||||
|
||||
for recipe_path in &recipe_paths {
|
||||
match command.as_str() {
|
||||
"fetch" => handle_fetch(recipe_path, &config)?,
|
||||
"cook" => handle_cook(recipe_path, &config)?,
|
||||
"unfetch" => handle_unfetch(recipe_path, &config)?,
|
||||
"clean" => handle_clean(recipe_path, &config)?,
|
||||
"push" => handle_push(recipe_path, &config)?,
|
||||
_ => {
|
||||
eprintln!("Error: Unknown command '{}'\n", command);
|
||||
println!("{}", REPO_HELP_STR);
|
||||
process::exit(1);
|
||||
}
|
||||
let command = command.ok_or(anyhow!("Error: No command specified."))?;
|
||||
let command: CliCommand = str::parse(&command)?;
|
||||
let recipes = if config.all {
|
||||
if !recipe_names.is_empty() {
|
||||
bail!("Cannot specify recipe names when using the --all flag.");
|
||||
}
|
||||
if command == CliCommand::Cook
|
||||
|| command == CliCommand::Fetch
|
||||
|| command == CliCommand::Push
|
||||
{
|
||||
// because read_recipe is false below
|
||||
// some recipes on wip folders are invalid anyway
|
||||
bail!(
|
||||
"Refusing to run an unrealistic command to {} all recipes",
|
||||
command.to_string()
|
||||
);
|
||||
}
|
||||
|
||||
pkg::recipes::list("")
|
||||
.iter()
|
||||
.map(|f| CookRecipe::from_path(f, false))
|
||||
.collect::<Result<Vec<CookRecipe>, PackageError>>()?
|
||||
} else {
|
||||
if recipe_names.is_empty() {
|
||||
bail!("Error: No recipe names provided and --all flag was not used.");
|
||||
}
|
||||
if config.with_package_deps {
|
||||
recipe_names = CookRecipe::get_package_deps_recursive(&recipe_names, WALK_DEPTH)
|
||||
.context("failed get package deps")?;
|
||||
}
|
||||
|
||||
CookRecipe::get_build_deps_recursive(&recipe_names, !config.with_package_deps)?
|
||||
};
|
||||
|
||||
Ok((config, command, recipes))
|
||||
}
|
||||
|
||||
fn handle_cook(
|
||||
recipe: &CookRecipe,
|
||||
config: &CliConfig,
|
||||
fetch_only: bool,
|
||||
is_deps: bool,
|
||||
) -> anyhow::Result<()> {
|
||||
let recipe_dir = &recipe.dir;
|
||||
let source_dir = match config.cook.offline {
|
||||
true => fetch_offline(recipe_dir, &recipe.recipe),
|
||||
false => fetch(recipe_dir, &recipe.recipe),
|
||||
}
|
||||
.map_err(|e| anyhow!(e))?;
|
||||
|
||||
if fetch_only {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
println!(
|
||||
"\nCommand '{}' completed for all specified recipes.",
|
||||
command
|
||||
);
|
||||
let target_dir = create_target_dir(recipe_dir).map_err(|e| anyhow!(e))?;
|
||||
|
||||
let (stage_dir, auto_deps) = build(
|
||||
recipe_dir,
|
||||
&source_dir,
|
||||
&target_dir,
|
||||
&recipe.name,
|
||||
&recipe.recipe,
|
||||
config.cook.offline,
|
||||
!is_deps,
|
||||
)
|
||||
.map_err(|err| anyhow!("failed to build: {}", err))?;
|
||||
|
||||
package(
|
||||
&stage_dir,
|
||||
&target_dir,
|
||||
&recipe.name,
|
||||
&recipe.recipe,
|
||||
&auto_deps,
|
||||
)
|
||||
.map_err(|err| anyhow!("failed to package: {}", err))?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn handle_fetch(recipe_path: &Path, config: &CliConfig) -> anyhow::Result<()> {
|
||||
let mut cmd = Command::new("cook");
|
||||
cmd.arg("--fetch-only");
|
||||
if config.with_package_deps {
|
||||
cmd.arg("--with-package-deps");
|
||||
fn handle_clean(
|
||||
recipe: &CookRecipe,
|
||||
_config: &CliConfig,
|
||||
source: bool,
|
||||
target: bool,
|
||||
) -> anyhow::Result<()> {
|
||||
let dir = recipe.dir.join("target");
|
||||
if dir.exists() && target {
|
||||
fs::remove_dir_all(&dir).context(format!("failed to delete {}", dir.display()))?;
|
||||
}
|
||||
if config.offline {
|
||||
cmd.arg("--offline");
|
||||
}
|
||||
if config.quiet {
|
||||
cmd.arg("--quiet");
|
||||
}
|
||||
cmd.arg(recipe_path);
|
||||
let status = cmd.status().context("Failed to execute cook command")?;
|
||||
if !status.success() && !config.nonstop {
|
||||
return Err(anyhow!(
|
||||
"Cook command failed for recipe '{}' with exit code: {}",
|
||||
recipe_path.display(),
|
||||
status.code().unwrap_or(1)
|
||||
));
|
||||
let dir = recipe.dir.join("source");
|
||||
if dir.exists() && source {
|
||||
fs::remove_dir_all(&dir).context(format!("failed to delete {}", dir.display()))?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn handle_cook(recipe_path: &Path, config: &CliConfig) -> anyhow::Result<()> {
|
||||
let mut cmd = Command::new("cook");
|
||||
cmd.arg(recipe_path);
|
||||
if config.with_package_deps {
|
||||
cmd.arg("--with-package-deps");
|
||||
}
|
||||
if config.offline {
|
||||
cmd.arg("--offline");
|
||||
}
|
||||
if config.quiet {
|
||||
cmd.arg("--quiet");
|
||||
}
|
||||
let status = cmd.status().context("Failed to execute cook command")?;
|
||||
if !status.success() && !config.nonstop {
|
||||
return Err(anyhow!(
|
||||
"Cook command failed for recipe '{}' with exit code: {}",
|
||||
recipe_path.display(),
|
||||
status.code().unwrap_or(1)
|
||||
));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn handle_unfetch(recipe_path: &Path, _config: &CliConfig) -> anyhow::Result<()> {
|
||||
let dir = recipe_path.join("source");
|
||||
if dir.exists() {
|
||||
fs::remove_dir_all(dir).context(format!("failed to delete {}", recipe_path.display()))?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn handle_clean(recipe_path: &Path, _config: &CliConfig) -> anyhow::Result<()> {
|
||||
let dir = recipe_path.join("target");
|
||||
if dir.exists() {
|
||||
fs::remove_dir_all(dir).context(format!("failed to delete {}", recipe_path.display()))?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn handle_push(recipe_path: &Path, config: &CliConfig) -> anyhow::Result<()> {
|
||||
fn handle_push(recipe: &CookRecipe, config: &CliConfig) -> anyhow::Result<()> {
|
||||
let public_path = "build/id_ed25519.pub.toml";
|
||||
let archive_path = config.repo_dir.join(recipe.name.as_str());
|
||||
pkgar::extract(
|
||||
public_path,
|
||||
config.sysroot_dir.as_path(),
|
||||
archive_path.as_path(),
|
||||
config.sysroot_dir.to_str().unwrap(),
|
||||
)
|
||||
.context(format!(
|
||||
"failed to install '{}' in '{}'",
|
||||
recipe_path.display(),
|
||||
archive_path.display(),
|
||||
config.sysroot_dir.display(),
|
||||
))
|
||||
}
|
||||
|
||||
@ -26,6 +26,9 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
.next()
|
||||
.expect("Usage: repo_builder <REPO_DIR> <recipe1> <recipe2> ...");
|
||||
let repo_path = Path::new(&repo_dir);
|
||||
if !repo_path.is_dir() {
|
||||
fs::create_dir_all(repo_path)?;
|
||||
}
|
||||
|
||||
// Runtime dependencies include both `[package.dependencies]` and dynamically
|
||||
// linked packages discovered by auto_deps.
|
||||
|
||||
@ -1,16 +1,58 @@
|
||||
use std::{collections::HashMap, fs, sync::OnceLock};
|
||||
use std::{collections::HashMap, env, fs, str::FromStr, sync::OnceLock};
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Debug, Default, Clone, Deserialize, PartialEq, Serialize)]
|
||||
pub struct CookConfigOpt {
|
||||
/// whether to run offline
|
||||
pub offline: Option<bool>,
|
||||
/// whether to set jobs number instead of from nproc
|
||||
pub jobs: Option<usize>,
|
||||
/// whether to use TUI to allow parallel build
|
||||
/// default value is yes if "CI" env unset and STDIN is open.
|
||||
pub tui: Option<bool>,
|
||||
/// whether to ignore build errors
|
||||
pub nonstop: Option<bool>,
|
||||
/// whether to not capture build output,
|
||||
/// default is true if "tui" is false.
|
||||
/// build failure still be printed anyway
|
||||
pub verbose: Option<bool>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Clone, Deserialize, PartialEq, Serialize)]
|
||||
pub struct CookConfig {
|
||||
pub offline: bool,
|
||||
pub jobs: usize,
|
||||
pub tui: bool,
|
||||
pub nonstop: bool,
|
||||
pub verbose: bool,
|
||||
}
|
||||
|
||||
impl From<CookConfigOpt> for CookConfig {
|
||||
fn from(value: CookConfigOpt) -> Self {
|
||||
CookConfig {
|
||||
offline: value.offline.unwrap(),
|
||||
jobs: value.jobs.unwrap(),
|
||||
tui: value.tui.unwrap(),
|
||||
nonstop: value.nonstop.unwrap(),
|
||||
verbose: value.verbose.unwrap(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Deserialize, PartialEq, Serialize)]
|
||||
pub struct CookbookConfig {
|
||||
#[serde(rename = "cook")]
|
||||
cook_opt: CookConfigOpt,
|
||||
#[serde(skip)]
|
||||
pub cook: CookConfig,
|
||||
pub mirrors: HashMap<String, String>,
|
||||
}
|
||||
|
||||
static CONFIG: OnceLock<CookbookConfig> = OnceLock::new();
|
||||
|
||||
pub fn init_config() {
|
||||
let config: CookbookConfig = if fs::exists("cookbook.toml").unwrap_or(false) {
|
||||
let mut config: CookbookConfig = if fs::exists("cookbook.toml").unwrap_or(false) {
|
||||
let toml_content = fs::read_to_string("cookbook.toml")
|
||||
.map_err(|e| format!("Unable to read config: {:?}", e))
|
||||
.unwrap();
|
||||
@ -21,9 +63,47 @@ pub fn init_config() {
|
||||
CookbookConfig::default()
|
||||
};
|
||||
|
||||
if config.cook_opt.tui.is_none() {
|
||||
config.cook_opt.tui = Some(!env::var("CI").is_ok_and(|s| !s.is_empty()));
|
||||
}
|
||||
if config.cook_opt.jobs.is_none() {
|
||||
config.cook_opt.jobs = Some(extract_env(
|
||||
"COOKBOOK_MAKE_JOBS",
|
||||
std::thread::available_parallelism()
|
||||
.map(|f| usize::from(f))
|
||||
.unwrap_or(1),
|
||||
));
|
||||
}
|
||||
if config.cook_opt.offline.is_none() {
|
||||
config.cook_opt.offline = Some(extract_env("COOKBOOK_OFFLINE", false));
|
||||
}
|
||||
if config.cook_opt.verbose.is_none() {
|
||||
config.cook_opt.verbose = Some(extract_env(
|
||||
"COOKBOOK_VERBOSE",
|
||||
!config.cook_opt.tui.unwrap(),
|
||||
));
|
||||
}
|
||||
if config.cook_opt.nonstop.is_none() {
|
||||
config.cook_opt.nonstop = Some(extract_env("COOKBOOK_NONSTOP", false));
|
||||
}
|
||||
|
||||
config.cook = CookConfig::from(config.cook_opt.clone());
|
||||
|
||||
CONFIG.set(config).expect("config is initialized twice");
|
||||
}
|
||||
|
||||
fn extract_env<T: FromStr>(key: &str, default: T) -> T {
|
||||
if let Ok(e) = env::var(&key) {
|
||||
str::parse(&e).unwrap_or(default)
|
||||
} else {
|
||||
default
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_config() -> &'static CookbookConfig {
|
||||
return CONFIG.get().expect("Configuration is not initialized");
|
||||
}
|
||||
|
||||
pub fn translate_mirror(original_url: &str) -> String {
|
||||
let config = CONFIG.get().expect("Configuration is not initialized");
|
||||
|
||||
|
||||
@ -151,6 +151,10 @@ pub fn build(
|
||||
) -> Result<(PathBuf, BTreeSet<PackageName>), String> {
|
||||
let sysroot_dir = target_dir.join("sysroot");
|
||||
let stage_dir = target_dir.join("stage");
|
||||
if recipe.build.kind == BuildKind::None {
|
||||
// metapackages don't need to do anything here
|
||||
return Ok((stage_dir, BTreeSet::new()));
|
||||
}
|
||||
|
||||
let mut dep_pkgars = BTreeSet::new();
|
||||
for dependency in recipe.build.dependencies.iter() {
|
||||
|
||||
@ -2,6 +2,7 @@ use crate::config::translate_mirror;
|
||||
use crate::cook::fs::*;
|
||||
use crate::cook::script::*;
|
||||
use crate::is_redox;
|
||||
use crate::recipe::BuildKind;
|
||||
use crate::recipe::Recipe;
|
||||
use crate::{blake3, recipe::SourceRecipe};
|
||||
use std::fs;
|
||||
@ -24,14 +25,18 @@ pub(crate) fn get_blake3(path: &PathBuf, show_progress: bool) -> Result<String,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn fetch_offline(recipe_dir: &Path, source: &Option<SourceRecipe>) -> Result<PathBuf, String> {
|
||||
pub fn fetch_offline(recipe_dir: &Path, recipe: &Recipe) -> Result<PathBuf, String> {
|
||||
let source_dir = recipe_dir.join("source");
|
||||
match source {
|
||||
if recipe.build.kind == BuildKind::None || recipe.build.kind == BuildKind::Remote {
|
||||
// the build function doesn't need source dir exists
|
||||
return Ok(source_dir);
|
||||
}
|
||||
match &recipe.source {
|
||||
Some(SourceRecipe::Path { path: _ }) | None => {
|
||||
return fetch(recipe_dir, source);
|
||||
return fetch(recipe_dir, recipe);
|
||||
}
|
||||
Some(SourceRecipe::SameAs { same_as: _ }) => {
|
||||
return fetch(recipe_dir, source);
|
||||
return fetch(recipe_dir, recipe);
|
||||
}
|
||||
Some(SourceRecipe::Git {
|
||||
git: _,
|
||||
@ -79,17 +84,22 @@ pub fn fetch_offline(recipe_dir: &Path, source: &Option<SourceRecipe>) -> Result
|
||||
Ok(source_dir)
|
||||
}
|
||||
|
||||
pub fn fetch(recipe_dir: &Path, source: &Option<SourceRecipe>) -> Result<PathBuf, String> {
|
||||
pub fn fetch(recipe_dir: &Path, recipe: &Recipe) -> Result<PathBuf, String> {
|
||||
let source_dir = recipe_dir.join("source");
|
||||
match source {
|
||||
if recipe.build.kind == BuildKind::None || recipe.build.kind == BuildKind::Remote {
|
||||
// the build function doesn't need source dir exists
|
||||
return Ok(source_dir);
|
||||
}
|
||||
match &recipe.source {
|
||||
Some(SourceRecipe::SameAs { same_as }) => {
|
||||
let (canon_dir, recipe) = fetch_resolve_canon(recipe_dir, same_as)?;
|
||||
let (canon_dir, recipe) = fetch_resolve_canon(recipe_dir, &same_as)?;
|
||||
// recursively fetch
|
||||
fetch(&canon_dir, &recipe.source)?;
|
||||
fetch_make_symlink(&source_dir, same_as)?;
|
||||
fetch(&canon_dir, &recipe)?;
|
||||
fetch_make_symlink(&source_dir, &same_as)?;
|
||||
}
|
||||
Some(SourceRecipe::Path { path }) => {
|
||||
if !source_dir.is_dir() || modified_dir(Path::new(path))? > modified_dir(&source_dir)? {
|
||||
if !source_dir.is_dir() || modified_dir(Path::new(&path))? > modified_dir(&source_dir)?
|
||||
{
|
||||
eprintln!("[DEBUG]: {} is newer than {}", path, source_dir.display());
|
||||
copy_dir_all(path, &source_dir).map_err(|e| {
|
||||
format!(
|
||||
@ -122,7 +132,7 @@ pub fn fetch(recipe_dir: &Path, source: &Option<SourceRecipe>) -> Result<PathBuf
|
||||
command
|
||||
.arg("clone")
|
||||
.arg("--recursive")
|
||||
.arg(translate_mirror(git));
|
||||
.arg(translate_mirror(&git));
|
||||
if let Some(branch) = branch {
|
||||
command.arg("--branch").arg(branch);
|
||||
}
|
||||
@ -268,7 +278,6 @@ pub fn fetch(recipe_dir: &Path, source: &Option<SourceRecipe>) -> Result<PathBuf
|
||||
// Local Sources
|
||||
None => {
|
||||
if !source_dir.is_dir() {
|
||||
//TODO: Don't print if build template is none or remote
|
||||
eprintln!(
|
||||
"WARNING: Recipe without source section expected source dir at '{}'",
|
||||
source_dir.display(),
|
||||
|
||||
@ -1,8 +1,4 @@
|
||||
use std::{
|
||||
collections::BTreeSet,
|
||||
env,
|
||||
path::{Path, PathBuf},
|
||||
};
|
||||
use std::{collections::BTreeSet, env, path::Path};
|
||||
|
||||
use pkg::{Package, PackageName};
|
||||
|
||||
@ -17,7 +13,13 @@ pub fn package(
|
||||
name: &PackageName,
|
||||
recipe: &Recipe,
|
||||
auto_deps: &BTreeSet<PackageName>,
|
||||
) -> Result<PathBuf, String> {
|
||||
) -> Result<(), String> {
|
||||
if recipe.build.kind == BuildKind::None {
|
||||
// metapackages don't have stage dir
|
||||
package_toml(target_dir, name, recipe, auto_deps)?;
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let secret_path = "build/id_ed25519.toml";
|
||||
let public_path = "build/id_ed25519.pub.toml";
|
||||
if !Path::new(secret_path).is_file() || !Path::new(public_path).is_file() {
|
||||
@ -58,7 +60,7 @@ pub fn package(
|
||||
package_toml(target_dir, name, recipe, auto_deps)?;
|
||||
}
|
||||
|
||||
Ok(package_file)
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn package_toml(
|
||||
@ -80,7 +82,8 @@ pub fn package_toml(
|
||||
depends,
|
||||
};
|
||||
|
||||
serialize_and_write(&target_dir.join("stage.toml"), &package)?;
|
||||
let toml_path = &target_dir.join("stage.toml");
|
||||
serialize_and_write(&toml_path, &package)?;
|
||||
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
@ -1,4 +1,9 @@
|
||||
use std::{collections::BTreeSet, convert::TryInto, fs, path::PathBuf};
|
||||
use std::{
|
||||
collections::BTreeSet,
|
||||
convert::TryInto,
|
||||
fs,
|
||||
path::{Path, PathBuf},
|
||||
};
|
||||
|
||||
use pkg::{PackageName, package::PackageError, recipes};
|
||||
use regex::Regex;
|
||||
@ -146,7 +151,7 @@ pub struct PackageRecipe {
|
||||
}
|
||||
|
||||
/// Everything required to build a Redox package
|
||||
#[derive(Debug, Deserialize, PartialEq, Serialize)]
|
||||
#[derive(Debug, Default, Deserialize, PartialEq, Serialize)]
|
||||
pub struct Recipe {
|
||||
/// Specifies how to download the source for this recipe
|
||||
pub source: Option<SourceRecipe>,
|
||||
@ -158,6 +163,18 @@ pub struct Recipe {
|
||||
pub package: PackageRecipe,
|
||||
}
|
||||
|
||||
impl Recipe {
|
||||
pub fn new(file: &PathBuf) -> Result<Recipe, PackageError> {
|
||||
if !file.is_file() {
|
||||
return Err(PackageError::FileMissing(file.clone()));
|
||||
}
|
||||
let toml = fs::read_to_string(&file)
|
||||
.map_err(|err| PackageError::Parse(DeError::custom(err), Some(file.clone())))?;
|
||||
let recipe: Recipe = toml::from_str(&toml)
|
||||
.map_err(|err| PackageError::Parse(DeError::custom(err), Some(file.clone())))?;
|
||||
Ok(recipe)
|
||||
}
|
||||
}
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub struct CookRecipe {
|
||||
pub name: PackageName,
|
||||
@ -168,24 +185,7 @@ pub struct CookRecipe {
|
||||
}
|
||||
|
||||
impl CookRecipe {
|
||||
pub fn new(
|
||||
name: impl TryInto<PackageName, Error = PackageError>,
|
||||
) -> Result<Self, PackageError> {
|
||||
let name: PackageName = name.try_into()?;
|
||||
let dir = recipes::find(name.as_str())
|
||||
.ok_or_else(|| PackageError::PackageNotFound(name.clone()))?;
|
||||
let file = dir.join("recipe.toml");
|
||||
if !file.is_file() {
|
||||
return Err(PackageError::FileMissing(file));
|
||||
}
|
||||
|
||||
let toml = fs::read_to_string(&file)
|
||||
.map_err(|err| PackageError::Parse(DeError::custom(err), Some(file.clone())))?;
|
||||
|
||||
let recipe: Recipe = toml::from_str(&toml)
|
||||
.map_err(|err| PackageError::Parse(DeError::custom(err), Some(file)))?;
|
||||
|
||||
let dir = dir.to_path_buf();
|
||||
pub fn new(name: PackageName, dir: PathBuf, recipe: Recipe) -> Result<Self, PackageError> {
|
||||
Ok(Self {
|
||||
name,
|
||||
dir,
|
||||
@ -194,6 +194,29 @@ impl CookRecipe {
|
||||
})
|
||||
}
|
||||
|
||||
pub fn from_name(
|
||||
name: impl TryInto<PackageName, Error = PackageError>,
|
||||
) -> Result<Self, PackageError> {
|
||||
let name: PackageName = name.try_into()?;
|
||||
let dir = recipes::find(name.as_str())
|
||||
.ok_or_else(|| PackageError::PackageNotFound(name.clone()))?;
|
||||
let file = dir.join("recipe.toml");
|
||||
let recipe = Recipe::new(&file)?;
|
||||
Self::new(name, dir.to_path_buf(), recipe)
|
||||
}
|
||||
|
||||
pub fn from_path(dir: &Path, read_recipe: bool) -> Result<Self, PackageError> {
|
||||
let file = dir.join("recipe.toml");
|
||||
let name: PackageName = file.file_name().unwrap().try_into()?;
|
||||
let recipe = if read_recipe {
|
||||
Recipe::new(&file)?
|
||||
} else {
|
||||
// clean/unfetch don't need to read recipe
|
||||
Recipe::default()
|
||||
};
|
||||
Self::new(name, dir.to_path_buf(), recipe)
|
||||
}
|
||||
|
||||
pub fn new_recursive(
|
||||
names: &[PackageName],
|
||||
recursion: usize,
|
||||
@ -204,7 +227,7 @@ impl CookRecipe {
|
||||
|
||||
let mut recipes = Vec::new();
|
||||
for name in names {
|
||||
let recipe = Self::new(name.as_str())?;
|
||||
let recipe = Self::from_name(name.as_str())?;
|
||||
|
||||
let dependencies =
|
||||
Self::new_recursive(&recipe.recipe.build.dependencies, recursion - 1).map_err(
|
||||
@ -253,7 +276,7 @@ impl CookRecipe {
|
||||
|
||||
let mut recipes: Vec<PackageName> = Vec::new();
|
||||
for name in names {
|
||||
let recipe = Self::new(name.as_str())?;
|
||||
let recipe = Self::from_name(name.as_str())?;
|
||||
|
||||
let dependencies = Self::get_package_deps_recursive(
|
||||
&recipe.recipe.package.dependencies,
|
||||
|
||||
Loading…
Reference in New Issue
Block a user