mirror of
https://gitlab.redox-os.org/redox-os/redox.git
synced 2026-06-23 05:14:18 +08:00
Now mostly usable
This commit is contained in:
parent
0bad6d1562
commit
ff3cd11099
53
Cargo.lock
generated
53
Cargo.lock
generated
@ -444,7 +444,7 @@ dependencies = [
|
||||
"js-sys",
|
||||
"num-traits",
|
||||
"wasm-bindgen",
|
||||
"windows-link 0.1.3",
|
||||
"windows-link",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -611,17 +611,6 @@ dependencies = [
|
||||
"subtle",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ctrlc"
|
||||
version = "3.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "881c5d0a13b2f1498e2306e82cbada78390e152d4b1378fb28a84f4dcd0dc4f3"
|
||||
dependencies = [
|
||||
"dispatch",
|
||||
"nix",
|
||||
"windows-sys 0.61.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "curve25519-dalek"
|
||||
version = "4.1.3"
|
||||
@ -753,12 +742,6 @@ dependencies = [
|
||||
"windows-sys 0.60.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dispatch"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bd0c93bb4b0c6d9b77f4435b0ae98c24d17f1c45b2ff844c6151a07256ca923b"
|
||||
|
||||
[[package]]
|
||||
name = "displaydoc"
|
||||
version = "0.2.5"
|
||||
@ -1554,18 +1537,6 @@ dependencies = [
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nix"
|
||||
version = "0.30.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "74523f3a35e05aba87a1d978330aef40f67b0304ac79c1c00b294c9830543db6"
|
||||
dependencies = [
|
||||
"bitflags 2.9.1",
|
||||
"cfg-if 1.0.1",
|
||||
"cfg_aliases",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-conv"
|
||||
version = "0.1.0"
|
||||
@ -2036,7 +2007,6 @@ version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"blake3 1.5.3",
|
||||
"ctrlc",
|
||||
"ignore",
|
||||
"object",
|
||||
"pbr",
|
||||
@ -3194,7 +3164,7 @@ checksum = "c0fdd3ddb90610c7638aa2b3a3ab2904fb9e5cdbecc643ddb3647212781c4ae3"
|
||||
dependencies = [
|
||||
"windows-implement",
|
||||
"windows-interface",
|
||||
"windows-link 0.1.3",
|
||||
"windows-link",
|
||||
"windows-result",
|
||||
"windows-strings",
|
||||
]
|
||||
@ -3227,19 +3197,13 @@ version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a"
|
||||
|
||||
[[package]]
|
||||
name = "windows-link"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
|
||||
|
||||
[[package]]
|
||||
name = "windows-result"
|
||||
version = "0.3.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6"
|
||||
dependencies = [
|
||||
"windows-link 0.1.3",
|
||||
"windows-link",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -3248,7 +3212,7 @@ version = "0.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57"
|
||||
dependencies = [
|
||||
"windows-link 0.1.3",
|
||||
"windows-link",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -3287,15 +3251,6 @@ dependencies = [
|
||||
"windows-targets 0.53.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.61.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc"
|
||||
dependencies = [
|
||||
"windows-link 0.2.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-targets"
|
||||
version = "0.42.2"
|
||||
|
||||
@ -3,7 +3,7 @@ name = "redox_cookbook"
|
||||
version = "0.1.0"
|
||||
authors = ["Jeremy Soller <jackpot51@gmail.com>"]
|
||||
edition = "2024"
|
||||
default-run = "cook"
|
||||
default-run = "repo"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
@ -23,7 +23,6 @@ doctest = false
|
||||
[dependencies]
|
||||
anyhow = "1"
|
||||
blake3 = "=1.5.3" # 1.5.4 is incompatible with blake3 0.3 dependency from pkgar
|
||||
ctrlc = { version = "3.5.0", features = ["termination"] }
|
||||
ignore = "0.4"
|
||||
object = { version = "0.36", features = ["build_core"] }
|
||||
pbr = "1.0.2"
|
||||
|
||||
10
clean.sh
10
clean.sh
@ -5,15 +5,9 @@ source config.sh
|
||||
|
||||
if [ $# = 0 ]
|
||||
then
|
||||
recipes="$(list_recipes --short)"
|
||||
recipes="--all"
|
||||
else
|
||||
recipes="$@"
|
||||
fi
|
||||
|
||||
for recipe_name in $recipes
|
||||
do
|
||||
recipe_path=`find_recipe $recipe_name`
|
||||
|
||||
echo -e "\033[01;38;5;215mcook - clean $recipe_name\033[0m"
|
||||
rm -rf "${ROOT}/$recipe_path/target/${TARGET}"
|
||||
done
|
||||
repo clean $recipes
|
||||
|
||||
559
src/bin/repo.rs
559
src/bin/repo.rs
@ -1,8 +1,9 @@
|
||||
use std::collections::HashMap;
|
||||
use std::io::{BufRead, BufReader, PipeReader, stdout};
|
||||
use std::collections::{HashMap, VecDeque};
|
||||
use std::io::{BufRead, BufReader, PipeReader, Write, stderr, stdin, stdout};
|
||||
use std::path::PathBuf;
|
||||
use std::process::Command;
|
||||
use std::str::FromStr;
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use std::sync::atomic::{AtomicBool, AtomicU32, Ordering};
|
||||
use std::sync::{Arc, mpsc};
|
||||
use std::time::Duration;
|
||||
use std::{env, fs};
|
||||
@ -22,11 +23,13 @@ use ratatui::Terminal;
|
||||
use ratatui::layout::{Constraint, Direction, Layout, Position, Rect};
|
||||
use ratatui::prelude::TermionBackend;
|
||||
use ratatui::style::{Color, Style};
|
||||
use ratatui::widgets::{Block, Borders, List, ListItem, Paragraph, Wrap};
|
||||
use ratatui::text::{Line, Span};
|
||||
use ratatui::widgets::{Block, Borders, Clear, List, ListItem, Paragraph, Wrap};
|
||||
use termion::event::{Event, Key, MouseEvent};
|
||||
use termion::input::{MouseTerminal, TermRead};
|
||||
use termion::raw::RawTerminal;
|
||||
use termion::screen::{AlternateScreen, ToAlternateScreen, ToMainScreen};
|
||||
use termion::input::TermRead;
|
||||
use termion::raw::IntoRawMode;
|
||||
use termion::screen::IntoAlternateScreen;
|
||||
use termion::{color, style};
|
||||
|
||||
// A repo manager, to replace repo.sh
|
||||
|
||||
@ -125,7 +128,10 @@ impl CliConfig {
|
||||
|
||||
fn main() {
|
||||
init_config();
|
||||
main_inner().unwrap();
|
||||
if let Err(e) = main_inner() {
|
||||
eprintln!("{:?}", e);
|
||||
process::exit(1);
|
||||
};
|
||||
}
|
||||
|
||||
fn main_inner() -> anyhow::Result<()> {
|
||||
@ -139,7 +145,19 @@ fn main_inner() -> anyhow::Result<()> {
|
||||
let (config, command, recipe_names) = parse_args(args)?;
|
||||
|
||||
if command == CliCommand::Cook && config.cook.tui {
|
||||
run_tui_cook(config, recipe_names)?;
|
||||
if let Some(e) = run_tui_cook(config, recipe_names)? {
|
||||
let _ = stderr().write(e.as_bytes());
|
||||
let _ = stderr().write(b"\n\n");
|
||||
return Err(anyhow!("Execution has failed"));
|
||||
} else {
|
||||
eprintln!(
|
||||
"{}{}cook - successful{}{}",
|
||||
style::Bold,
|
||||
color::Fg(color::AnsiValue(215)),
|
||||
color::Fg(color::Reset),
|
||||
style::Reset,
|
||||
);
|
||||
}
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
@ -343,27 +361,32 @@ enum RecipeStatus {
|
||||
#[derive(Debug, Clone)]
|
||||
enum StatusUpdate {
|
||||
StartFetch(PackageName),
|
||||
Fetched(PackageName),
|
||||
FailFetch(PackageName, String),
|
||||
Fetched(CookRecipe),
|
||||
FailFetch(CookRecipe, String),
|
||||
StartCook(PackageName),
|
||||
CookLog(PackageName, String),
|
||||
Cooked(PackageName),
|
||||
FailCook(PackageName, String),
|
||||
Cooked(CookRecipe),
|
||||
FailCook(CookRecipe, String),
|
||||
PushLog(PackageName, String),
|
||||
FetchThreadFinished,
|
||||
CookThreadFinished,
|
||||
}
|
||||
|
||||
#[derive(PartialEq)]
|
||||
enum JobType {
|
||||
Fetch,
|
||||
Cook,
|
||||
}
|
||||
|
||||
struct TuiApp {
|
||||
recipes: Vec<(CookRecipe, RecipeStatus)>,
|
||||
fetch_queue: Vec<PackageName>,
|
||||
cook_queue: Vec<PackageName>,
|
||||
fetch_queue: VecDeque<CookRecipe>,
|
||||
cook_queue: VecDeque<CookRecipe>,
|
||||
done: Vec<PackageName>,
|
||||
failed: Vec<PackageName>,
|
||||
active_fetch: Option<PackageName>,
|
||||
active_cook: Option<PackageName>,
|
||||
logs: HashMap<PackageName, Vec<String>>,
|
||||
log_scroll: u16,
|
||||
log_view_cook: bool,
|
||||
log_view_job: JobType,
|
||||
auto_scroll: bool,
|
||||
fetch_scroll: u16,
|
||||
cook_scroll: u16,
|
||||
@ -372,26 +395,27 @@ struct TuiApp {
|
||||
fetch_panel_rect: Option<Rect>,
|
||||
cook_panel_rect: Option<Rect>,
|
||||
log_panel_rect: Option<Rect>,
|
||||
prompt: Option<FailurePrompt>,
|
||||
dump_logs_on_exit: Option<String>,
|
||||
}
|
||||
|
||||
impl TuiApp {
|
||||
fn new(recipes: Vec<CookRecipe>) -> Self {
|
||||
let recipe_names = recipes.iter().map(|r| r.name.clone()).collect();
|
||||
Self {
|
||||
recipes: recipes
|
||||
.into_iter()
|
||||
.iter()
|
||||
.cloned()
|
||||
.map(|r| (r, RecipeStatus::Pending))
|
||||
.collect(),
|
||||
fetch_queue: recipe_names,
|
||||
cook_queue: Vec::new(),
|
||||
fetch_queue: recipes.iter().cloned().map(|r| r.clone()).collect(),
|
||||
cook_queue: VecDeque::new(),
|
||||
done: Vec::new(),
|
||||
failed: Vec::new(),
|
||||
active_fetch: None,
|
||||
active_cook: None,
|
||||
logs: HashMap::new(),
|
||||
log_scroll: 0,
|
||||
auto_scroll: true,
|
||||
log_view_cook: false,
|
||||
log_view_job: JobType::Fetch,
|
||||
fetch_scroll: 0,
|
||||
cook_scroll: 0,
|
||||
fetch_complete: false,
|
||||
@ -399,6 +423,8 @@ impl TuiApp {
|
||||
fetch_panel_rect: None,
|
||||
cook_panel_rect: None,
|
||||
log_panel_rect: None,
|
||||
prompt: None,
|
||||
dump_logs_on_exit: None,
|
||||
}
|
||||
}
|
||||
|
||||
@ -412,14 +438,17 @@ impl TuiApp {
|
||||
self.auto_scroll = true;
|
||||
(name.clone(), RecipeStatus::Fetching)
|
||||
}
|
||||
StatusUpdate::Fetched(name) => (name, RecipeStatus::Fetched),
|
||||
StatusUpdate::FailFetch(name, err) => (name, RecipeStatus::Failed(err)),
|
||||
StatusUpdate::Fetched(recipe) => (recipe.name.clone(), RecipeStatus::Fetched),
|
||||
StatusUpdate::FailFetch(recipe, err) => {
|
||||
self.prompt = Some(FailurePrompt::new(recipe.clone(), err.clone()));
|
||||
(recipe.name.clone(), RecipeStatus::Failed(err))
|
||||
}
|
||||
StatusUpdate::StartCook(name) => {
|
||||
self.active_cook = Some(name.clone());
|
||||
self.logs.insert(name.clone(), Vec::new());
|
||||
(name.clone(), RecipeStatus::Cooking)
|
||||
}
|
||||
StatusUpdate::CookLog(name, line) => {
|
||||
StatusUpdate::PushLog(name, line) => {
|
||||
self.logs.entry(name.clone()).or_default().push(line);
|
||||
// No status change, just return the current state
|
||||
if let Some((_, status)) = self.recipes.iter().find(|(r, _)| r.name == name) {
|
||||
@ -428,23 +457,21 @@ impl TuiApp {
|
||||
return; // Should not happen
|
||||
}
|
||||
}
|
||||
StatusUpdate::Cooked(name) => {
|
||||
if self.active_cook.as_ref() == Some(&name) {
|
||||
StatusUpdate::Cooked(recipe) => {
|
||||
if self.active_cook.as_ref() == Some(&recipe.name) {
|
||||
self.active_cook = None;
|
||||
}
|
||||
self.auto_scroll = true;
|
||||
(name.clone(), RecipeStatus::Done)
|
||||
(recipe.name.clone(), RecipeStatus::Done)
|
||||
}
|
||||
StatusUpdate::FailCook(name, err) => {
|
||||
if self.active_cook.as_ref() == Some(&name) {
|
||||
self.active_cook = None;
|
||||
}
|
||||
self.auto_scroll = false;
|
||||
(name.clone(), RecipeStatus::Failed(err))
|
||||
StatusUpdate::FailCook(recipe, err) => {
|
||||
self.prompt = Some(FailurePrompt::new(recipe.clone(), err.clone()));
|
||||
|
||||
(recipe.name.clone(), RecipeStatus::Failed(err))
|
||||
}
|
||||
StatusUpdate::FetchThreadFinished => {
|
||||
self.fetch_complete = true;
|
||||
self.log_view_cook = true;
|
||||
self.log_view_job = JobType::Cook;
|
||||
return;
|
||||
}
|
||||
StatusUpdate::CookThreadFinished => {
|
||||
@ -461,14 +488,14 @@ impl TuiApp {
|
||||
self.fetch_queue = self
|
||||
.recipes
|
||||
.iter()
|
||||
.filter(|(_, s)| *s == RecipeStatus::Pending || *s == RecipeStatus::Fetching)
|
||||
.map(|(r, _)| r.name.clone())
|
||||
.filter(|(_, s)| *s == RecipeStatus::Pending)
|
||||
.map(|(r, _)| r.clone())
|
||||
.collect();
|
||||
self.cook_queue = self
|
||||
.recipes
|
||||
.iter()
|
||||
.filter(|(_, s)| *s == RecipeStatus::Fetched || *s == RecipeStatus::Cooking)
|
||||
.map(|(r, _)| r.name.clone())
|
||||
.filter(|(_, s)| *s == RecipeStatus::Fetched)
|
||||
.map(|(r, _)| (r.clone()))
|
||||
.collect();
|
||||
self.done = self
|
||||
.recipes
|
||||
@ -476,24 +503,22 @@ impl TuiApp {
|
||||
.filter(|(_, s)| *s == RecipeStatus::Done)
|
||||
.map(|(r, _)| r.name.clone())
|
||||
.collect();
|
||||
self.failed = self
|
||||
.recipes
|
||||
.iter()
|
||||
.filter(|(_, s)| matches!(s, RecipeStatus::Failed(_)))
|
||||
.map(|(r, _)| r.name.clone())
|
||||
.collect();
|
||||
}
|
||||
}
|
||||
|
||||
fn run_tui_cook(config: CliConfig, recipes: Vec<CookRecipe>) -> anyhow::Result<()> {
|
||||
fn run_tui_cook(config: CliConfig, recipes: Vec<CookRecipe>) -> anyhow::Result<Option<String>> {
|
||||
let (work_tx, work_rx) = mpsc::channel::<(CookRecipe, PathBuf)>();
|
||||
let (status_tx, status_rx) = mpsc::channel::<StatusUpdate>();
|
||||
|
||||
let running = Arc::new(AtomicBool::new(true));
|
||||
let prompting = Arc::new(AtomicU32::new(0));
|
||||
|
||||
// ---- Cooker Thread ----
|
||||
let cooker_config = config.clone();
|
||||
let cooker_status_tx = status_tx.clone();
|
||||
let cooker_prompting = prompting.clone();
|
||||
let cooker_handle = thread::spawn(move || {
|
||||
for (recipe, source_dir) in work_rx {
|
||||
'done: for (recipe, source_dir) in work_rx {
|
||||
let name = recipe.name.clone();
|
||||
let is_deps = recipe.is_deps;
|
||||
cooker_status_tx
|
||||
@ -501,11 +526,51 @@ fn run_tui_cook(config: CliConfig, recipes: Vec<CookRecipe>) -> anyhow::Result<(
|
||||
.unwrap();
|
||||
let (mut stdout_writer, mut stderr_writer) = setup_logger(&cooker_status_tx, &name);
|
||||
let logger = Some((&mut stdout_writer, &mut stderr_writer));
|
||||
match handle_cook(&recipe, &cooker_config, source_dir, is_deps, &logger) {
|
||||
Ok(_) => cooker_status_tx.send(StatusUpdate::Cooked(name)).unwrap(),
|
||||
Err(e) => cooker_status_tx
|
||||
.send(StatusUpdate::FailCook(name, e.to_string()))
|
||||
.unwrap(),
|
||||
'again: loop {
|
||||
match handle_cook(
|
||||
&recipe,
|
||||
&cooker_config,
|
||||
source_dir.clone(),
|
||||
is_deps,
|
||||
&logger,
|
||||
) {
|
||||
Ok(()) => {
|
||||
cooker_status_tx
|
||||
.send(StatusUpdate::Cooked(recipe))
|
||||
.unwrap_or_default();
|
||||
break;
|
||||
}
|
||||
Err(e) => {
|
||||
cooker_status_tx
|
||||
.send(StatusUpdate::FailCook(recipe.clone(), e.to_string()))
|
||||
.unwrap_or_default();
|
||||
if !cooker_config.cook.nonstop {
|
||||
while cooker_prompting.load(Ordering::SeqCst) != 0 {
|
||||
thread::sleep(Duration::from_millis(101)); // wait other prompt
|
||||
}
|
||||
cooker_prompting.swap(1, Ordering::SeqCst);
|
||||
'wait: loop {
|
||||
match cooker_prompting.load(Ordering::SeqCst) {
|
||||
0 => break 'again,
|
||||
1 => thread::sleep(Duration::from_millis(101)),
|
||||
2 => {
|
||||
cooker_prompting.swap(0, Ordering::SeqCst);
|
||||
break 'wait;
|
||||
} // retry
|
||||
3 => {
|
||||
cooker_prompting.swap(0, Ordering::SeqCst);
|
||||
break 'again;
|
||||
} // skip
|
||||
4 => {
|
||||
cooker_prompting.swap(0, Ordering::SeqCst);
|
||||
break 'done;
|
||||
} // done
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
cooker_status_tx
|
||||
@ -513,11 +578,17 @@ fn run_tui_cook(config: CliConfig, recipes: Vec<CookRecipe>) -> anyhow::Result<(
|
||||
.unwrap_or_default();
|
||||
});
|
||||
|
||||
let mstdin = stdin();
|
||||
let mstdout = stdout()
|
||||
.into_raw_mode()
|
||||
.unwrap()
|
||||
.into_alternate_screen()
|
||||
.unwrap();
|
||||
|
||||
// ----- Input Thread -----
|
||||
let (input_tx, input_rx) = mpsc::channel::<Event>();
|
||||
let _input_handle = thread::spawn(move || {
|
||||
let stdin = std::io::stdin();
|
||||
for evt in stdin.events() {
|
||||
for evt in mstdin.events() {
|
||||
if let Ok(evt) = evt {
|
||||
if input_tx.send(evt).is_err() {
|
||||
return;
|
||||
@ -528,28 +599,62 @@ fn run_tui_cook(config: CliConfig, recipes: Vec<CookRecipe>) -> anyhow::Result<(
|
||||
|
||||
// ---- Fetcher Thread ----
|
||||
let fetcher_recipes = recipes.clone();
|
||||
let fetcher_status_tx = status_tx.clone();
|
||||
let fetcher_config = config.clone();
|
||||
let fetcher_prompting = prompting.clone();
|
||||
let fetcher_handle = thread::spawn(move || {
|
||||
for recipe in fetcher_recipes {
|
||||
'done: for recipe in fetcher_recipes {
|
||||
let name = recipe.name.clone();
|
||||
status_tx
|
||||
fetcher_status_tx
|
||||
.send(StatusUpdate::StartFetch(name.clone()))
|
||||
.unwrap();
|
||||
|
||||
let (mut stdout_writer, mut stderr_writer) = setup_logger(&status_tx, &name);
|
||||
let (mut stdout_writer, mut stderr_writer) = setup_logger(&fetcher_status_tx, &name);
|
||||
let logger = Some((&mut stdout_writer, &mut stderr_writer));
|
||||
|
||||
match handle_fetch(&recipe, &fetcher_config, &logger) {
|
||||
Ok(source_dir) => {
|
||||
status_tx.send(StatusUpdate::Fetched(name)).unwrap();
|
||||
if work_tx.send((recipe.clone(), source_dir)).is_err() {
|
||||
// Cooker thread died
|
||||
'again: loop {
|
||||
match handle_fetch(&recipe, &fetcher_config, &logger) {
|
||||
Ok(source_dir) => {
|
||||
fetcher_status_tx
|
||||
.send(StatusUpdate::Fetched(recipe.clone()))
|
||||
.unwrap();
|
||||
if work_tx.send((recipe.clone(), source_dir)).is_err() {
|
||||
// Cooker thread died
|
||||
break 'done;
|
||||
}
|
||||
break;
|
||||
}
|
||||
Err(e) => {
|
||||
fetcher_status_tx
|
||||
.send(StatusUpdate::FailFetch(recipe.clone(), e.to_string()))
|
||||
.unwrap_or_default();
|
||||
if !fetcher_config.cook.nonstop {
|
||||
while fetcher_prompting.load(Ordering::SeqCst) != 0 {
|
||||
thread::sleep(Duration::from_millis(101)); // wait other prompt
|
||||
}
|
||||
fetcher_prompting.swap(1, Ordering::SeqCst);
|
||||
'wait: loop {
|
||||
match fetcher_prompting.load(Ordering::SeqCst) {
|
||||
0 => break 'again,
|
||||
1 => thread::sleep(Duration::from_millis(101)),
|
||||
2 => {
|
||||
fetcher_prompting.swap(0, Ordering::SeqCst);
|
||||
break 'wait;
|
||||
} // retry
|
||||
3 => {
|
||||
fetcher_prompting.swap(0, Ordering::SeqCst);
|
||||
break 'again;
|
||||
} // skip
|
||||
4 => {
|
||||
fetcher_prompting.swap(0, Ordering::SeqCst);
|
||||
break 'done;
|
||||
} // done
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(e) => status_tx
|
||||
.send(StatusUpdate::FailFetch(name, e.to_string()))
|
||||
.unwrap(),
|
||||
}
|
||||
}
|
||||
status_tx
|
||||
@ -557,28 +662,19 @@ fn run_tui_cook(config: CliConfig, recipes: Vec<CookRecipe>) -> anyhow::Result<(
|
||||
.unwrap_or_default();
|
||||
});
|
||||
|
||||
print!("{}", ToAlternateScreen);
|
||||
let mut terminal = Terminal::new(TermionBackend::new(stdout()))?;
|
||||
terminal.clear()?;
|
||||
|
||||
let mut app = TuiApp::new(recipes);
|
||||
// let total_recipes = app.recipes.len();
|
||||
let running = Arc::new(AtomicBool::new(true));
|
||||
|
||||
ctrlc::set_handler(move || {
|
||||
print!("{}", ToMainScreen);
|
||||
process::exit(1);
|
||||
})
|
||||
.context("Error setting Ctrl-C handler")?;
|
||||
|
||||
while running.load(Ordering::Relaxed) {
|
||||
while running.load(Ordering::SeqCst) {
|
||||
terminal.draw(|f| {
|
||||
let mut constraints = Vec::new();
|
||||
if !app.fetch_complete {
|
||||
constraints.push(Constraint::Length(30));
|
||||
}
|
||||
constraints.push(Constraint::Length(30));
|
||||
constraints.push(Constraint::Min(20)); // Log panel always exists
|
||||
constraints.push(Constraint::Min(20));
|
||||
let chunks = Layout::default()
|
||||
.direction(Direction::Horizontal)
|
||||
.constraints(constraints)
|
||||
@ -633,7 +729,7 @@ fn run_tui_cook(config: CliConfig, recipes: Vec<CookRecipe>) -> anyhow::Result<(
|
||||
);
|
||||
f.render_widget(cook_list, chunks[if app.fetch_complete { 0 } else { 1 }]);
|
||||
|
||||
let active_name = if app.log_view_cook {
|
||||
let active_name = if app.log_view_job == JobType::Cook {
|
||||
&app.active_cook
|
||||
} else {
|
||||
&app.active_fetch
|
||||
@ -667,8 +763,9 @@ fn run_tui_cook(config: CliConfig, recipes: Vec<CookRecipe>) -> anyhow::Result<(
|
||||
}
|
||||
} else {
|
||||
if total_log_lines > log_pane_height {
|
||||
if app.log_scroll > total_log_lines - log_pane_height {
|
||||
if app.log_scroll >= total_log_lines - log_pane_height {
|
||||
app.log_scroll = total_log_lines - log_pane_height;
|
||||
app.auto_scroll = true;
|
||||
}
|
||||
} else {
|
||||
app.log_scroll = 0;
|
||||
@ -685,66 +782,21 @@ fn run_tui_cook(config: CliConfig, recipes: Vec<CookRecipe>) -> anyhow::Result<(
|
||||
chunks[if app.fetch_complete { 1 } else { 2 }],
|
||||
);
|
||||
|
||||
if let Some(prompt) = &app.prompt {
|
||||
draw_prompt(f, prompt);
|
||||
}
|
||||
|
||||
while let Ok(event) = input_rx.try_recv() {
|
||||
match event {
|
||||
Event::Key(key) => match key {
|
||||
Key::Char('\t') => {
|
||||
app.log_view_cook = !app.log_view_cook;
|
||||
}
|
||||
Key::Char('1') => {
|
||||
app.log_view_cook = false;
|
||||
}
|
||||
Key::Char('2') => {
|
||||
app.log_view_cook = true;
|
||||
}
|
||||
Key::Up => {
|
||||
app.auto_scroll = false;
|
||||
app.log_scroll = app.log_scroll.saturating_sub(1);
|
||||
}
|
||||
Key::Down => {
|
||||
app.auto_scroll = false;
|
||||
app.log_scroll = app.log_scroll.saturating_add(1);
|
||||
}
|
||||
_ => {}
|
||||
},
|
||||
|
||||
Event::Mouse(mouse_event) => {
|
||||
match mouse_event {
|
||||
MouseEvent::Press(termion::event::MouseButton::WheelUp, x, y) => {
|
||||
// termion is 1-based, ratatui rects are 0-based
|
||||
let pos = Position {
|
||||
x: x.saturating_sub(1),
|
||||
y: y.saturating_sub(1),
|
||||
};
|
||||
|
||||
if app.fetch_panel_rect.map_or(false, |r| r.contains(pos)) {
|
||||
app.fetch_scroll = app.fetch_scroll.saturating_sub(1);
|
||||
} else if app.cook_panel_rect.map_or(false, |r| r.contains(pos)) {
|
||||
app.cook_scroll = app.cook_scroll.saturating_sub(1);
|
||||
} else if app.log_panel_rect.map_or(false, |r| r.contains(pos)) {
|
||||
app.auto_scroll = false;
|
||||
app.log_scroll = app.log_scroll.saturating_sub(1);
|
||||
}
|
||||
}
|
||||
MouseEvent::Press(termion::event::MouseButton::WheelDown, x, y) => {
|
||||
let pos = Position {
|
||||
x: x.saturating_sub(1),
|
||||
y: y.saturating_sub(1),
|
||||
};
|
||||
|
||||
if app.fetch_panel_rect.map_or(false, |r| r.contains(pos)) {
|
||||
app.fetch_scroll = app.fetch_scroll.saturating_add(1);
|
||||
} else if app.cook_panel_rect.map_or(false, |r| r.contains(pos)) {
|
||||
app.cook_scroll = app.cook_scroll.saturating_add(1);
|
||||
} else if app.log_panel_rect.map_or(false, |r| r.contains(pos)) {
|
||||
app.auto_scroll = false;
|
||||
app.log_scroll = app.log_scroll.saturating_add(1);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
if app.prompt.is_some() {
|
||||
if let Some(res) = handle_prompt_input(event, &mut app, &running) {
|
||||
prompting.swap(res as u32, Ordering::SeqCst);
|
||||
if res == PromptOption::Exit {
|
||||
app.dump_logs_on_exit = Some(log_text.join("\n"))
|
||||
}
|
||||
app.prompt = None;
|
||||
}
|
||||
_ => {}
|
||||
} else {
|
||||
handle_main_event(&mut app, event);
|
||||
}
|
||||
}
|
||||
})?;
|
||||
@ -753,19 +805,194 @@ fn run_tui_cook(config: CliConfig, recipes: Vec<CookRecipe>) -> anyhow::Result<(
|
||||
app.update_status(update);
|
||||
}
|
||||
|
||||
if fetcher_handle.is_finished() && cooker_handle.is_finished() {
|
||||
thread::sleep(Duration::from_secs(5));
|
||||
if app.cook_complete {
|
||||
running.swap(false, Ordering::SeqCst);
|
||||
}
|
||||
}
|
||||
|
||||
// disable_raw_mode()?;
|
||||
print!("{}", ToMainScreen);
|
||||
drop(mstdout);
|
||||
let _ = stdout().flush();
|
||||
|
||||
fetcher_handle.join().unwrap();
|
||||
cooker_handle.join().unwrap();
|
||||
|
||||
Ok(())
|
||||
Ok(app.dump_logs_on_exit)
|
||||
}
|
||||
|
||||
fn handle_main_event(app: &mut TuiApp, event: Event) {
|
||||
match event {
|
||||
Event::Key(key) => match key {
|
||||
Key::Char('1') => {
|
||||
app.log_view_job = JobType::Fetch;
|
||||
}
|
||||
Key::Char('2') => {
|
||||
app.log_view_job = JobType::Cook;
|
||||
}
|
||||
Key::Char('c') => {
|
||||
// as compilers still running, we use this way to stop it
|
||||
let pid = std::process::id();
|
||||
Command::new("pkill")
|
||||
.arg("-9")
|
||||
.arg("-P")
|
||||
.arg(pid.to_string())
|
||||
.spawn()
|
||||
.expect("unable to spawn pkill");
|
||||
}
|
||||
Key::Up => {
|
||||
app.auto_scroll = false;
|
||||
app.log_scroll = app.log_scroll.saturating_sub(1);
|
||||
}
|
||||
Key::Down => {
|
||||
app.auto_scroll = false;
|
||||
app.log_scroll = app.log_scroll.saturating_add(1);
|
||||
}
|
||||
Key::PageUp => {
|
||||
app.auto_scroll = false;
|
||||
app.log_scroll = app.log_scroll.saturating_sub(20);
|
||||
}
|
||||
Key::PageDown => {
|
||||
app.auto_scroll = false;
|
||||
app.log_scroll = app.log_scroll.saturating_add(20);
|
||||
}
|
||||
Key::End => {
|
||||
app.auto_scroll = true;
|
||||
}
|
||||
Key::Home => {
|
||||
app.auto_scroll = false;
|
||||
app.log_scroll = 0;
|
||||
}
|
||||
_ => {}
|
||||
},
|
||||
|
||||
Event::Mouse(mouse_event) => {
|
||||
match mouse_event {
|
||||
MouseEvent::Press(termion::event::MouseButton::WheelUp, x, y) => {
|
||||
// termion is 1-based, ratatui rects are 0-based
|
||||
let pos = Position {
|
||||
x: x.saturating_sub(1),
|
||||
y: y.saturating_sub(1),
|
||||
};
|
||||
|
||||
if app.fetch_panel_rect.map_or(false, |r| r.contains(pos)) {
|
||||
app.fetch_scroll = app.fetch_scroll.saturating_sub(1);
|
||||
} else if app.cook_panel_rect.map_or(false, |r| r.contains(pos)) {
|
||||
app.cook_scroll = app.cook_scroll.saturating_sub(1);
|
||||
} else if app.log_panel_rect.map_or(false, |r| r.contains(pos)) {
|
||||
app.auto_scroll = false;
|
||||
app.log_scroll = app.log_scroll.saturating_sub(1);
|
||||
}
|
||||
}
|
||||
MouseEvent::Press(termion::event::MouseButton::WheelDown, x, y) => {
|
||||
let pos = Position {
|
||||
x: x.saturating_sub(1),
|
||||
y: y.saturating_sub(1),
|
||||
};
|
||||
|
||||
if app.fetch_panel_rect.map_or(false, |r| r.contains(pos)) {
|
||||
app.fetch_scroll = app.fetch_scroll.saturating_add(1);
|
||||
} else if app.cook_panel_rect.map_or(false, |r| r.contains(pos)) {
|
||||
app.cook_scroll = app.cook_scroll.saturating_add(1);
|
||||
} else if app.log_panel_rect.map_or(false, |r| r.contains(pos)) {
|
||||
app.auto_scroll = false;
|
||||
app.log_scroll = app.log_scroll.saturating_add(1);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_prompt_input(
|
||||
event: Event,
|
||||
app: &mut TuiApp,
|
||||
running: &Arc<AtomicBool>,
|
||||
) -> Option<PromptOption> {
|
||||
if let Some(prompt) = &mut app.prompt {
|
||||
match event {
|
||||
Event::Key(key) => match key {
|
||||
Key::Char('q') | Key::Ctrl('c') | Key::Esc => {
|
||||
// Treat as "Exit"
|
||||
running.store(false, Ordering::SeqCst);
|
||||
return Some(PromptOption::Exit);
|
||||
}
|
||||
Key::Left | Key::BackTab => prompt.prev(),
|
||||
Key::Right | Key::Char('\t') => prompt.next(),
|
||||
Key::Char('\n') => {
|
||||
let prompt = app.prompt.take().unwrap();
|
||||
if prompt.selected == PromptOption::Exit {
|
||||
running.store(false, Ordering::SeqCst);
|
||||
}
|
||||
return Some(prompt.selected);
|
||||
}
|
||||
_ => {}
|
||||
},
|
||||
_ => {} // Ignore mouse events
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
fn draw_prompt(f: &mut ratatui::Frame, prompt: &FailurePrompt) {
|
||||
let title = format!(" FAILURE in {} ", prompt.recipe.name);
|
||||
let mut error_text = prompt.error.clone();
|
||||
if error_text.len() > 100 {
|
||||
error_text = error_text[0..100].to_string() + "..";
|
||||
}
|
||||
|
||||
// Style for options
|
||||
let retry_style = if prompt.selected == PromptOption::Retry {
|
||||
Style::default().bg(Color::White).fg(Color::Black)
|
||||
} else {
|
||||
Style::default()
|
||||
};
|
||||
let skip_style = if prompt.selected == PromptOption::Skip {
|
||||
Style::default().bg(Color::White).fg(Color::Black)
|
||||
} else {
|
||||
Style::default()
|
||||
};
|
||||
let exit_style = if prompt.selected == PromptOption::Exit {
|
||||
Style::default().bg(Color::White).fg(Color::Black)
|
||||
} else {
|
||||
Style::default()
|
||||
};
|
||||
|
||||
let text = vec![
|
||||
Line::from(error_text).style(Style::default().fg(Color::Yellow)),
|
||||
Line::from(""),
|
||||
Line::from(vec![
|
||||
Span::styled(" [Retry] ", retry_style),
|
||||
Span::raw(" "),
|
||||
Span::styled(" [Skip] ", skip_style),
|
||||
Span::raw(" "),
|
||||
Span::styled(" [Exit] ", exit_style),
|
||||
]),
|
||||
];
|
||||
|
||||
let block = Block::default()
|
||||
.title(Span::styled(
|
||||
title,
|
||||
Style::default().fg(Color::White).bg(Color::Red),
|
||||
))
|
||||
.borders(Borders::ALL)
|
||||
.border_style(Style::default().fg(Color::Red));
|
||||
|
||||
let paragraph = Paragraph::new(text)
|
||||
.block(block)
|
||||
.alignment(ratatui::layout::Alignment::Center)
|
||||
.wrap(Wrap { trim: true });
|
||||
|
||||
let area = f.area();
|
||||
let popup_area = Rect {
|
||||
x: area.width / 4,
|
||||
y: area.height / 3,
|
||||
width: area.width / 2,
|
||||
height: 10,
|
||||
};
|
||||
|
||||
f.render_widget(Clear, popup_area); // Clear the background
|
||||
f.render_widget(paragraph, popup_area);
|
||||
}
|
||||
|
||||
fn spawn_log_reader(
|
||||
@ -778,7 +1005,7 @@ fn spawn_log_reader(
|
||||
for line in reader.lines() {
|
||||
let line_str = line.unwrap_or_else(|e| format!("[IO Error] {}", e));
|
||||
if status_tx
|
||||
.send(StatusUpdate::CookLog(package_name.clone(), line_str))
|
||||
.send(StatusUpdate::PushLog(package_name.clone(), line_str))
|
||||
.is_err()
|
||||
{
|
||||
// TUI thread hung up
|
||||
@ -789,12 +1016,52 @@ fn spawn_log_reader(
|
||||
}
|
||||
|
||||
fn setup_logger(
|
||||
cooker_status_tx: &mpsc::Sender<StatusUpdate>,
|
||||
status_tx: &mpsc::Sender<StatusUpdate>,
|
||||
name: &PackageName,
|
||||
) -> (std::io::PipeWriter, std::io::PipeWriter) {
|
||||
let (stdout_reader, stdout_writer) = std::io::pipe().expect("Failed to create stdout pipe");
|
||||
let (stderr_reader, stderr_writer) = std::io::pipe().expect("Failed to create stderr pipe");
|
||||
spawn_log_reader(stdout_reader, name.clone(), cooker_status_tx.clone());
|
||||
spawn_log_reader(stderr_reader, name.clone(), cooker_status_tx.clone());
|
||||
spawn_log_reader(stdout_reader, name.clone(), status_tx.clone());
|
||||
spawn_log_reader(stderr_reader, name.clone(), status_tx.clone());
|
||||
(stdout_writer, stderr_writer)
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Clone, Copy)]
|
||||
#[repr(u32)]
|
||||
enum PromptOption {
|
||||
Retry = 2,
|
||||
Skip,
|
||||
Exit,
|
||||
}
|
||||
|
||||
struct FailurePrompt {
|
||||
recipe: CookRecipe,
|
||||
error: String,
|
||||
selected: PromptOption,
|
||||
}
|
||||
|
||||
impl FailurePrompt {
|
||||
fn new(recipe: CookRecipe, error: String) -> Self {
|
||||
Self {
|
||||
recipe,
|
||||
error,
|
||||
selected: PromptOption::Exit,
|
||||
}
|
||||
}
|
||||
|
||||
fn next(&mut self) {
|
||||
self.selected = match self.selected {
|
||||
PromptOption::Retry => PromptOption::Skip,
|
||||
PromptOption::Skip => PromptOption::Exit,
|
||||
PromptOption::Exit => PromptOption::Retry,
|
||||
}
|
||||
}
|
||||
|
||||
fn prev(&mut self) {
|
||||
self.selected = match self.selected {
|
||||
PromptOption::Retry => PromptOption::Exit,
|
||||
PromptOption::Skip => PromptOption::Retry,
|
||||
PromptOption::Exit => PromptOption::Skip,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -21,9 +21,25 @@ use crate::is_redox;
|
||||
|
||||
use crate::REMOTE_PKG_SOURCE;
|
||||
|
||||
macro_rules! log_warn {
|
||||
($logger:expr, $($arg:tt)+) => {
|
||||
use std::io::Write;
|
||||
|
||||
if $logger.is_some() {
|
||||
let _ = $logger.as_ref().unwrap().1.try_clone().unwrap().write(
|
||||
format!($($arg)+)
|
||||
.as_bytes(),
|
||||
);
|
||||
} else {
|
||||
eprintln!($($arg)+);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
fn auto_deps(
|
||||
stage_dir: &Path,
|
||||
dep_pkgars: &BTreeSet<(PackageName, PathBuf)>,
|
||||
logger: &Stdout,
|
||||
) -> BTreeSet<PackageName> {
|
||||
let mut paths = BTreeSet::new();
|
||||
let mut visited = BTreeSet::new();
|
||||
@ -43,7 +59,10 @@ fn auto_deps(
|
||||
};
|
||||
if visited.contains(&dir) {
|
||||
#[cfg(debug_assertions)]
|
||||
eprintln!("DEBUG: auto_deps => Skipping `{dir:?}` (already visited)");
|
||||
log_warn!(
|
||||
logger,
|
||||
"DEBUG: auto_deps => Skipping `{dir:?}` (already visited)"
|
||||
);
|
||||
continue;
|
||||
}
|
||||
assert!(
|
||||
@ -90,7 +109,7 @@ fn auto_deps(
|
||||
continue;
|
||||
};
|
||||
if let Ok(relative_path) = path.strip_prefix(stage_dir) {
|
||||
eprintln!("DEBUG: {} needs {}", relative_path.display(), name);
|
||||
log_warn!(logger, "DEBUG: {} needs {}", relative_path.display(), name);
|
||||
}
|
||||
needed.insert(name.to_string());
|
||||
}
|
||||
@ -124,7 +143,7 @@ fn auto_deps(
|
||||
continue;
|
||||
};
|
||||
if needed.contains(child_name) {
|
||||
eprintln!("DEBUG: {} provides {}", dep, child_name);
|
||||
log_warn!(logger, "DEBUG: {} provides {}", dep, child_name);
|
||||
deps.insert(dep.clone());
|
||||
missing.remove(child_name);
|
||||
}
|
||||
@ -134,7 +153,7 @@ fn auto_deps(
|
||||
}
|
||||
|
||||
for name in missing {
|
||||
eprintln!("WARN: {} missing", name);
|
||||
log_warn!(logger, "WARN: {} missing", name);
|
||||
}
|
||||
|
||||
deps
|
||||
@ -174,7 +193,7 @@ pub fn build(
|
||||
}
|
||||
|
||||
if stage_dir.exists() && !check_source {
|
||||
let auto_deps = build_auto_deps(target_dir, &stage_dir, dep_pkgars)?;
|
||||
let auto_deps = build_auto_deps(target_dir, &stage_dir, dep_pkgars, logger)?;
|
||||
return Ok((stage_dir, auto_deps));
|
||||
}
|
||||
|
||||
@ -190,7 +209,8 @@ pub fn build(
|
||||
if sysroot_dir.is_dir() {
|
||||
let sysroot_modified = modified_dir(&sysroot_dir)?;
|
||||
if sysroot_modified < source_modified || sysroot_modified < deps_modified {
|
||||
eprintln!(
|
||||
log_warn!(
|
||||
logger,
|
||||
"DEBUG: '{}' newer than '{}'",
|
||||
source_dir.display(),
|
||||
sysroot_dir.display()
|
||||
@ -239,7 +259,8 @@ pub fn build(
|
||||
if stage_dir.is_dir() {
|
||||
let stage_modified = modified_dir(&stage_dir)?;
|
||||
if stage_modified < source_modified || stage_modified < deps_modified {
|
||||
eprintln!(
|
||||
log_warn!(
|
||||
logger,
|
||||
"DEBUG: '{}' newer than '{}'",
|
||||
source_dir.display(),
|
||||
stage_dir.display()
|
||||
@ -318,7 +339,7 @@ pub fn build(
|
||||
} else {
|
||||
let cookbook_redoxer = Path::new("target/release/cookbook_redoxer")
|
||||
.canonicalize()
|
||||
.unwrap();
|
||||
.unwrap_or(PathBuf::from("/bin/false"));
|
||||
let mut command = Command::new(&cookbook_redoxer);
|
||||
command.arg("env").arg("bash").arg("-ex");
|
||||
command.env("COOKBOOK_REDOXER", &cookbook_redoxer);
|
||||
@ -348,7 +369,7 @@ pub fn build(
|
||||
rename(&stage_dir_tmp, &stage_dir)?;
|
||||
}
|
||||
|
||||
let auto_deps = build_auto_deps(target_dir, &stage_dir, dep_pkgars)?;
|
||||
let auto_deps = build_auto_deps(target_dir, &stage_dir, dep_pkgars, logger)?;
|
||||
|
||||
Ok((stage_dir, auto_deps))
|
||||
}
|
||||
@ -358,6 +379,7 @@ fn build_auto_deps(
|
||||
target_dir: &Path,
|
||||
stage_dir: &PathBuf,
|
||||
dep_pkgars: BTreeSet<(PackageName, PathBuf)>,
|
||||
logger: &Stdout,
|
||||
) -> Result<BTreeSet<PackageName>, String> {
|
||||
let auto_deps_path = target_dir.join("auto_deps.toml");
|
||||
if auto_deps_path.is_file() && modified(&auto_deps_path)? < modified(stage_dir)? {
|
||||
@ -371,7 +393,7 @@ fn build_auto_deps(
|
||||
toml::from_str(&toml_content).map_err(|_| "failed to deserialize cached auto_deps")?;
|
||||
wrapper.packages
|
||||
} else {
|
||||
let packages = auto_deps(stage_dir, &dep_pkgars);
|
||||
let packages = auto_deps(stage_dir, &dep_pkgars, logger);
|
||||
let wrapper = AutoDeps { packages };
|
||||
serialize_and_write(&auto_deps_path, &wrapper)?;
|
||||
wrapper.packages
|
||||
@ -475,7 +497,7 @@ mod tests {
|
||||
"Expected a loop where {dir:?} points to {root:?}"
|
||||
);
|
||||
|
||||
let entries = auto_deps(root, &Default::default());
|
||||
let entries = auto_deps(root, &Default::default(), &None);
|
||||
assert!(
|
||||
entries.is_empty(),
|
||||
"auto_deps shouldn't have yielded any libraries"
|
||||
|
||||
@ -76,7 +76,7 @@ pub fn fetch_offline(
|
||||
}) => {
|
||||
if !source_dir.is_dir() {
|
||||
let source_tar = recipe_dir.join("source.tar");
|
||||
let source_tar_blake3 = get_blake3(&source_tar, true)?;
|
||||
let source_tar_blake3 = get_blake3(&source_tar, true && logger.is_none())?;
|
||||
if source_tar.exists() {
|
||||
if let Some(blake3) = blake3 {
|
||||
if source_tar_blake3 != *blake3 {
|
||||
@ -257,7 +257,7 @@ pub fn fetch(recipe_dir: &Path, recipe: &Recipe, logger: &Stdout) -> Result<Path
|
||||
tar_updated = true;
|
||||
download_wget(&tar, &source_tar, logger)?;
|
||||
}
|
||||
let source_tar_blake3 = get_blake3(&source_tar, tar_updated)?;
|
||||
let source_tar_blake3 = get_blake3(&source_tar, tar_updated && logger.is_none())?;
|
||||
if let Some(blake3) = blake3 {
|
||||
if source_tar_blake3 != *blake3 {
|
||||
if tar_updated {
|
||||
|
||||
11
unfetch.sh
11
unfetch.sh
@ -5,16 +5,9 @@ source config.sh
|
||||
|
||||
if [ $# = 0 ]
|
||||
then
|
||||
recipes="$(list_recipes --short)"
|
||||
recipes="--all"
|
||||
else
|
||||
recipes="$@"
|
||||
fi
|
||||
|
||||
for recipe_name in $recipes
|
||||
do
|
||||
recipe_path=`find_recipe $recipe_name`
|
||||
|
||||
echo -e "\033[01;38;5;215mcook - unfetch $recipe_name\033[0m"
|
||||
rm -rfv "$recipe_path"/source "$recipe_path"/source.tar
|
||||
done
|
||||
|
||||
repo unfetch $recipes
|
||||
|
||||
Loading…
Reference in New Issue
Block a user