mirror of
https://gitlab.redox-os.org/redox-os/redox.git
synced 2026-06-25 14:24:18 +08:00
Merge branch 'smart-unfetch' into 'master'
Auto unfetch for tar recipes and auto fetch symlink recipes Closes redox#1701 See merge request redox-os/cookbook!658
This commit is contained in:
commit
b68340234b
196
Cargo.lock
generated
196
Cargo.lock
generated
@ -642,11 +642,11 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "dirs"
|
||||
version = "5.0.1"
|
||||
version = "6.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "44c45a9d03d6676652bcb5e724c7e988de1acad23a711b5217ab9cbecbec2225"
|
||||
checksum = "c3e8aa94d75141228480295a7d0e7feb620b1a5ad9f12bc40be62411e38cce4e"
|
||||
dependencies = [
|
||||
"dirs-sys 0.4.1",
|
||||
"dirs-sys 0.5.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -656,20 +656,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1b1d1d91c932ef41c0f2663aa8b0ca0342d444d842c06914aa0a7e352d0bada6"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"redox_users",
|
||||
"redox_users 0.4.6",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dirs-sys"
|
||||
version = "0.4.1"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c"
|
||||
checksum = "e01a3366d27ee9890022452ee61b2b63a67e6f13f58900b651ff5665f0bb1fab"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"option-ext",
|
||||
"redox_users",
|
||||
"windows-sys 0.48.0",
|
||||
"redox_users 0.5.2",
|
||||
"windows-sys 0.60.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1830,31 +1830,15 @@ version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "436d45c2b6a5b159d43da708e62b25be3a4a3d5550d654b72216ade4c4bfd717"
|
||||
|
||||
[[package]]
|
||||
name = "redox-pkg"
|
||||
version = "0.2.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "70f49b2c29ae3c72ff3a8dbc1c5eefba9093a8c5ceaa8ca5292833816fe931e2"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"indicatif",
|
||||
"pkgar 0.1.18",
|
||||
"pkgar-core 0.1.18",
|
||||
"pkgar-keys 0.1.18",
|
||||
"reqwest",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
"thiserror 1.0.69",
|
||||
"toml 0.8.23",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox-pkg"
|
||||
version = "0.2.8"
|
||||
source = "git+https://gitlab.redox-os.org/redox-os/pkgutils#ea2641126c8b38d7b8997c5c7ebec74999fc9578"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6d50a7ed267e236ce8bfa178bfd3fb7a39765689d037e51c57f36bad46f474fd"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"ignore",
|
||||
"indicatif",
|
||||
"pkgar 0.1.18",
|
||||
"pkgar-core 0.1.18",
|
||||
"pkgar-keys 0.1.18",
|
||||
@ -1886,7 +1870,7 @@ dependencies = [
|
||||
"pkgar 0.1.19",
|
||||
"pkgar-core 0.1.19",
|
||||
"pkgar-keys 0.1.19",
|
||||
"redox-pkg 0.2.8",
|
||||
"redox-pkg",
|
||||
"redoxer",
|
||||
"regex",
|
||||
"serde",
|
||||
@ -1913,7 +1897,7 @@ dependencies = [
|
||||
"pkgar-core 0.1.18",
|
||||
"pkgar-keys 0.1.18",
|
||||
"rand 0.8.5",
|
||||
"redox-pkg 0.2.5",
|
||||
"redox-pkg",
|
||||
"redox_liner",
|
||||
"redox_syscall",
|
||||
"redoxfs",
|
||||
@ -1965,18 +1949,29 @@ dependencies = [
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redoxer"
|
||||
version = "0.2.53"
|
||||
name = "redox_users"
|
||||
version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5558ef5ce386b5a4b7d5276467d940023b31c5a85484a05ac35b31da4055d740"
|
||||
checksum = "a4e608c6638b9c18977b00b475ac1f28d14e84b27d8d42f70e0bf1e3dec127ac"
|
||||
dependencies = [
|
||||
"dirs 5.0.1",
|
||||
"getrandom 0.2.16",
|
||||
"libredox",
|
||||
"thiserror 2.0.12",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redoxer"
|
||||
version = "0.2.54"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ead20eb76f54e16ecc3e678daca948d49497588a777148ac60d99a67dab8a2b0"
|
||||
dependencies = [
|
||||
"dirs 6.0.0",
|
||||
"proc-mounts",
|
||||
"redox_installer",
|
||||
"redox_syscall",
|
||||
"redoxfs",
|
||||
"tempfile",
|
||||
"toml 0.5.11",
|
||||
"toml 0.9.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -2274,6 +2269,15 @@ dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_spanned"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "40734c41988f7306bb04f0ecf60ec0f3f1caa34290e4e8ea471dcd3346483b83"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_urlencoded"
|
||||
version = "0.7.1"
|
||||
@ -2547,15 +2551,6 @@ dependencies = [
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml"
|
||||
version = "0.5.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml"
|
||||
version = "0.8.23"
|
||||
@ -2563,11 +2558,26 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"serde_spanned",
|
||||
"toml_datetime",
|
||||
"serde_spanned 0.6.9",
|
||||
"toml_datetime 0.6.11",
|
||||
"toml_edit",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml"
|
||||
version = "0.9.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "75129e1dc5000bfbaa9fee9d1b21f974f9fbad9daec557a521ee6e080825f6e8"
|
||||
dependencies = [
|
||||
"indexmap",
|
||||
"serde",
|
||||
"serde_spanned 1.0.0",
|
||||
"toml_datetime 0.7.0",
|
||||
"toml_parser",
|
||||
"toml_writer",
|
||||
"winnow",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml_datetime"
|
||||
version = "0.6.11"
|
||||
@ -2577,6 +2587,15 @@ dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml_datetime"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bade1c3e902f58d73d3f294cd7f20391c1cb2fbcb643b73566bc773971df91e3"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml_edit"
|
||||
version = "0.22.27"
|
||||
@ -2585,18 +2604,33 @@ checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a"
|
||||
dependencies = [
|
||||
"indexmap",
|
||||
"serde",
|
||||
"serde_spanned",
|
||||
"toml_datetime",
|
||||
"serde_spanned 0.6.9",
|
||||
"toml_datetime 0.6.11",
|
||||
"toml_write",
|
||||
"winnow",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml_parser"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b551886f449aa90d4fe2bdaa9f4a2577ad2dde302c61ecf262d80b116db95c10"
|
||||
dependencies = [
|
||||
"winnow",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml_write"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801"
|
||||
|
||||
[[package]]
|
||||
name = "toml_writer"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "df8b2b54733674ad286d16267dcfc7a71ed5c776e4ac7aa3c3e2561f7c637bf2"
|
||||
|
||||
[[package]]
|
||||
name = "tower"
|
||||
version = "0.5.2"
|
||||
@ -2924,7 +2958,7 @@ version = "0.1.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb"
|
||||
dependencies = [
|
||||
"windows-sys 0.48.0",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -3001,15 +3035,6 @@ dependencies = [
|
||||
"windows-targets 0.42.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.48.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
|
||||
dependencies = [
|
||||
"windows-targets 0.48.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.52.0"
|
||||
@ -3052,21 +3077,6 @@ dependencies = [
|
||||
"windows_x86_64_msvc 0.42.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-targets"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c"
|
||||
dependencies = [
|
||||
"windows_aarch64_gnullvm 0.48.5",
|
||||
"windows_aarch64_msvc 0.48.5",
|
||||
"windows_i686_gnu 0.48.5",
|
||||
"windows_i686_msvc 0.48.5",
|
||||
"windows_x86_64_gnu 0.48.5",
|
||||
"windows_x86_64_gnullvm 0.48.5",
|
||||
"windows_x86_64_msvc 0.48.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-targets"
|
||||
version = "0.52.6"
|
||||
@ -3105,12 +3115,6 @@ version = "0.42.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_gnullvm"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_gnullvm"
|
||||
version = "0.52.6"
|
||||
@ -3129,12 +3133,6 @@ version = "0.42.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.52.6"
|
||||
@ -3153,12 +3151,6 @@ version = "0.42.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
version = "0.52.6"
|
||||
@ -3189,12 +3181,6 @@ version = "0.42.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.52.6"
|
||||
@ -3213,12 +3199,6 @@ version = "0.42.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
version = "0.52.6"
|
||||
@ -3237,12 +3217,6 @@ version = "0.42.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnullvm"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnullvm"
|
||||
version = "0.52.6"
|
||||
@ -3261,12 +3235,6 @@ version = "0.42.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.52.6"
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
name = "redox_cookbook"
|
||||
version = "0.1.0"
|
||||
authors = ["Jeremy Soller <jackpot51@gmail.com>"]
|
||||
edition = "2018"
|
||||
edition = "2024"
|
||||
default-run = "cook"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
@ -28,7 +28,7 @@ pbr = "1.0.2"
|
||||
pkgar = { path = "pkgar/pkgar" }
|
||||
pkgar-core = { path = "pkgar/pkgar-core" }
|
||||
pkgar-keys = { path = "pkgar/pkgar-keys" }
|
||||
redox-pkg = { git = "https://gitlab.redox-os.org/redox-os/pkgutils" }
|
||||
redox-pkg = "0.2.8"
|
||||
redoxer = "0.2"
|
||||
regex = "1.11"
|
||||
serde = { version = "=1.0.197", features = ["derive"] }
|
||||
|
||||
622
src/bin/cook.rs
622
src/bin/cook.rs
@ -1,629 +1,23 @@
|
||||
use cookbook::blake3::blake3_progress;
|
||||
use cookbook::config::{init_config, translate_mirror};
|
||||
use cookbook::recipe::{AutoDeps, BuildKind, CookRecipe, Recipe, SourceRecipe};
|
||||
use cookbook::config::init_config;
|
||||
use cookbook::cook::fetch::*;
|
||||
use cookbook::cook::fs::*;
|
||||
use cookbook::cook::script::SHARED_PRESCRIPT;
|
||||
use cookbook::recipe::{AutoDeps, BuildKind, CookRecipe, Recipe};
|
||||
use pkg::package::Package;
|
||||
use pkg::{recipes, PackageName};
|
||||
use serde::Serialize;
|
||||
use pkg::{PackageName, recipes};
|
||||
use std::collections::VecDeque;
|
||||
use std::convert::TryInto;
|
||||
use std::{
|
||||
collections::BTreeSet,
|
||||
env, fs,
|
||||
io::{self, Write},
|
||||
path::{Path, PathBuf},
|
||||
process::{self, Command, Stdio},
|
||||
process::{self, Command},
|
||||
str,
|
||||
time::SystemTime,
|
||||
};
|
||||
use termion::{color, style};
|
||||
use walkdir::{DirEntry, WalkDir};
|
||||
|
||||
use cookbook::{is_redox, WALK_DEPTH};
|
||||
|
||||
fn remove_all(path: &Path) -> Result<(), String> {
|
||||
if path.is_dir() {
|
||||
fs::remove_dir_all(path)
|
||||
} else {
|
||||
fs::remove_file(path)
|
||||
}
|
||||
.map_err(|err| format!("failed to remove '{}': {}\n{:?}", path.display(), err, err))
|
||||
}
|
||||
|
||||
fn create_dir(dir: &Path) -> Result<(), String> {
|
||||
fs::create_dir(dir)
|
||||
.map_err(|err| format!("failed to create '{}': {}\n{:?}", dir.display(), err, err))
|
||||
}
|
||||
|
||||
fn create_dir_clean(dir: &Path) -> Result<(), String> {
|
||||
if dir.is_dir() {
|
||||
remove_all(dir)?;
|
||||
}
|
||||
create_dir(dir)
|
||||
}
|
||||
|
||||
fn copy_dir_all(src: impl AsRef<Path>, dst: impl AsRef<Path>) -> io::Result<()> {
|
||||
fs::create_dir_all(&dst)?;
|
||||
for entry in fs::read_dir(src)? {
|
||||
let entry = entry?;
|
||||
let ty = entry.file_type()?;
|
||||
if ty.is_dir() {
|
||||
copy_dir_all(entry.path(), dst.as_ref().join(entry.file_name()))?;
|
||||
} else {
|
||||
fs::copy(entry.path(), dst.as_ref().join(entry.file_name()))?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn symlink(original: impl AsRef<Path>, link: impl AsRef<Path>) -> Result<(), String> {
|
||||
std::os::unix::fs::symlink(&original, &link).map_err(|err| {
|
||||
format!(
|
||||
"failed to symlink '{}' to '{}': {}\n{:?}",
|
||||
original.as_ref().display(),
|
||||
link.as_ref().display(),
|
||||
err,
|
||||
err
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
fn modified(path: &Path) -> Result<SystemTime, String> {
|
||||
let metadata = fs::metadata(path).map_err(|err| {
|
||||
format!(
|
||||
"failed to get metadata of '{}': {}\n{:#?}",
|
||||
path.display(),
|
||||
err,
|
||||
err
|
||||
)
|
||||
})?;
|
||||
metadata.modified().map_err(|err| {
|
||||
format!(
|
||||
"failed to get modified time of '{}': {}\n{:#?}",
|
||||
path.display(),
|
||||
err,
|
||||
err
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
fn modified_dir_inner<F: FnMut(&DirEntry) -> bool>(
|
||||
dir: &Path,
|
||||
filter: F,
|
||||
) -> io::Result<SystemTime> {
|
||||
let mut newest = fs::metadata(dir)?.modified()?;
|
||||
for entry_res in WalkDir::new(dir).into_iter().filter_entry(filter) {
|
||||
let entry = entry_res?;
|
||||
let modified = entry.metadata()?.modified()?;
|
||||
if modified > newest {
|
||||
newest = modified;
|
||||
}
|
||||
}
|
||||
Ok(newest)
|
||||
}
|
||||
|
||||
fn modified_dir(dir: &Path) -> Result<SystemTime, String> {
|
||||
modified_dir_inner(dir, |_| true).map_err(|err| {
|
||||
format!(
|
||||
"failed to get modified time of '{}': {}\n{:#?}",
|
||||
dir.display(),
|
||||
err,
|
||||
err
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
fn modified_dir_ignore_git(dir: &Path) -> Result<SystemTime, String> {
|
||||
modified_dir_inner(dir, |entry| {
|
||||
entry
|
||||
.file_name()
|
||||
.to_str()
|
||||
.map(|s| s != ".git")
|
||||
.unwrap_or(true)
|
||||
})
|
||||
.map_err(|err| {
|
||||
format!(
|
||||
"failed to get modified time of '{}': {}\n{:#?}",
|
||||
dir.display(),
|
||||
err,
|
||||
err
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
fn rename(src: &Path, dst: &Path) -> Result<(), String> {
|
||||
fs::rename(src, dst).map_err(|err| {
|
||||
format!(
|
||||
"failed to rename '{}' to '{}': {}\n{:?}",
|
||||
src.display(),
|
||||
dst.display(),
|
||||
err,
|
||||
err
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
fn run_command(mut command: process::Command) -> Result<(), String> {
|
||||
let status = command
|
||||
.status()
|
||||
.map_err(|err| format!("failed to run {:?}: {}\n{:#?}", command, err, err))?;
|
||||
|
||||
if !status.success() {
|
||||
return Err(format!(
|
||||
"failed to run {:?}: exited with status {}",
|
||||
command, status
|
||||
));
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn run_command_stdin(mut command: process::Command, stdin_data: &[u8]) -> Result<(), String> {
|
||||
command.stdin(Stdio::piped());
|
||||
|
||||
let mut child = command
|
||||
.spawn()
|
||||
.map_err(|err| format!("failed to spawn {:?}: {}\n{:#?}", command, err, err))?;
|
||||
|
||||
if let Some(ref mut stdin) = child.stdin {
|
||||
stdin.write_all(stdin_data).map_err(|err| {
|
||||
format!(
|
||||
"failed to write stdin of {:?}: {}\n{:#?}",
|
||||
command, err, err
|
||||
)
|
||||
})?;
|
||||
} else {
|
||||
return Err(format!("failed to find stdin of {:?}", command));
|
||||
}
|
||||
|
||||
let status = child
|
||||
.wait()
|
||||
.map_err(|err| format!("failed to run {:?}: {}\n{:#?}", command, err, err))?;
|
||||
|
||||
if !status.success() {
|
||||
return Err(format!(
|
||||
"failed to run {:?}: exited with status {}",
|
||||
command, status
|
||||
));
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn serialize_and_write<T: Serialize>(file_path: &Path, content: &T) -> Result<(), String> {
|
||||
let toml_content = toml::to_string(content).map_err(|err| {
|
||||
format!(
|
||||
"Failed to serialize content for '{}': {}",
|
||||
file_path.display(),
|
||||
err
|
||||
)
|
||||
})?;
|
||||
|
||||
fs::write(file_path, toml_content)
|
||||
.map_err(|err| format!("Failed to write to file '{}': {}", file_path.display(), err))?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
static SHARED_PRESCRIPT: &str = r#"
|
||||
# Build dynamically
|
||||
function DYNAMIC_INIT {
|
||||
COOKBOOK_AUTORECONF="autoreconf"
|
||||
autotools_recursive_regenerate() {
|
||||
for f in $(find . -name configure.ac -o -name configure.in -type f | sort); do
|
||||
echo "* autotools regen in '$(dirname $f)'..."
|
||||
( cd "$(dirname "$f")" && "${COOKBOOK_AUTORECONF}" -fvi "$@" -I${COOKBOOK_HOST_SYSROOT}/share/aclocal )
|
||||
done
|
||||
}
|
||||
|
||||
if [ "${TARGET}" != "x86_64-unknown-redox" ]
|
||||
then
|
||||
echo "WARN: ${TARGET} does not support dynamic linking." >&2
|
||||
return
|
||||
fi
|
||||
|
||||
echo "DEBUG: Program is being compiled dynamically."
|
||||
|
||||
COOKBOOK_CONFIGURE_FLAGS=(
|
||||
--host="${GNU_TARGET}"
|
||||
--prefix="/usr"
|
||||
--enable-shared
|
||||
--disable-static
|
||||
)
|
||||
|
||||
COOKBOOK_CMAKE_FLAGS=(
|
||||
-DBUILD_SHARED_LIBS=True
|
||||
-DENABLE_SHARED=True
|
||||
-DENABLE_STATIC=False
|
||||
)
|
||||
|
||||
COOKBOOK_MESON_FLAGS=(
|
||||
--buildtype release
|
||||
--wrap-mode nofallback
|
||||
--strip
|
||||
-Ddefault_library=shared
|
||||
-Dprefix=/usr
|
||||
)
|
||||
|
||||
# TODO: check paths for spaces
|
||||
export LDFLAGS="-Wl,-rpath-link,${COOKBOOK_SYSROOT}/lib -L${COOKBOOK_SYSROOT}/lib"
|
||||
export RUSTFLAGS="-C target-feature=-crt-static"
|
||||
export COOKBOOK_DYNAMIC=1
|
||||
}
|
||||
|
||||
# Build both dynamically and statically
|
||||
function DYNAMIC_STATIC_INIT {
|
||||
DYNAMIC_INIT
|
||||
if [ "${COOKBOOK_DYNAMIC}" == "1" ]
|
||||
then
|
||||
COOKBOOK_CONFIGURE_FLAGS=(
|
||||
--host="${GNU_TARGET}"
|
||||
--prefix="/usr"
|
||||
--enable-shared
|
||||
--enable-static
|
||||
)
|
||||
|
||||
COOKBOOK_CMAKE_FLAGS=(
|
||||
-DBUILD_SHARED_LIBS=True
|
||||
-DENABLE_SHARED=True
|
||||
-DENABLE_STATIC=True
|
||||
)
|
||||
|
||||
COOKBOOK_MESON_FLAGS=(
|
||||
--buildtype release
|
||||
--wrap-mode nofallback
|
||||
--strip
|
||||
-Ddefault_library=both
|
||||
-Dprefix=/usr
|
||||
)
|
||||
fi
|
||||
}
|
||||
|
||||
function GNU_CONFIG_GET {
|
||||
wget -O "$1" "https://gitlab.redox-os.org/redox-os/gnu-config/-/raw/master/config.sub?inline=false"
|
||||
}
|
||||
"#;
|
||||
|
||||
fn fetch_offline(recipe_dir: &Path, source: &Option<SourceRecipe>) -> Result<PathBuf, String> {
|
||||
let source_dir = recipe_dir.join("source");
|
||||
match source {
|
||||
Some(SourceRecipe::SameAs { same_as: _ }) | Some(SourceRecipe::Path { path: _ }) | None => {
|
||||
return fetch(recipe_dir, source);
|
||||
}
|
||||
Some(SourceRecipe::Git {
|
||||
git: _,
|
||||
upstream: _,
|
||||
branch: _,
|
||||
rev: _,
|
||||
patches: _,
|
||||
script: _,
|
||||
shallow_clone: _,
|
||||
})
|
||||
| Some(SourceRecipe::Tar {
|
||||
tar: _,
|
||||
blake3: _,
|
||||
patches: _,
|
||||
script: _,
|
||||
}) => {
|
||||
if !source_dir.is_dir() {
|
||||
return Err(format!(
|
||||
"'{dir}' is not exist and unable to continue in offline mode",
|
||||
dir = source_dir.display(),
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(source_dir)
|
||||
}
|
||||
|
||||
fn fetch(recipe_dir: &Path, source: &Option<SourceRecipe>) -> Result<PathBuf, String> {
|
||||
let source_dir = recipe_dir.join("source");
|
||||
match source {
|
||||
Some(SourceRecipe::SameAs { same_as }) => {
|
||||
if !source_dir.is_symlink() {
|
||||
if source_dir.is_dir() {
|
||||
return Err(format!(
|
||||
"'{dir}' is a directory, but recipe indicated a symlink. \n\
|
||||
try removing '{dir}' if you haven't made any changes that would be lost",
|
||||
dir = source_dir.display(),
|
||||
));
|
||||
}
|
||||
let original = Path::new(same_as).join("source");
|
||||
std::os::unix::fs::symlink(&original, &source_dir).map_err(|err| {
|
||||
format!(
|
||||
"failed to symlink '{}' to '{}': {}\n{:?}",
|
||||
original.display(),
|
||||
source_dir.display(),
|
||||
err,
|
||||
err
|
||||
)
|
||||
})?;
|
||||
}
|
||||
}
|
||||
Some(SourceRecipe::Path { path }) => {
|
||||
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!(
|
||||
"Couldn't copy source from {} to {}: {}",
|
||||
path,
|
||||
source_dir.display(),
|
||||
e
|
||||
)
|
||||
})?;
|
||||
}
|
||||
}
|
||||
Some(SourceRecipe::Git {
|
||||
git,
|
||||
upstream,
|
||||
branch,
|
||||
rev,
|
||||
patches,
|
||||
script,
|
||||
shallow_clone,
|
||||
}) => {
|
||||
//TODO: use libgit?
|
||||
let shallow_clone = *shallow_clone == Some(true);
|
||||
if !source_dir.is_dir() {
|
||||
// Create source.tmp
|
||||
let source_dir_tmp = recipe_dir.join("source.tmp");
|
||||
create_dir_clean(&source_dir_tmp)?;
|
||||
|
||||
// Clone the repository to source.tmp
|
||||
let mut command = Command::new("git");
|
||||
command
|
||||
.arg("clone")
|
||||
.arg("--recursive")
|
||||
.arg(translate_mirror(git));
|
||||
if let Some(branch) = branch {
|
||||
command.arg("--branch").arg(branch);
|
||||
}
|
||||
if shallow_clone {
|
||||
command.arg("--depth").arg("1").arg("--shallow-submodules");
|
||||
}
|
||||
command.arg(&source_dir_tmp);
|
||||
run_command(command)?;
|
||||
|
||||
// Move source.tmp to source atomically
|
||||
rename(&source_dir_tmp, &source_dir)?;
|
||||
} else if !shallow_clone {
|
||||
// Don't let this code reset the origin for the cookbook repo
|
||||
let source_git_dir = source_dir.join(".git");
|
||||
if !source_git_dir.is_dir() {
|
||||
return Err(format!(
|
||||
"'{}' is not a git repository, but recipe indicated git source",
|
||||
source_dir.display(),
|
||||
));
|
||||
}
|
||||
|
||||
// Reset origin
|
||||
let mut command = Command::new("git");
|
||||
command.arg("-C").arg(&source_dir);
|
||||
command.arg("remote").arg("set-url").arg("origin").arg(git);
|
||||
run_command(command)?;
|
||||
|
||||
// Fetch origin
|
||||
let mut command = Command::new("git");
|
||||
command.arg("-C").arg(&source_dir);
|
||||
command.arg("fetch").arg("origin");
|
||||
run_command(command)?;
|
||||
}
|
||||
|
||||
if let Some(_upstream) = upstream {
|
||||
//TODO: set upstream URL
|
||||
// git remote set-url upstream "$GIT_UPSTREAM" &> /dev/null ||
|
||||
// git remote add upstream "$GIT_UPSTREAM"
|
||||
// git fetch upstream
|
||||
}
|
||||
|
||||
if let Some(rev) = rev {
|
||||
// Check out specified revision
|
||||
let mut command = Command::new("git");
|
||||
command.arg("-C").arg(&source_dir);
|
||||
command.arg("checkout").arg(rev);
|
||||
run_command(command)?;
|
||||
} else if !shallow_clone && !is_redox() {
|
||||
//TODO: complicated stuff to check and reset branch to origin
|
||||
//TODO: redox can't undestand this (got exit status 1)
|
||||
let mut command = Command::new("bash");
|
||||
command.arg("-c").arg(
|
||||
r#"
|
||||
ORIGIN_BRANCH="$(git branch --remotes | grep '^ origin/HEAD -> ' | cut -d ' ' -f 5-)"
|
||||
if [ -n "$BRANCH" ]
|
||||
then
|
||||
ORIGIN_BRANCH="origin/$BRANCH"
|
||||
fi
|
||||
|
||||
if [ "$(git rev-parse HEAD)" != "$(git rev-parse $ORIGIN_BRANCH)" ]
|
||||
then
|
||||
git checkout -B "$(echo "$ORIGIN_BRANCH" | cut -d / -f 2-)" "$ORIGIN_BRANCH"
|
||||
fi"#,
|
||||
);
|
||||
if let Some(branch) = branch {
|
||||
command.env("BRANCH", branch);
|
||||
}
|
||||
command.current_dir(&source_dir);
|
||||
run_command(command)?;
|
||||
}
|
||||
|
||||
if !patches.is_empty() || script.is_some() {
|
||||
// Hard reset
|
||||
let mut command = Command::new("git");
|
||||
command.arg("-C").arg(&source_dir);
|
||||
command.arg("reset").arg("--hard");
|
||||
run_command(command)?;
|
||||
}
|
||||
|
||||
if !shallow_clone {
|
||||
// Sync submodules URL
|
||||
let mut command = Command::new("git");
|
||||
command.arg("-C").arg(&source_dir);
|
||||
command.arg("submodule").arg("sync").arg("--recursive");
|
||||
run_command(command)?;
|
||||
|
||||
// Update submodules
|
||||
let mut command = Command::new("git");
|
||||
command.arg("-C").arg(&source_dir);
|
||||
command
|
||||
.arg("submodule")
|
||||
.arg("update")
|
||||
.arg("--init")
|
||||
.arg("--recursive");
|
||||
run_command(command)?;
|
||||
}
|
||||
|
||||
// Apply patches
|
||||
for patch_name in patches {
|
||||
let patch_file = recipe_dir.join(patch_name);
|
||||
if !patch_file.is_file() {
|
||||
return Err(format!(
|
||||
"failed to find patch file '{}'",
|
||||
patch_file.display()
|
||||
));
|
||||
}
|
||||
|
||||
let patch = fs::read_to_string(&patch_file).map_err(|err| {
|
||||
format!(
|
||||
"failed to read patch file '{}': {}\n{:#?}",
|
||||
patch_file.display(),
|
||||
err,
|
||||
err
|
||||
)
|
||||
})?;
|
||||
|
||||
let mut command = Command::new("patch");
|
||||
command.arg("--forward");
|
||||
command.arg("--batch");
|
||||
command.arg("--directory").arg(&source_dir);
|
||||
command.arg("--strip=1");
|
||||
run_command_stdin(command, patch.as_bytes())?;
|
||||
}
|
||||
|
||||
// Run source script
|
||||
if let Some(script) = script {
|
||||
let mut command = Command::new("bash");
|
||||
command.arg("-ex");
|
||||
command.current_dir(&source_dir);
|
||||
run_command_stdin(command, format!("{SHARED_PRESCRIPT}\n{script}").as_bytes())?;
|
||||
}
|
||||
}
|
||||
Some(SourceRecipe::Tar {
|
||||
tar,
|
||||
blake3,
|
||||
patches,
|
||||
script,
|
||||
}) => {
|
||||
if !source_dir.is_dir() {
|
||||
// Download tar
|
||||
//TODO: replace wget
|
||||
let source_tar = recipe_dir.join("source.tar");
|
||||
if !source_tar.is_file() {
|
||||
let source_tar_tmp = recipe_dir.join("source.tar.tmp");
|
||||
|
||||
let mut command = Command::new("wget");
|
||||
command.arg(translate_mirror(tar));
|
||||
command.arg("--continue").arg("-O").arg(&source_tar_tmp);
|
||||
run_command(command)?;
|
||||
|
||||
// Move source.tar.tmp to source.tar atomically
|
||||
rename(&source_tar_tmp, &source_tar)?;
|
||||
}
|
||||
|
||||
// Calculate blake3
|
||||
let source_tar_blake3 = blake3_progress(&source_tar).map_err(|err| {
|
||||
format!(
|
||||
"failed to calculate blake3 of '{}': {}\n{:?}",
|
||||
source_tar.display(),
|
||||
err,
|
||||
err
|
||||
)
|
||||
})?;
|
||||
if let Some(blake3) = blake3 {
|
||||
// Check if it matches recipe
|
||||
if &source_tar_blake3 != blake3 {
|
||||
return Err(format!(
|
||||
"calculated blake3 '{}' does not match recipe blake3 '{}'",
|
||||
source_tar_blake3, blake3
|
||||
));
|
||||
}
|
||||
} else {
|
||||
//TODO: set blake3 hash on the recipe with something like "cook fix"
|
||||
eprintln!(
|
||||
"WARNING: set blake3 for '{}' to '{}'",
|
||||
source_tar.display(),
|
||||
source_tar_blake3
|
||||
);
|
||||
}
|
||||
|
||||
// Create source.tmp
|
||||
let source_dir_tmp = recipe_dir.join("source.tmp");
|
||||
create_dir_clean(&source_dir_tmp)?;
|
||||
|
||||
// Extract tar to source.tmp
|
||||
//TODO: use tar crate (how to deal with compression?)
|
||||
let mut command = Command::new("tar");
|
||||
if is_redox() {
|
||||
command.arg("xvf");
|
||||
} else {
|
||||
command.arg("--extract");
|
||||
command.arg("--verbose");
|
||||
command.arg("--file");
|
||||
}
|
||||
command.arg(&source_tar);
|
||||
command.arg("--directory").arg(&source_dir_tmp);
|
||||
command.arg("--strip-components").arg("1");
|
||||
run_command(command)?;
|
||||
|
||||
// Apply patches
|
||||
for patch_name in patches {
|
||||
let patch_file = recipe_dir.join(patch_name);
|
||||
if !patch_file.is_file() {
|
||||
return Err(format!(
|
||||
"failed to find patch file '{}'",
|
||||
patch_file.display()
|
||||
));
|
||||
}
|
||||
|
||||
let patch = fs::read_to_string(&patch_file).map_err(|err| {
|
||||
format!(
|
||||
"failed to read patch file '{}': {}\n{:#?}",
|
||||
patch_file.display(),
|
||||
err,
|
||||
err
|
||||
)
|
||||
})?;
|
||||
|
||||
let mut command = Command::new("patch");
|
||||
command.arg("--directory").arg(&source_dir_tmp);
|
||||
command.arg("--strip=1");
|
||||
run_command_stdin(command, patch.as_bytes())?;
|
||||
}
|
||||
|
||||
// Run source script
|
||||
if let Some(script) = script {
|
||||
let mut command = Command::new("bash");
|
||||
command.arg("-ex");
|
||||
command.current_dir(&source_dir_tmp);
|
||||
run_command_stdin(command, format!("{SHARED_PRESCRIPT}\n{script}").as_bytes())?;
|
||||
}
|
||||
|
||||
// Move source.tmp to source atomically
|
||||
rename(&source_dir_tmp, &source_dir)?;
|
||||
}
|
||||
}
|
||||
// Local Sources
|
||||
None => {
|
||||
if !source_dir.is_dir() {
|
||||
eprintln!(
|
||||
"WARNING: Recipe without source section expected source dir at '{}'",
|
||||
source_dir.display(),
|
||||
);
|
||||
create_dir(&source_dir)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(source_dir)
|
||||
}
|
||||
use cookbook::{WALK_DEPTH, is_redox};
|
||||
|
||||
fn auto_deps(
|
||||
stage_dir: &Path,
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
use cookbook::WALK_DEPTH;
|
||||
use pkg::{recipes, Package, PackageName};
|
||||
use pkg::{Package, PackageName, recipes};
|
||||
use std::collections::{BTreeMap, HashMap};
|
||||
use std::env;
|
||||
use std::fs::{self, File};
|
||||
|
||||
@ -21,3 +21,11 @@ pub fn blake3_progress<P: AsRef<Path>>(path: P) -> Result<String> {
|
||||
|
||||
Ok(res)
|
||||
}
|
||||
|
||||
pub fn blake3_silent<P: AsRef<Path>>(path: P) -> Result<String> {
|
||||
let mut f = fs::File::open(&path)?;
|
||||
|
||||
let hash = Hasher::new().update_reader(&mut f)?.finalize();
|
||||
let res = format!("{}", hash.to_hex());
|
||||
Ok(res)
|
||||
}
|
||||
|
||||
6
src/cook.rs
Normal file
6
src/cook.rs
Normal file
@ -0,0 +1,6 @@
|
||||
pub mod fetch;
|
||||
pub mod fs;
|
||||
pub mod script;
|
||||
//TODO: Move rest of cook functions here in the next refactor
|
||||
//pub mod build;
|
||||
//pub mod package;
|
||||
429
src/cook/fetch.rs
Normal file
429
src/cook/fetch.rs
Normal file
@ -0,0 +1,429 @@
|
||||
use crate::config::translate_mirror;
|
||||
use crate::cook::fs::*;
|
||||
use crate::cook::script::*;
|
||||
use crate::is_redox;
|
||||
use crate::recipe::Recipe;
|
||||
use crate::{blake3, recipe::SourceRecipe};
|
||||
use std::fs;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::process::Command;
|
||||
|
||||
pub(crate) fn get_blake3(path: &PathBuf, show_progress: bool) -> Result<String, String> {
|
||||
if show_progress {
|
||||
blake3::blake3_progress(&path)
|
||||
} else {
|
||||
blake3::blake3_silent(&path)
|
||||
}
|
||||
.map_err(|err| {
|
||||
format!(
|
||||
"failed to calculate blake3 of '{}': {}\n{:?}",
|
||||
path.display(),
|
||||
err,
|
||||
err
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
pub fn fetch_offline(recipe_dir: &Path, source: &Option<SourceRecipe>) -> Result<PathBuf, String> {
|
||||
let source_dir = recipe_dir.join("source");
|
||||
match source {
|
||||
Some(SourceRecipe::Path { path: _ }) | None => {
|
||||
return fetch(recipe_dir, source);
|
||||
}
|
||||
Some(SourceRecipe::SameAs { same_as: _ }) => {
|
||||
return fetch(recipe_dir, source);
|
||||
}
|
||||
Some(SourceRecipe::Git {
|
||||
git: _,
|
||||
upstream: _,
|
||||
branch: _,
|
||||
rev: _,
|
||||
patches: _,
|
||||
script: _,
|
||||
shallow_clone: _,
|
||||
}) => {
|
||||
if !source_dir.is_dir() {
|
||||
return Err(format!(
|
||||
"'{dir}' is not exist and unable to continue in offline mode",
|
||||
dir = source_dir.display(),
|
||||
));
|
||||
}
|
||||
}
|
||||
Some(SourceRecipe::Tar {
|
||||
tar: _,
|
||||
blake3,
|
||||
patches,
|
||||
script,
|
||||
}) => {
|
||||
if !source_dir.is_dir() {
|
||||
let source_tar = recipe_dir.join("source.tar");
|
||||
let source_tar_blake3 = get_blake3(&source_tar, true)?;
|
||||
if source_tar.exists() {
|
||||
if let Some(blake3) = blake3 {
|
||||
if source_tar_blake3 != *blake3 {
|
||||
return Err(format!(
|
||||
"The downloaded tar blake3 '{source_tar_blake3}' is not equal to blake3 in recipe.toml."
|
||||
));
|
||||
}
|
||||
fetch_extract_tar(source_tar, &source_dir)?;
|
||||
fetch_apply_patches(recipe_dir, patches, script, &source_dir)?;
|
||||
} else {
|
||||
// need to trust this tar file
|
||||
return Err(format!(
|
||||
"Please add blake3 = \"{source_tar_blake3}\" to '{recipe}'",
|
||||
recipe = recipe_dir.join("recipe.toml").display(),
|
||||
));
|
||||
}
|
||||
} else {
|
||||
return Err(format!(
|
||||
"'{dir}' is not exist and unable to continue in offline mode",
|
||||
dir = source_dir.display(),
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(source_dir)
|
||||
}
|
||||
|
||||
pub fn fetch(recipe_dir: &Path, source: &Option<SourceRecipe>) -> Result<PathBuf, String> {
|
||||
let source_dir = recipe_dir.join("source");
|
||||
match source {
|
||||
Some(SourceRecipe::SameAs { 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)?;
|
||||
}
|
||||
Some(SourceRecipe::Path { path }) => {
|
||||
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!(
|
||||
"Couldn't copy source from {} to {}: {}",
|
||||
path,
|
||||
source_dir.display(),
|
||||
e
|
||||
)
|
||||
})?;
|
||||
}
|
||||
}
|
||||
Some(SourceRecipe::Git {
|
||||
git,
|
||||
upstream,
|
||||
branch,
|
||||
rev,
|
||||
patches,
|
||||
script,
|
||||
shallow_clone,
|
||||
}) => {
|
||||
//TODO: use libgit?
|
||||
let shallow_clone = *shallow_clone == Some(true);
|
||||
if !source_dir.is_dir() {
|
||||
// Create source.tmp
|
||||
let source_dir_tmp = recipe_dir.join("source.tmp");
|
||||
create_dir_clean(&source_dir_tmp)?;
|
||||
|
||||
// Clone the repository to source.tmp
|
||||
let mut command = Command::new("git");
|
||||
command
|
||||
.arg("clone")
|
||||
.arg("--recursive")
|
||||
.arg(translate_mirror(git));
|
||||
if let Some(branch) = branch {
|
||||
command.arg("--branch").arg(branch);
|
||||
}
|
||||
if shallow_clone {
|
||||
command.arg("--depth").arg("1").arg("--shallow-submodules");
|
||||
}
|
||||
command.arg(&source_dir_tmp);
|
||||
run_command(command)?;
|
||||
|
||||
// Move source.tmp to source atomically
|
||||
rename(&source_dir_tmp, &source_dir)?;
|
||||
} else if !shallow_clone {
|
||||
// Don't let this code reset the origin for the cookbook repo
|
||||
let source_git_dir = source_dir.join(".git");
|
||||
if !source_git_dir.is_dir() {
|
||||
return Err(format!(
|
||||
"'{}' is not a git repository, but recipe indicated git source",
|
||||
source_dir.display(),
|
||||
));
|
||||
}
|
||||
|
||||
// Reset origin
|
||||
let mut command = Command::new("git");
|
||||
command.arg("-C").arg(&source_dir);
|
||||
command.arg("remote").arg("set-url").arg("origin").arg(git);
|
||||
run_command(command)?;
|
||||
|
||||
// Fetch origin
|
||||
let mut command = Command::new("git");
|
||||
command.arg("-C").arg(&source_dir);
|
||||
command.arg("fetch").arg("origin");
|
||||
run_command(command)?;
|
||||
}
|
||||
|
||||
if let Some(_upstream) = upstream {
|
||||
//TODO: set upstream URL
|
||||
// git remote set-url upstream "$GIT_UPSTREAM" &> /dev/null ||
|
||||
// git remote add upstream "$GIT_UPSTREAM"
|
||||
// git fetch upstream
|
||||
}
|
||||
|
||||
if let Some(rev) = rev {
|
||||
// Check out specified revision
|
||||
let mut command = Command::new("git");
|
||||
command.arg("-C").arg(&source_dir);
|
||||
command.arg("checkout").arg(rev);
|
||||
run_command(command)?;
|
||||
} else if !shallow_clone && !is_redox() {
|
||||
//TODO: complicated stuff to check and reset branch to origin
|
||||
//TODO: redox can't undestand this (got exit status 1)
|
||||
let mut command = Command::new("bash");
|
||||
command.arg("-c").arg(GIT_RESET_BRANCH);
|
||||
if let Some(branch) = branch {
|
||||
command.env("BRANCH", branch);
|
||||
}
|
||||
command.current_dir(&source_dir);
|
||||
run_command(command)?;
|
||||
}
|
||||
|
||||
if !patches.is_empty() || script.is_some() {
|
||||
// Hard reset
|
||||
let mut command = Command::new("git");
|
||||
command.arg("-C").arg(&source_dir);
|
||||
command.arg("reset").arg("--hard");
|
||||
run_command(command)?;
|
||||
}
|
||||
|
||||
if !shallow_clone {
|
||||
// Sync submodules URL
|
||||
let mut command = Command::new("git");
|
||||
command.arg("-C").arg(&source_dir);
|
||||
command.arg("submodule").arg("sync").arg("--recursive");
|
||||
run_command(command)?;
|
||||
|
||||
// Update submodules
|
||||
let mut command = Command::new("git");
|
||||
command.arg("-C").arg(&source_dir);
|
||||
command
|
||||
.arg("submodule")
|
||||
.arg("update")
|
||||
.arg("--init")
|
||||
.arg("--recursive");
|
||||
run_command(command)?;
|
||||
}
|
||||
|
||||
fetch_apply_patches(recipe_dir, patches, script, &source_dir)?;
|
||||
}
|
||||
Some(SourceRecipe::Tar {
|
||||
tar,
|
||||
blake3,
|
||||
patches,
|
||||
script,
|
||||
}) => {
|
||||
let source_tar = recipe_dir.join("source.tar");
|
||||
let mut tar_updated = false;
|
||||
while {
|
||||
if !source_tar.is_file() {
|
||||
tar_updated = true;
|
||||
//TODO: replace wget
|
||||
if !source_tar.is_file() {
|
||||
let source_tar_tmp = recipe_dir.join("source.tar.tmp");
|
||||
|
||||
let mut command = Command::new("wget");
|
||||
command.arg(translate_mirror(tar));
|
||||
command.arg("--continue").arg("-O").arg(&source_tar_tmp);
|
||||
run_command(command)?;
|
||||
|
||||
// Move source.tar.tmp to source.tar atomically
|
||||
rename(&source_tar_tmp, &source_tar)?;
|
||||
}
|
||||
}
|
||||
let source_tar_blake3 = get_blake3(&source_tar, tar_updated)?;
|
||||
if let Some(blake3) = blake3 {
|
||||
if source_tar_blake3 != *blake3 {
|
||||
if tar_updated {
|
||||
return Err(format!(
|
||||
"The downloaded tar blake3 '{source_tar_blake3}' is not equal to blake3 in recipe.toml"
|
||||
));
|
||||
} else {
|
||||
eprintln!("DEBUG: source tar blake3 is different and need redownload");
|
||||
remove_all(&source_tar)?;
|
||||
}
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
} else {
|
||||
//TODO: set blake3 hash on the recipe with something like "cook fix"
|
||||
eprintln!(
|
||||
"WARNING: set blake3 for '{}' to '{}'",
|
||||
source_tar.display(),
|
||||
source_tar_blake3
|
||||
);
|
||||
false
|
||||
}
|
||||
} {}
|
||||
if source_dir.is_dir() {
|
||||
if tar_updated || fetch_is_patches_newer(recipe_dir, patches, &source_dir)? {
|
||||
eprintln!("DEBUG: source tar or patches is newer than the source directory");
|
||||
remove_all(&source_dir)?
|
||||
}
|
||||
}
|
||||
if !source_dir.is_dir() {
|
||||
// Create source.tmp
|
||||
let source_dir_tmp = recipe_dir.join("source.tmp");
|
||||
create_dir_clean(&source_dir_tmp)?;
|
||||
fetch_extract_tar(source_tar, &source_dir_tmp)?;
|
||||
fetch_apply_patches(recipe_dir, patches, script, &source_dir_tmp)?;
|
||||
|
||||
// Move source.tmp to source atomically
|
||||
rename(&source_dir_tmp, &source_dir)?;
|
||||
}
|
||||
}
|
||||
// Local Sources
|
||||
None => {
|
||||
if !source_dir.is_dir() {
|
||||
eprintln!(
|
||||
"WARNING: Recipe without source section expected source dir at '{}'",
|
||||
source_dir.display(),
|
||||
);
|
||||
create_dir(&source_dir)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(source_dir)
|
||||
}
|
||||
|
||||
pub(crate) fn fetch_make_symlink(source_dir: &PathBuf, same_as: &String) -> Result<(), String> {
|
||||
let target_dir = Path::new(same_as).join("source");
|
||||
if !source_dir.is_symlink() {
|
||||
if source_dir.is_dir() {
|
||||
return Err(format!(
|
||||
"'{dir}' is a directory, but recipe indicated a symlink. \n\
|
||||
try removing '{dir}' if you haven't made any changes that would be lost",
|
||||
dir = source_dir.display(),
|
||||
));
|
||||
}
|
||||
std::os::unix::fs::symlink(&target_dir, source_dir).map_err(|err| {
|
||||
format!(
|
||||
"failed to symlink '{}' to '{}': {}\n{:?}",
|
||||
target_dir.display(),
|
||||
source_dir.display(),
|
||||
err,
|
||||
err
|
||||
)
|
||||
})?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn fetch_resolve_canon(
|
||||
recipe_dir: &Path,
|
||||
same_as: &String,
|
||||
) -> Result<(PathBuf, Recipe), String> {
|
||||
let canon_dir = Path::new(recipe_dir).join(same_as);
|
||||
if canon_dir
|
||||
.to_str()
|
||||
.unwrap()
|
||||
.chars()
|
||||
.filter(|c| *c == '/')
|
||||
.count()
|
||||
> 50
|
||||
{
|
||||
return Err(format!("Infinite loop detected"));
|
||||
}
|
||||
if !canon_dir.exists() {
|
||||
return Err(format!("'{dir}' is not exists.", dir = canon_dir.display()));
|
||||
}
|
||||
let recipe_path = canon_dir.join("recipe.toml");
|
||||
let recipe_str = fs::read_to_string(&recipe_path)
|
||||
.map_err(|e| format!("unable to read {path}: {e}", path = recipe_path.display()))?;
|
||||
let recipe: Recipe = toml::from_str(&recipe_str)
|
||||
.map_err(|e| format!("Unable to parse {path}: {e}", path = recipe_path.display()))?;
|
||||
Ok((canon_dir, recipe))
|
||||
}
|
||||
|
||||
pub(crate) fn fetch_extract_tar(
|
||||
source_tar: PathBuf,
|
||||
source_dir_tmp: &PathBuf,
|
||||
) -> Result<(), String> {
|
||||
let mut command = Command::new("tar");
|
||||
if is_redox() {
|
||||
command.arg("xvf");
|
||||
} else {
|
||||
command.arg("--extract");
|
||||
command.arg("--verbose");
|
||||
command.arg("--file");
|
||||
}
|
||||
command.arg(&source_tar);
|
||||
command.arg("--directory").arg(source_dir_tmp);
|
||||
command.arg("--strip-components").arg("1");
|
||||
run_command(command)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn fetch_is_patches_newer(
|
||||
recipe_dir: &Path,
|
||||
patches: &Vec<String>,
|
||||
source_dir: &PathBuf,
|
||||
) -> Result<bool, String> {
|
||||
// don't check source files inside as it can be mixed with user patches
|
||||
let source_time = modified(&source_dir)?;
|
||||
for patch_name in patches {
|
||||
let patch_file = recipe_dir.join(patch_name);
|
||||
if !patch_file.is_file() {
|
||||
return Err(format!(
|
||||
"failed to find patch file '{}'",
|
||||
patch_file.display()
|
||||
));
|
||||
}
|
||||
|
||||
let patch_time = modified(&patch_file)?;
|
||||
if patch_time > source_time {
|
||||
return Ok(true);
|
||||
}
|
||||
}
|
||||
return Ok(false);
|
||||
}
|
||||
|
||||
pub(crate) fn fetch_apply_patches(
|
||||
recipe_dir: &Path,
|
||||
patches: &Vec<String>,
|
||||
script: &Option<String>,
|
||||
source_dir_tmp: &PathBuf,
|
||||
) -> Result<(), String> {
|
||||
for patch_name in patches {
|
||||
let patch_file = recipe_dir.join(patch_name);
|
||||
if !patch_file.is_file() {
|
||||
return Err(format!(
|
||||
"failed to find patch file '{}'",
|
||||
patch_file.display()
|
||||
));
|
||||
}
|
||||
|
||||
let patch = fs::read_to_string(&patch_file).map_err(|err| {
|
||||
format!(
|
||||
"failed to read patch file '{}': {}\n{:#?}",
|
||||
patch_file.display(),
|
||||
err,
|
||||
err
|
||||
)
|
||||
})?;
|
||||
|
||||
let mut command = Command::new("patch");
|
||||
command.arg("--directory").arg(source_dir_tmp);
|
||||
command.arg("--strip=1");
|
||||
run_command_stdin(command, patch.as_bytes())?;
|
||||
}
|
||||
Ok(if let Some(script) = script {
|
||||
let mut command = Command::new("bash");
|
||||
command.arg("-ex");
|
||||
command.current_dir(source_dir_tmp);
|
||||
run_command_stdin(command, format!("{SHARED_PRESCRIPT}\n{script}").as_bytes())?;
|
||||
})
|
||||
}
|
||||
194
src/cook/fs.rs
Normal file
194
src/cook/fs.rs
Normal file
@ -0,0 +1,194 @@
|
||||
use serde::Serialize;
|
||||
use std::{
|
||||
fs,
|
||||
io::{self, Write},
|
||||
path::Path,
|
||||
process::{self, Stdio},
|
||||
time::SystemTime,
|
||||
};
|
||||
use walkdir::{DirEntry, WalkDir};
|
||||
|
||||
//TODO: pub(crate) for all of these functions
|
||||
|
||||
pub fn remove_all(path: &Path) -> Result<(), String> {
|
||||
if path.is_dir() {
|
||||
fs::remove_dir_all(path)
|
||||
} else {
|
||||
fs::remove_file(path)
|
||||
}
|
||||
.map_err(|err| format!("failed to remove '{}': {}\n{:?}", path.display(), err, err))
|
||||
}
|
||||
|
||||
pub fn create_dir(dir: &Path) -> Result<(), String> {
|
||||
fs::create_dir(dir)
|
||||
.map_err(|err| format!("failed to create '{}': {}\n{:?}", dir.display(), err, err))
|
||||
}
|
||||
|
||||
pub fn create_dir_clean(dir: &Path) -> Result<(), String> {
|
||||
if dir.is_dir() {
|
||||
remove_all(dir)?;
|
||||
}
|
||||
create_dir(dir)
|
||||
}
|
||||
|
||||
pub fn copy_dir_all(src: impl AsRef<Path>, dst: impl AsRef<Path>) -> io::Result<()> {
|
||||
fs::create_dir_all(&dst)?;
|
||||
for entry in fs::read_dir(src)? {
|
||||
let entry = entry?;
|
||||
let ty = entry.file_type()?;
|
||||
if ty.is_dir() {
|
||||
copy_dir_all(entry.path(), dst.as_ref().join(entry.file_name()))?;
|
||||
} else {
|
||||
fs::copy(entry.path(), dst.as_ref().join(entry.file_name()))?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn symlink(original: impl AsRef<Path>, link: impl AsRef<Path>) -> Result<(), String> {
|
||||
std::os::unix::fs::symlink(&original, &link).map_err(|err| {
|
||||
format!(
|
||||
"failed to symlink '{}' to '{}': {}\n{:?}",
|
||||
original.as_ref().display(),
|
||||
link.as_ref().display(),
|
||||
err,
|
||||
err
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
pub fn modified(path: &Path) -> Result<SystemTime, String> {
|
||||
let metadata = fs::metadata(path).map_err(|err| {
|
||||
format!(
|
||||
"failed to get metadata of '{}': {}\n{:#?}",
|
||||
path.display(),
|
||||
err,
|
||||
err
|
||||
)
|
||||
})?;
|
||||
metadata.modified().map_err(|err| {
|
||||
format!(
|
||||
"failed to get modified time of '{}': {}\n{:#?}",
|
||||
path.display(),
|
||||
err,
|
||||
err
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
pub fn modified_dir_inner<F: FnMut(&DirEntry) -> bool>(
|
||||
dir: &Path,
|
||||
filter: F,
|
||||
) -> io::Result<SystemTime> {
|
||||
let mut newest = fs::metadata(dir)?.modified()?;
|
||||
for entry_res in WalkDir::new(dir).into_iter().filter_entry(filter) {
|
||||
let entry = entry_res?;
|
||||
let modified = entry.metadata()?.modified()?;
|
||||
if modified > newest {
|
||||
newest = modified;
|
||||
}
|
||||
}
|
||||
Ok(newest)
|
||||
}
|
||||
|
||||
pub fn modified_dir(dir: &Path) -> Result<SystemTime, String> {
|
||||
modified_dir_inner(dir, |_| true).map_err(|err| {
|
||||
format!(
|
||||
"failed to get modified time of '{}': {}\n{:#?}",
|
||||
dir.display(),
|
||||
err,
|
||||
err
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
pub fn modified_dir_ignore_git(dir: &Path) -> Result<SystemTime, String> {
|
||||
modified_dir_inner(dir, |entry| {
|
||||
entry
|
||||
.file_name()
|
||||
.to_str()
|
||||
.map(|s| s != ".git")
|
||||
.unwrap_or(true)
|
||||
})
|
||||
.map_err(|err| {
|
||||
format!(
|
||||
"failed to get modified time of '{}': {}\n{:#?}",
|
||||
dir.display(),
|
||||
err,
|
||||
err
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
pub fn rename(src: &Path, dst: &Path) -> Result<(), String> {
|
||||
fs::rename(src, dst).map_err(|err| {
|
||||
format!(
|
||||
"failed to rename '{}' to '{}': {}\n{:?}",
|
||||
src.display(),
|
||||
dst.display(),
|
||||
err,
|
||||
err
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
pub fn run_command(mut command: process::Command) -> Result<(), String> {
|
||||
let status = command
|
||||
.status()
|
||||
.map_err(|err| format!("failed to run {:?}: {}\n{:#?}", command, err, err))?;
|
||||
|
||||
if !status.success() {
|
||||
return Err(format!(
|
||||
"failed to run {:?}: exited with status {}",
|
||||
command, status
|
||||
));
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn run_command_stdin(mut command: process::Command, stdin_data: &[u8]) -> Result<(), String> {
|
||||
command.stdin(Stdio::piped());
|
||||
|
||||
let mut child = command
|
||||
.spawn()
|
||||
.map_err(|err| format!("failed to spawn {:?}: {}\n{:#?}", command, err, err))?;
|
||||
|
||||
if let Some(ref mut stdin) = child.stdin {
|
||||
stdin.write_all(stdin_data).map_err(|err| {
|
||||
format!(
|
||||
"failed to write stdin of {:?}: {}\n{:#?}",
|
||||
command, err, err
|
||||
)
|
||||
})?;
|
||||
} else {
|
||||
return Err(format!("failed to find stdin of {:?}", command));
|
||||
}
|
||||
|
||||
let status = child
|
||||
.wait()
|
||||
.map_err(|err| format!("failed to run {:?}: {}\n{:#?}", command, err, err))?;
|
||||
|
||||
if !status.success() {
|
||||
return Err(format!(
|
||||
"failed to run {:?}: exited with status {}",
|
||||
command, status
|
||||
));
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn serialize_and_write<T: Serialize>(file_path: &Path, content: &T) -> Result<(), String> {
|
||||
let toml_content = toml::to_string(content).map_err(|err| {
|
||||
format!(
|
||||
"Failed to serialize content for '{}': {}",
|
||||
file_path.display(),
|
||||
err
|
||||
)
|
||||
})?;
|
||||
|
||||
fs::write(file_path, toml_content)
|
||||
.map_err(|err| format!("Failed to write to file '{}': {}", file_path.display(), err))?;
|
||||
Ok(())
|
||||
}
|
||||
91
src/cook/script.rs
Normal file
91
src/cook/script.rs
Normal file
@ -0,0 +1,91 @@
|
||||
//TODO: pub(crate)
|
||||
pub static SHARED_PRESCRIPT: &str = r#"
|
||||
# Build dynamically
|
||||
function DYNAMIC_INIT {
|
||||
COOKBOOK_AUTORECONF="autoreconf"
|
||||
autotools_recursive_regenerate() {
|
||||
for f in $(find . -name configure.ac -o -name configure.in -type f | sort); do
|
||||
echo "* autotools regen in '$(dirname $f)'..."
|
||||
( cd "$(dirname "$f")" && "${COOKBOOK_AUTORECONF}" -fvi "$@" -I${COOKBOOK_HOST_SYSROOT}/share/aclocal )
|
||||
done
|
||||
}
|
||||
|
||||
if [ "${TARGET}" != "x86_64-unknown-redox" ]
|
||||
then
|
||||
echo "WARN: ${TARGET} does not support dynamic linking." >&2
|
||||
return
|
||||
fi
|
||||
|
||||
echo "DEBUG: Program is being compiled dynamically."
|
||||
|
||||
COOKBOOK_CONFIGURE_FLAGS=(
|
||||
--host="${GNU_TARGET}"
|
||||
--prefix="/usr"
|
||||
--enable-shared
|
||||
--disable-static
|
||||
)
|
||||
|
||||
COOKBOOK_CMAKE_FLAGS=(
|
||||
-DBUILD_SHARED_LIBS=True
|
||||
-DENABLE_SHARED=True
|
||||
-DENABLE_STATIC=False
|
||||
)
|
||||
|
||||
COOKBOOK_MESON_FLAGS=(
|
||||
--buildtype release
|
||||
--wrap-mode nofallback
|
||||
--strip
|
||||
-Ddefault_library=shared
|
||||
-Dprefix=/usr
|
||||
)
|
||||
|
||||
# TODO: check paths for spaces
|
||||
export LDFLAGS="-Wl,-rpath-link,${COOKBOOK_SYSROOT}/lib -L${COOKBOOK_SYSROOT}/lib"
|
||||
export RUSTFLAGS="-C target-feature=-crt-static"
|
||||
export COOKBOOK_DYNAMIC=1
|
||||
}
|
||||
|
||||
# Build both dynamically and statically
|
||||
function DYNAMIC_STATIC_INIT {
|
||||
DYNAMIC_INIT
|
||||
if [ "${COOKBOOK_DYNAMIC}" == "1" ]
|
||||
then
|
||||
COOKBOOK_CONFIGURE_FLAGS=(
|
||||
--host="${GNU_TARGET}"
|
||||
--prefix="/usr"
|
||||
--enable-shared
|
||||
--enable-static
|
||||
)
|
||||
|
||||
COOKBOOK_CMAKE_FLAGS=(
|
||||
-DBUILD_SHARED_LIBS=True
|
||||
-DENABLE_SHARED=True
|
||||
-DENABLE_STATIC=True
|
||||
)
|
||||
|
||||
COOKBOOK_MESON_FLAGS=(
|
||||
--buildtype release
|
||||
--wrap-mode nofallback
|
||||
--strip
|
||||
-Ddefault_library=both
|
||||
-Dprefix=/usr
|
||||
)
|
||||
fi
|
||||
}
|
||||
|
||||
function GNU_CONFIG_GET {
|
||||
wget -O "$1" "https://gitlab.redox-os.org/redox-os/gnu-config/-/raw/master/config.sub?inline=false"
|
||||
}
|
||||
"#;
|
||||
|
||||
pub(crate) static GIT_RESET_BRANCH: &str = r#"
|
||||
ORIGIN_BRANCH="$(git branch --remotes | grep '^ origin/HEAD -> ' | cut -d ' ' -f 5-)"
|
||||
if [ -n "$BRANCH" ]
|
||||
then
|
||||
ORIGIN_BRANCH="origin/$BRANCH"
|
||||
fi
|
||||
|
||||
if [ "$(git rev-parse HEAD)" != "$(git rev-parse $ORIGIN_BRANCH)" ]
|
||||
then
|
||||
git checkout -B "$(echo "$ORIGIN_BRANCH" | cut -d / -f 2-)" "$ORIGIN_BRANCH"
|
||||
fi"#;
|
||||
@ -1,5 +1,6 @@
|
||||
pub mod blake3;
|
||||
pub mod config;
|
||||
pub mod cook;
|
||||
pub mod recipe;
|
||||
|
||||
mod progress_bar;
|
||||
|
||||
@ -1,10 +1,10 @@
|
||||
use std::{collections::BTreeSet, convert::TryInto, fs, path::PathBuf};
|
||||
|
||||
use pkg::{package::PackageError, recipes, PackageName};
|
||||
use pkg::{PackageName, package::PackageError, recipes};
|
||||
use regex::Regex;
|
||||
use serde::{
|
||||
de::{value::Error as DeError, Error as DeErrorT},
|
||||
Deserialize, Serialize,
|
||||
de::{Error as DeErrorT, value::Error as DeError},
|
||||
};
|
||||
|
||||
use crate::WALK_DEPTH;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user