mirror of
https://gitlab.redox-os.org/redox-os/redox.git
synced 2026-06-25 06:14:18 +08:00
Migrate error type and drop anyhow
This commit is contained in:
parent
6d774c117a
commit
208878c1bf
5
Cargo.lock
generated
5
Cargo.lock
generated
@ -38,9 +38,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.100"
|
||||
version = "1.0.102"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61"
|
||||
checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c"
|
||||
|
||||
[[package]]
|
||||
name = "arg_parser"
|
||||
@ -871,7 +871,6 @@ name = "redox_cookbook"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"ansi-to-tui",
|
||||
"anyhow",
|
||||
"blake3",
|
||||
"globset",
|
||||
"ignore",
|
||||
|
||||
@ -30,7 +30,6 @@ default = ["tui"]
|
||||
tui = ["ratatui", "ansi-to-tui", "strip-ansi-escapes"]
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1"
|
||||
blake3 = "1"
|
||||
globset = "0.4"
|
||||
libc = "0.2"
|
||||
|
||||
135
src/bin/repo.rs
135
src/bin/repo.rs
@ -1,16 +1,15 @@
|
||||
use ansi_to_tui::IntoText;
|
||||
use anyhow::{Context, anyhow, bail};
|
||||
use cookbook::config::{CookConfig, get_config, init_config};
|
||||
use cookbook::cook::cook_build::{build, get_stage_dirs, remove_stage_dir};
|
||||
use cookbook::cook::fetch::{FetchResult, fetch, fetch_offline};
|
||||
use cookbook::cook::fs::{create_target_dir, run_command};
|
||||
use cookbook::cook::fs::{create_dir, create_target_dir, remove_all, run_command};
|
||||
use cookbook::cook::ident;
|
||||
use cookbook::cook::package::{package, package_handle_push};
|
||||
use cookbook::cook::pty::{PtyOut, UnixSlavePty, flush_pty, setup_pty, write_to_pty};
|
||||
use cookbook::cook::script::KILL_ALL_PID;
|
||||
use cookbook::cook::tree::{self, WalkTreeEntry};
|
||||
use cookbook::recipe::{CookRecipe, recipes_flatten_package_names, recipes_mark_as_deps};
|
||||
use cookbook::{Error, staged_pkg};
|
||||
use cookbook::{Error, Result, staged_pkg};
|
||||
use pkg::{PackageName, PackageState};
|
||||
use ratatui::Terminal;
|
||||
use ratatui::layout::{Constraint, Direction, Layout, Rect};
|
||||
@ -122,9 +121,9 @@ impl CliCommand {
|
||||
}
|
||||
|
||||
impl FromStr for CliCommand {
|
||||
type Err = anyhow::Error;
|
||||
type Err = Error;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
|
||||
match s {
|
||||
"fetch" => Ok(CliCommand::Fetch),
|
||||
"cook" => Ok(CliCommand::Cook),
|
||||
@ -135,7 +134,10 @@ impl FromStr for CliCommand {
|
||||
"push-tree" => Ok(CliCommand::PushTree),
|
||||
"cook-tree" => Ok(CliCommand::CookTree),
|
||||
"find" => Ok(CliCommand::Find),
|
||||
_ => Err(anyhow!("Unknown command '{}'\n{}\n", s, REPO_HELP_STR)),
|
||||
_ => Err(Error::Other(format!(
|
||||
"Unknown command '{}'\n{}\n",
|
||||
s, REPO_HELP_STR
|
||||
))),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -157,8 +159,8 @@ impl ToString for CliCommand {
|
||||
}
|
||||
|
||||
impl CliConfig {
|
||||
fn new() -> Result<Self, std::io::Error> {
|
||||
let current_dir = env::current_dir()?;
|
||||
fn new() -> Result<Self> {
|
||||
let current_dir = env::current_dir().map_err(|e| Error::from_io_error(e, "Getting cwd"))?;
|
||||
Ok(CliConfig {
|
||||
//FIXME: This config is unused as redox-pkg harcoded this to $PWD/recipes
|
||||
cookbook_dir: current_dir.join("recipes"),
|
||||
@ -191,7 +193,7 @@ fn main() {
|
||||
};
|
||||
}
|
||||
|
||||
fn main_inner() -> anyhow::Result<()> {
|
||||
fn main_inner() -> Result<()> {
|
||||
let args: Vec<String> = env::args().skip(1).collect();
|
||||
|
||||
if args.is_empty() || args.contains(&"--help".to_string()) || args.contains(&"-h".to_string()) {
|
||||
@ -212,7 +214,7 @@ fn main_inner() -> anyhow::Result<()> {
|
||||
let _ = stderr().write(err.as_bytes());
|
||||
let _ = stderr().write(b"\n\n");
|
||||
print_failed(&command, &name);
|
||||
return Err(anyhow!("Execution has failed"));
|
||||
return Err(Error::from(format!("Execution has failed")));
|
||||
}
|
||||
Ok(app) => {
|
||||
for (recipe, status) in app.recipes {
|
||||
@ -228,7 +230,7 @@ fn main_inner() -> anyhow::Result<()> {
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(e) => return Err(anyhow!(e)),
|
||||
Err(e) => return Err(e),
|
||||
}
|
||||
return publish_packages(&recipes, &config.repo_dir);
|
||||
}
|
||||
@ -321,14 +323,10 @@ fn print_cached(command: &CliCommand, recipe: &PackageName) {
|
||||
);
|
||||
}
|
||||
|
||||
fn repo_inner(
|
||||
config: &CliConfig,
|
||||
command: &CliCommand,
|
||||
recipe: &CookRecipe,
|
||||
) -> Result<bool, anyhow::Error> {
|
||||
fn repo_inner(config: &CliConfig, command: &CliCommand, recipe: &CookRecipe) -> Result<bool> {
|
||||
Ok(match *command {
|
||||
CliCommand::Fetch | CliCommand::Cook => {
|
||||
let repo_inner_fn = move |logger: &PtyOut| -> Result<bool, anyhow::Error> {
|
||||
let repo_inner_fn = move |logger: &PtyOut| -> Result<bool> {
|
||||
let is_cook = *command == CliCommand::Cook;
|
||||
let fetch_result = handle_fetch(recipe, config, is_cook, logger)?;
|
||||
let cached = if is_cook {
|
||||
@ -399,8 +397,12 @@ fn repo_inner(
|
||||
})
|
||||
}
|
||||
|
||||
fn publish_packages(recipe_names: &Vec<CookRecipe>, repo_path: &PathBuf) -> anyhow::Result<()> {
|
||||
let repo_bin = env::current_exe()?.parent().unwrap().join("repo_builder");
|
||||
fn publish_packages(recipe_names: &Vec<CookRecipe>, repo_path: &PathBuf) -> Result<()> {
|
||||
let repo_bin = env::current_exe()
|
||||
.map_err(|e| Error::from_io_error(e, "Getting exe path"))?
|
||||
.parent()
|
||||
.unwrap()
|
||||
.join("repo_builder");
|
||||
let mut command = Command::new(repo_bin);
|
||||
command
|
||||
.arg(repo_path)
|
||||
@ -412,10 +414,10 @@ fn publish_packages(recipe_names: &Vec<CookRecipe>, repo_path: &PathBuf) -> anyh
|
||||
}
|
||||
}));
|
||||
|
||||
run_command(command, &None).map_err(|e| anyhow!(e))
|
||||
run_command(command, &None)
|
||||
}
|
||||
|
||||
fn parse_args(args: Vec<String>) -> anyhow::Result<(CliConfig, CliCommand, Vec<CookRecipe>)> {
|
||||
fn parse_args(args: Vec<String>) -> Result<(CliConfig, CliCommand, Vec<CookRecipe>)> {
|
||||
let mut config = CliConfig::new()?;
|
||||
let mut command: Option<String> = None;
|
||||
let mut recipe_names: Vec<PackageName> = Vec::new();
|
||||
@ -431,7 +433,7 @@ fn parse_args(args: Vec<String>) -> anyhow::Result<(CliConfig, CliCommand, Vec<C
|
||||
"--filesystem" => {
|
||||
config.filesystem = Some({
|
||||
let r = redox_installer::Config::from_file(&PathBuf::from(value));
|
||||
r.context("Unable to read filesystem installer config")?
|
||||
r.map_err(|e| Error::Other(e.to_string()))?
|
||||
})
|
||||
}
|
||||
_ => {
|
||||
@ -465,7 +467,7 @@ fn parse_args(args: Vec<String>) -> anyhow::Result<(CliConfig, CliCommand, Vec<C
|
||||
command = Some(arg);
|
||||
} else {
|
||||
// Subsequent non-flag arguments are recipe names
|
||||
recipe_names.push(arg.try_into().context("Invalid package name")?);
|
||||
recipe_names.push(arg.try_into().map_err(Error::from)?);
|
||||
}
|
||||
}
|
||||
|
||||
@ -474,11 +476,13 @@ fn parse_args(args: Vec<String>) -> anyhow::Result<(CliConfig, CliCommand, Vec<C
|
||||
config.category = Some(PathBuf::from("recipes").join(c));
|
||||
}
|
||||
if let Some(c) = config.logs_dir.as_mut() {
|
||||
fs::create_dir_all(c.join(redoxer::target())).map_err(|e| anyhow!(e))?;
|
||||
fs::create_dir_all(c.join(redoxer::host_target())).map_err(|e| anyhow!(e))?;
|
||||
create_dir(&c.join(redoxer::target()))?;
|
||||
create_dir(&c.join(redoxer::host_target()))?;
|
||||
}
|
||||
|
||||
let command = command.ok_or(anyhow!("Error: No command specified."))?;
|
||||
let Some(command) = command else {
|
||||
return Err(Error::Other(format!("Error: No command specified.")));
|
||||
};
|
||||
let command: CliCommand = str::parse(&command)?;
|
||||
if command.is_informational() {
|
||||
// avoid extra data that clobber stdout
|
||||
@ -490,18 +494,22 @@ fn parse_args(args: Vec<String>) -> anyhow::Result<(CliConfig, CliCommand, Vec<C
|
||||
if recipe_names.is_empty() {
|
||||
if config.all || config.category.is_some() {
|
||||
if !recipe_names.is_empty() {
|
||||
bail!("Do not specify recipe names when using the --all or --category flag.");
|
||||
return Err(Error::Other(format!(
|
||||
"Do not specify recipe names when using the --all or --category flag."
|
||||
)));
|
||||
}
|
||||
if config.all && config.category.is_some() {
|
||||
bail!("Do not specify both --all and --category flag.");
|
||||
return Err(Error::Other(format!(
|
||||
"Do not specify both --all and --category flag."
|
||||
)));
|
||||
}
|
||||
if config.all && !command.is_cleaning() {
|
||||
// because read_recipe is false by logic below
|
||||
// some recipes on wip folders are invalid anyway
|
||||
bail!(
|
||||
return Err(Error::Other(format!(
|
||||
"Refusing to run an unrealistic command to {} all recipes",
|
||||
command.to_string()
|
||||
);
|
||||
)));
|
||||
}
|
||||
let all_recipes_path = match &config.category {
|
||||
None => staged_pkg::list(""),
|
||||
@ -526,9 +534,9 @@ fn parse_args(args: Vec<String>) -> anyhow::Result<(CliConfig, CliCommand, Vec<C
|
||||
.filter_map(|k| PackageName::new(k.to_string()).ok())
|
||||
.collect();
|
||||
} else {
|
||||
bail!(
|
||||
return Err(Error::Other(format!(
|
||||
"Error: No recipe names or filesystem config provided and --all flag was not used."
|
||||
);
|
||||
)));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -696,14 +704,11 @@ fn handle_fetch(
|
||||
config: &CliConfig,
|
||||
allow_offline: bool,
|
||||
logger: &PtyOut,
|
||||
) -> anyhow::Result<FetchResult> {
|
||||
let source_dir = match config.cook.offline && allow_offline {
|
||||
) -> Result<FetchResult> {
|
||||
match config.cook.offline && allow_offline {
|
||||
true => fetch_offline(&recipe, logger),
|
||||
false => fetch(&recipe, !recipe.is_deps, logger),
|
||||
}
|
||||
.map_err(|e| anyhow!("failed to fetch: {}", e))?;
|
||||
|
||||
Ok(source_dir)
|
||||
}
|
||||
|
||||
fn handle_cook(
|
||||
@ -711,9 +716,9 @@ fn handle_cook(
|
||||
config: &CliConfig,
|
||||
source_dir: PathBuf,
|
||||
logger: &PtyOut,
|
||||
) -> anyhow::Result<bool> {
|
||||
) -> Result<bool> {
|
||||
let recipe_dir = &recipe.dir;
|
||||
let target_dir = create_target_dir(recipe_dir, recipe.target).map_err(|e| anyhow!(e))?;
|
||||
let target_dir = create_target_dir(recipe_dir, recipe.target)?;
|
||||
let build_result = build(
|
||||
recipe_dir,
|
||||
&source_dir,
|
||||
@ -721,11 +726,9 @@ fn handle_cook(
|
||||
&recipe,
|
||||
&config.cook,
|
||||
logger,
|
||||
)
|
||||
.map_err(|err| anyhow!("failed to build: {}", err))?;
|
||||
)?;
|
||||
|
||||
package(&recipe, &build_result, &config.cook, logger)
|
||||
.map_err(|err| anyhow!("failed to package: {}", err))?;
|
||||
package(&recipe, &build_result, &config.cook, logger)?;
|
||||
|
||||
if config.cook.clean_target || config.cook.write_filetree {
|
||||
for stage_dir in &build_result.stage_dirs {
|
||||
@ -733,12 +736,12 @@ fn handle_cook(
|
||||
if config.cook.write_filetree {
|
||||
let mut stage_files_buf = String::new();
|
||||
tree::walk_file_tree(&stage_dir, "", &mut stage_files_buf)
|
||||
.context("failed to walk stage files tree")?;
|
||||
.map_err(|e| Error::from_io_error(e, "Walking files tree"))?;
|
||||
fs::write(stage_dir.with_added_extension("files"), stage_files_buf)
|
||||
.context("unable to write stage files")?;
|
||||
.map_err(|e| Error::from_io_error(e, "Writing files tree"))?;
|
||||
}
|
||||
if config.cook.clean_target {
|
||||
fs::remove_dir_all(&stage_dir).context("failed to remove stage dir")?;
|
||||
remove_all(&stage_dir)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -756,30 +759,26 @@ fn handle_nonstop_fail(recipe: &CookRecipe) -> cookbook::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn handle_clean(
|
||||
recipe: &CookRecipe,
|
||||
_config: &CliConfig,
|
||||
command: &CliCommand,
|
||||
) -> anyhow::Result<bool> {
|
||||
fn handle_clean(recipe: &CookRecipe, _config: &CliConfig, command: &CliCommand) -> Result<bool> {
|
||||
let mut dir = recipe.dir.join("target");
|
||||
let mut cached = true;
|
||||
if matches!(*command, CliCommand::CleanTarget) {
|
||||
dir = dir.join(redoxer::target())
|
||||
}
|
||||
if dir.exists() {
|
||||
fs::remove_dir_all(&dir).context(format!("failed to delete {}", dir.display()))?;
|
||||
remove_all(&dir)?;
|
||||
cached = false;
|
||||
}
|
||||
let dir = recipe.dir.join("source");
|
||||
if dir.exists() && matches!(*command, CliCommand::Unfetch) {
|
||||
fs::remove_dir_all(&dir).context(format!("failed to delete {}", dir.display()))?;
|
||||
remove_all(&dir)?;
|
||||
cached = false;
|
||||
}
|
||||
Ok(cached)
|
||||
}
|
||||
|
||||
static PUSH_SYSROOT_DIR: OnceLock<PathBuf> = OnceLock::new();
|
||||
fn handle_push(recipes: &Vec<CookRecipe>, config: &CliConfig) -> anyhow::Result<()> {
|
||||
fn handle_push(recipes: &Vec<CookRecipe>, config: &CliConfig) -> Result<()> {
|
||||
let recipe_map: HashMap<&PackageName, &CookRecipe> =
|
||||
recipes.iter().map(|r| (&r.name, r)).collect();
|
||||
let mut total_size: u64 = 0;
|
||||
@ -791,23 +790,23 @@ fn handle_push(recipes: &Vec<CookRecipe>, config: &CliConfig) -> anyhow::Result<
|
||||
_prefix: &str,
|
||||
_is_last: bool,
|
||||
entry: &WalkTreeEntry|
|
||||
-> anyhow::Result<bool> {
|
||||
-> Result<bool> {
|
||||
let r = match entry {
|
||||
WalkTreeEntry::Built(archive_path, _) => {
|
||||
let install_path = PUSH_SYSROOT_DIR.get().unwrap();
|
||||
let mut state =
|
||||
PackageState::from_sysroot(install_path).map_err(|e| anyhow!("{e:?}"))?;
|
||||
let r = package_handle_push(&mut state, archive_path, &install_path, false)
|
||||
.map_err(|e| anyhow!("{e:?}"));
|
||||
let mut state = PackageState::from_sysroot(install_path).map_err(Error::from)?;
|
||||
let r = package_handle_push(&mut state, archive_path, &install_path, false);
|
||||
if matches!(r, Ok(false)) {
|
||||
state.to_sysroot(install_path)?;
|
||||
state
|
||||
.to_sysroot(install_path)
|
||||
.map_err(|e| Error::from_io_error(e, "Extracting package"))?;
|
||||
}
|
||||
r
|
||||
}
|
||||
WalkTreeEntry::NotBuilt => Err(anyhow!(
|
||||
WalkTreeEntry::NotBuilt => Err(Error::Other(format!(
|
||||
"Package {} has not been built",
|
||||
package_name.name()
|
||||
)),
|
||||
))),
|
||||
WalkTreeEntry::Deduped | WalkTreeEntry::Missing => {
|
||||
// does not matter
|
||||
return Ok(false);
|
||||
@ -863,11 +862,7 @@ fn handle_push(recipes: &Vec<CookRecipe>, config: &CliConfig) -> anyhow::Result<
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn handle_tree(
|
||||
recipes: &Vec<CookRecipe>,
|
||||
is_build_tree: bool,
|
||||
_config: &CliConfig,
|
||||
) -> anyhow::Result<()> {
|
||||
fn handle_tree(recipes: &Vec<CookRecipe>, is_build_tree: bool, _config: &CliConfig) -> Result<()> {
|
||||
let recipe_map: HashMap<&PackageName, &CookRecipe> =
|
||||
recipes.iter().map(|r| (&r.name, r)).collect();
|
||||
let mut total_size: u64 = 0;
|
||||
@ -1051,13 +1046,13 @@ impl TuiApp {
|
||||
(log_text, log_line)
|
||||
}
|
||||
|
||||
pub fn write_log(&self, recipe_name: &PackageName, log_path: &PathBuf) -> anyhow::Result<()> {
|
||||
pub fn write_log(&self, recipe_name: &PackageName, log_path: &PathBuf) -> Result<()> {
|
||||
let (Some(logs), line) = self.get_recipe_log(recipe_name) else {
|
||||
return Ok(());
|
||||
};
|
||||
let str = strip_ansi_escapes::strip_str(join_logs(logs, line));
|
||||
if !str.trim_end().is_empty() {
|
||||
fs::write(log_path, str)?;
|
||||
fs::write(log_path, str).map_err(|e| Error::from_io_error(e, "Writing log"))?;
|
||||
}
|
||||
return Ok(());
|
||||
}
|
||||
@ -1162,7 +1157,7 @@ impl TuiApp {
|
||||
}
|
||||
}
|
||||
|
||||
fn run_tui_cook(config: CliConfig, recipes: Vec<CookRecipe>) -> Result<TuiApp, cookbook::Error> {
|
||||
fn run_tui_cook(config: CliConfig, recipes: Vec<CookRecipe>) -> Result<TuiApp> {
|
||||
let (work_tx, work_rx) = mpsc::channel::<(CookRecipe, FetchResult)>();
|
||||
let (status_tx, status_rx) = mpsc::channel::<StatusUpdate>();
|
||||
|
||||
|
||||
@ -1,30 +1,16 @@
|
||||
use cookbook::cook::ident::{get_ident, init_ident};
|
||||
use cookbook::cook::{fetch, package as cook_package};
|
||||
use cookbook::cook::{fetch, fs, package as cook_package};
|
||||
use cookbook::recipe::CookRecipe;
|
||||
use cookbook::web::{CliWebConfig, generate_web};
|
||||
use cookbook::{WALK_DEPTH, staged_pkg};
|
||||
use cookbook::{Error, Result, WALK_DEPTH, staged_pkg};
|
||||
use pkg::PackageName;
|
||||
use pkg::{Repository, SourceIdentifier};
|
||||
use std::collections::{BTreeMap, BTreeSet, HashMap};
|
||||
use std::env;
|
||||
use std::fs::{self, File};
|
||||
use std::io::{Read, Write};
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::process::Command;
|
||||
use toml::Value;
|
||||
|
||||
fn is_newer(src: &Path, dst: &Path) -> bool {
|
||||
match (fs::metadata(src), fs::metadata(dst)) {
|
||||
(Ok(src_meta), Ok(dst_meta)) => match (src_meta.modified(), dst_meta.modified()) {
|
||||
(Ok(src_time), Ok(dst_time)) => src_time > dst_time,
|
||||
(Ok(_), Err(_)) => true,
|
||||
_ => false,
|
||||
},
|
||||
(Ok(_), Err(_)) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
struct CliConfig {
|
||||
repo_dir: PathBuf,
|
||||
@ -34,7 +20,7 @@ struct CliConfig {
|
||||
}
|
||||
|
||||
impl CliConfig {
|
||||
fn parse_args() -> Result<Self, std::io::Error> {
|
||||
fn parse_args() -> Result<Self> {
|
||||
let mut args = env::args().skip(1);
|
||||
let repo_dir = PathBuf::from(
|
||||
args.next()
|
||||
@ -50,26 +36,29 @@ impl CliConfig {
|
||||
}
|
||||
}
|
||||
|
||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
fn main() -> Result<()> {
|
||||
init_ident();
|
||||
let conf = CliConfig::parse_args()?;
|
||||
Ok(publish_packages(&conf)?)
|
||||
}
|
||||
|
||||
// TODO: Make this callable from repo bin
|
||||
fn publish_packages(config: &CliConfig) -> anyhow::Result<()> {
|
||||
fn publish_packages(config: &CliConfig) -> Result<()> {
|
||||
let repo_path = &config.repo_dir.join(redoxer::target());
|
||||
if !repo_path.is_dir() {
|
||||
fs::create_dir_all(repo_path)?;
|
||||
fs::create_dir(repo_path)?;
|
||||
}
|
||||
|
||||
// Don't publish host packages
|
||||
let target_packages = &config
|
||||
.recipe_list
|
||||
.iter()
|
||||
.map(PackageName::new)
|
||||
.filter(|pkg| pkg.as_ref().is_ok_and(|p| !p.is_host()))
|
||||
.collect::<Result<Vec<_>, _>>()?;
|
||||
.filter_map(|n| match PackageName::new(n) {
|
||||
Ok(p) if p.is_host() => None,
|
||||
Ok(p) => Some(p),
|
||||
Err(_) => None,
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
if target_packages.len() == 0 {
|
||||
return Ok(());
|
||||
@ -89,7 +78,7 @@ fn publish_packages(config: &CliConfig) -> anyhow::Result<()> {
|
||||
|
||||
if recipe_list.len() == 0 {
|
||||
// Fail-Safe
|
||||
anyhow::bail!("Zero packages are passing the build");
|
||||
return Err(Error::Other(format!("Zero packages are passing the build")));
|
||||
}
|
||||
|
||||
let mut appstream_sources: HashMap<String, PathBuf> = HashMap::new();
|
||||
@ -116,17 +105,19 @@ fn publish_packages(config: &CliConfig) -> anyhow::Result<()> {
|
||||
let pkgar_dst = repo_path.join(format!("{}.pkgar", recipe_name));
|
||||
let toml_dst = repo_path.join(format!("{}.toml", recipe_name));
|
||||
|
||||
if !fs::exists(&toml_src)? {
|
||||
if !toml_src.is_file() {
|
||||
eprintln!("recipe {} is missing stage.toml", recipe_name);
|
||||
continue;
|
||||
}
|
||||
|
||||
if is_newer(&toml_src, &toml_dst) {
|
||||
if fs::modified_is_newer(&toml_src, &toml_dst) {
|
||||
eprintln!("\x1b[01;38;5;155mrepo - publishing {}\x1b[0m", recipe_name);
|
||||
if fs::exists(&pkgar_src)? {
|
||||
fs::copy(&pkgar_src, &pkgar_dst)?;
|
||||
if pkgar_src.is_file() {
|
||||
std::fs::copy(&pkgar_src, &pkgar_dst)
|
||||
.map_err(|e| Error::from_io_error(e, "Copying file"))?;
|
||||
}
|
||||
fs::copy(&toml_src, &toml_dst)?;
|
||||
std::fs::copy(&toml_src, &toml_dst)
|
||||
.map_err(|e| Error::from_io_error(e, "Copying file"))?;
|
||||
}
|
||||
|
||||
// TODO: Extract from pkgar instead to handle config.cook.clean_target == true
|
||||
@ -147,8 +138,7 @@ fn publish_packages(config: &CliConfig) -> anyhow::Result<()> {
|
||||
.join(&target)
|
||||
.join("appstream");
|
||||
|
||||
fs::remove_dir_all(&appstream_root).ok();
|
||||
fs::create_dir_all(&appstream_root)?;
|
||||
fs::create_dir_clean(&appstream_root)?;
|
||||
|
||||
if !appstream_sources.is_empty() {
|
||||
let mut compose_cmd = Command::new("appstreamcli");
|
||||
@ -162,10 +152,12 @@ fn publish_packages(config: &CliConfig) -> anyhow::Result<()> {
|
||||
compose_cmd.arg(source_path);
|
||||
}
|
||||
|
||||
let exit_status = compose_cmd.status()?;
|
||||
let exit_status = compose_cmd
|
||||
.status()
|
||||
.map_err(|e| Error::from_io_error(e, "Reading exit status"))?;
|
||||
if exit_status.success() {
|
||||
let appstream_pkg = repo_path.join("repo-appstream.pkgar");
|
||||
fs::remove_file(&appstream_pkg).ok();
|
||||
let _ = fs::remove_all(&appstream_pkg);
|
||||
pkgar::create(
|
||||
format!("{}/build/id_ed25519.toml", root),
|
||||
&appstream_pkg,
|
||||
@ -227,11 +219,10 @@ fn publish_packages(config: &CliConfig) -> anyhow::Result<()> {
|
||||
// === 4. Read and update repo.toml ===
|
||||
let repo_toml_path = repo_path.join("repo.toml");
|
||||
if repo_toml_path.exists() {
|
||||
let mut file = File::open(&repo_toml_path)?;
|
||||
let mut contents = String::new();
|
||||
file.read_to_string(&mut contents)?;
|
||||
let contents = fs::read_to_string(&repo_toml_path)?;
|
||||
|
||||
let parsed: Repository = toml::from_str(&contents)?;
|
||||
let parsed: Repository = toml::from_str(&contents)
|
||||
.map_err(|_| Error::Other(format!("Unable to deserialize repo.toml")))?;
|
||||
for (k, v) in parsed.packages {
|
||||
packages.insert(k, v);
|
||||
}
|
||||
@ -248,8 +239,10 @@ fn publish_packages(config: &CliConfig) -> anyhow::Result<()> {
|
||||
}
|
||||
}
|
||||
|
||||
for entry in fs::read_dir(&repo_path)? {
|
||||
let entry = entry?;
|
||||
for entry in
|
||||
std::fs::read_dir(&repo_path).map_err(|e| Error::from_io_error(e, "Listing repo"))?
|
||||
{
|
||||
let entry = entry.map_err(|e| Error::from_io_error(e, "Reading repo entry"))?;
|
||||
let path = entry.path();
|
||||
|
||||
if path.extension().and_then(|s| s.to_str()) != Some("toml") {
|
||||
@ -261,7 +254,8 @@ fn publish_packages(config: &CliConfig) -> anyhow::Result<()> {
|
||||
}
|
||||
|
||||
let content = fs::read_to_string(&path)?;
|
||||
let parsed: Value = toml::from_str(&content)?;
|
||||
let parsed: Value = toml::from_str(&content)
|
||||
.map_err(|_| Error::Other(format!("Unable to deserialize repo.toml")))?;
|
||||
|
||||
let empty_ver = Value::String("".to_string());
|
||||
let version_str = parsed
|
||||
@ -278,9 +272,7 @@ fn publish_packages(config: &CliConfig) -> anyhow::Result<()> {
|
||||
outdated_packages,
|
||||
};
|
||||
|
||||
let output = toml::to_string(&repository)?;
|
||||
let mut output_file = File::create(&repo_toml_path)?;
|
||||
output_file.write_all(output.as_bytes())?;
|
||||
fs::serialize_and_write(&repo_toml_path, &repository)?;
|
||||
|
||||
if let Some(conf) = &config.web {
|
||||
eprintln!("\x1b[01;38;5;155mrepo - generating web content\x1b[0m");
|
||||
|
||||
@ -19,7 +19,7 @@ use std::{
|
||||
time::SystemTime,
|
||||
};
|
||||
|
||||
use crate::{is_redox, log_to_pty};
|
||||
use crate::{Result, is_redox, log_to_pty};
|
||||
|
||||
fn auto_deps_from_dynamic_linking(
|
||||
stage_dirs: &[PathBuf],
|
||||
@ -155,7 +155,7 @@ fn auto_deps_from_dynamic_linking(
|
||||
fn auto_deps_from_static_package_deps(
|
||||
build_dep_pkgars: &BTreeSet<(PackageName, PathBuf)>,
|
||||
dynamic_dep_pkgars: &BTreeSet<PackageName>,
|
||||
) -> Result<BTreeSet<PackageName>, PackageError> {
|
||||
) -> std::result::Result<BTreeSet<PackageName>, PackageError> {
|
||||
let static_dep_pkgars: Vec<PackageName> = build_dep_pkgars
|
||||
.iter()
|
||||
.map(|x| x.0.clone())
|
||||
@ -197,7 +197,7 @@ pub fn build(
|
||||
cook_recipe: &CookRecipe,
|
||||
cook_config: &CookConfig,
|
||||
logger: &PtyOut,
|
||||
) -> Result<BuildResult, String> {
|
||||
) -> Result<BuildResult> {
|
||||
let recipe = &cook_recipe.recipe;
|
||||
let name = &cook_recipe.name;
|
||||
let check_source = !cook_recipe.is_deps;
|
||||
@ -565,7 +565,7 @@ fn build_deps_dir(
|
||||
dep_pkgars: &BTreeSet<(PackageName, PathBuf)>,
|
||||
source_modified: SystemTime,
|
||||
deps_modified: SystemTime,
|
||||
) -> Result<bool, String> {
|
||||
) -> Result<bool> {
|
||||
let deps_dir_tmp = deps_dir.with_added_extension("tmp");
|
||||
if deps_dir.is_dir() {
|
||||
let tags_dir = deps_dir.join(".tags");
|
||||
@ -635,7 +635,7 @@ fn build_auto_deps(
|
||||
cook_config: &CookConfig,
|
||||
mut dep_pkgars: BTreeSet<(PackageName, PathBuf)>,
|
||||
logger: &PtyOut,
|
||||
) -> Result<BTreeSet<PackageName>, String> {
|
||||
) -> Result<BTreeSet<PackageName>> {
|
||||
if auto_deps_path.is_file() && !cached {
|
||||
if cook_config.verbose {
|
||||
log_to_pty!(logger, "DEBUG: updating {}", auto_deps_path.display());
|
||||
@ -670,7 +670,7 @@ pub fn build_remote(
|
||||
recipe: &Recipe,
|
||||
target_dir: &Path,
|
||||
cook_config: &CookConfig,
|
||||
) -> Result<BuildResult, String> {
|
||||
) -> Result<BuildResult> {
|
||||
let source_toml = target_dir.join("source.toml");
|
||||
let source_pubkey = "build/remotes/pub_key_static.redox-os.org.toml";
|
||||
|
||||
|
||||
@ -102,6 +102,18 @@ pub fn symlink(original: impl AsRef<Path>, link: impl AsRef<Path>) -> Result<()>
|
||||
.map_err(wrap_io_err!(link.as_ref(), "Creating symlink"))
|
||||
}
|
||||
|
||||
pub fn modified_is_newer(src: &Path, dst: &Path) -> bool {
|
||||
match (fs::metadata(src), fs::metadata(dst)) {
|
||||
(Ok(src_meta), Ok(dst_meta)) => match (src_meta.modified(), dst_meta.modified()) {
|
||||
(Ok(src_time), Ok(dst_time)) => src_time > dst_time,
|
||||
(Ok(_), Err(_)) => true,
|
||||
_ => false,
|
||||
},
|
||||
(Ok(_), Err(_)) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
fn modified_inner(path: &Path, metadata: fs::Metadata) -> Result<SystemTime> {
|
||||
metadata
|
||||
.modified()
|
||||
|
||||
@ -8,7 +8,7 @@ use pkgar::ext::PackageSrcExt;
|
||||
use pkgar_core::HeaderFlags;
|
||||
|
||||
use crate::{
|
||||
Error,
|
||||
Error, Result,
|
||||
config::CookConfig,
|
||||
cook::{cook_build::BuildResult, fetch, fs::*, pty::PtyOut},
|
||||
log_to_pty,
|
||||
@ -20,7 +20,7 @@ pub fn package(
|
||||
build_result: &BuildResult,
|
||||
cook_config: &CookConfig,
|
||||
logger: &PtyOut,
|
||||
) -> Result<(), String> {
|
||||
) -> Result<()> {
|
||||
let name = &recipe.name;
|
||||
let target_dir = &recipe.target_dir();
|
||||
let auto_deps = &build_result.auto_deps;
|
||||
@ -128,7 +128,7 @@ pub fn package_toml(
|
||||
package_suffix: Option<&OptionalPackageRecipe>,
|
||||
mut package_deps: Vec<PackageName>,
|
||||
auto_deps: &BTreeSet<PackageName>,
|
||||
) -> Result<(), String> {
|
||||
) -> Result<()> {
|
||||
for dep in auto_deps.iter() {
|
||||
if !package_deps.contains(dep) {
|
||||
package_deps.push(dep.clone());
|
||||
|
||||
@ -1,4 +1,3 @@
|
||||
use anyhow::Context;
|
||||
use pkg::{Package, PackageName};
|
||||
use std::fmt::Write as _;
|
||||
use std::{
|
||||
@ -8,6 +7,7 @@ use std::{
|
||||
};
|
||||
|
||||
use crate::recipe::CookRecipe;
|
||||
use crate::{Result, wrap_other_err};
|
||||
|
||||
pub enum WalkTreeEntry<'a> {
|
||||
Built(&'a PathBuf, u64),
|
||||
@ -25,7 +25,7 @@ pub fn display_tree_entry(
|
||||
visited: &mut HashSet<PackageName>,
|
||||
total_size: &mut u64,
|
||||
total_count: &mut u64,
|
||||
) -> anyhow::Result<()> {
|
||||
) -> Result<()> {
|
||||
walk_tree_entry(
|
||||
package_name,
|
||||
recipe_map,
|
||||
@ -48,8 +48,8 @@ pub fn walk_tree_entry(
|
||||
visited: &mut HashSet<PackageName>,
|
||||
total_size: &mut u64,
|
||||
total_count: &mut u64,
|
||||
op: fn(&PackageName, &str, bool, &WalkTreeEntry) -> anyhow::Result<bool>,
|
||||
) -> anyhow::Result<()> {
|
||||
op: fn(&PackageName, &str, bool, &WalkTreeEntry) -> Result<bool>,
|
||||
) -> Result<()> {
|
||||
let cook_recipe = match recipe_map.get(package_name) {
|
||||
Some(r) => r,
|
||||
None => {
|
||||
@ -97,7 +97,7 @@ pub fn walk_tree_entry(
|
||||
if let Ok(pkg_toml_str) = read_to_string(&pkg_toml) {
|
||||
// more accurate with auto deps
|
||||
pkg_meta = toml::from_str(&pkg_toml_str)
|
||||
.context(format!("Unable to parse {}", pkg_toml.display()))?;
|
||||
.map_err(|_| wrap_other_err!("Unable to parse {}", pkg_toml.display())())?;
|
||||
all_deps_set.extend(pkg_meta.depends.iter());
|
||||
}
|
||||
}
|
||||
@ -131,7 +131,7 @@ pub fn display_pkg_fn(
|
||||
prefix: &str,
|
||||
is_last: bool,
|
||||
entry: &WalkTreeEntry,
|
||||
) -> anyhow::Result<bool> {
|
||||
) -> Result<bool> {
|
||||
let size_str = match entry {
|
||||
WalkTreeEntry::Built(_path_buf, size) => format!("[{}]", format_size(*size)),
|
||||
WalkTreeEntry::NotBuilt => "(not built)".to_string(),
|
||||
|
||||
@ -9,7 +9,7 @@ use pkg::{PackageError, PackageName};
|
||||
use regex::Regex;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{WALK_DEPTH, cook::package as cook_package, staged_pkg};
|
||||
use crate::{WALK_DEPTH, bail_other_err, cook::package as cook_package, staged_pkg};
|
||||
|
||||
/// Specifies how to download the source for a recipe
|
||||
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
|
||||
@ -444,7 +444,7 @@ impl CookRecipe {
|
||||
self.dir.join("target").join(self.target)
|
||||
}
|
||||
|
||||
pub fn apply_filesystem_config(&mut self, rule: &str) -> Result<(), anyhow::Error> {
|
||||
pub fn apply_filesystem_config(&mut self, rule: &str) -> crate::Result<()> {
|
||||
match rule {
|
||||
// build from source as usual
|
||||
"source" => {}
|
||||
@ -463,8 +463,7 @@ impl CookRecipe {
|
||||
self.recipe.build.set_as_none();
|
||||
}
|
||||
rule => {
|
||||
anyhow::bail!(
|
||||
// Fail fast because we could risk losing local changes if "local" was typo'ed
|
||||
bail_other_err!(
|
||||
"Invalid pkg config {} = \"{}\"\nExpecting either 'source', 'local', 'binary' or 'ignore'",
|
||||
self.name.as_str(),
|
||||
rule
|
||||
|
||||
Loading…
Reference in New Issue
Block a user