mirror of
https://jturnerusa.dev/cgit/gentoo-utils/
synced 2025-12-03 03:28:35 -06:00
Compare commits
47 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d1127df296 | ||
|
|
94f3397d19 | ||
|
|
f0ffe5cb2b | ||
|
|
327d871c16 | ||
|
|
7b60034425 | ||
|
|
558e213ab4 | ||
|
|
ee5b3c8166 | ||
|
|
86e2b4559a | ||
|
|
5be1e5c37a | ||
|
|
f8149b43d4 | ||
|
|
bffc1e88b0 | ||
|
|
ffa1a05fc1 | ||
|
|
ac1eb15ea7 | ||
|
|
de9fd0fbd9 | ||
|
|
9062881692 | ||
|
|
e9603ce62f | ||
|
|
bd0fec80f9 | ||
|
|
c06360aed6 | ||
|
|
64065b753b | ||
|
|
9eaf25f8c8 | ||
|
|
fb69d82e6f | ||
|
|
bf56ed1c61 | ||
|
|
3bce987993 | ||
|
|
360a44d608 | ||
|
|
699d4bafd0 | ||
|
|
ff7d9b312f | ||
|
|
ad8a4b838b | ||
|
|
0d40608404 | ||
|
|
8d3cf7c83d | ||
|
|
16fdd27e9a | ||
|
|
70e8ea24a8 | ||
|
|
e01637fd3a | ||
|
|
e0cc7f6a03 | ||
|
|
c75a38f615 | ||
|
|
2dc5df6112 | ||
|
|
e2cc948803 | ||
|
|
920ec36141 | ||
|
|
2d0a91eb18 | ||
|
|
46c3c075d1 | ||
|
|
78398b7ebe | ||
|
|
db02762ee1 | ||
|
|
d4fd6cd211 | ||
|
|
34362dcb29 | ||
|
|
dc47258841 | ||
|
|
63db65b2f0 | ||
|
|
b74471706b | ||
|
|
0cc3ac8e84 |
2
Cargo.lock
generated
2
Cargo.lock
generated
@@ -40,7 +40,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "mon"
|
name = "mon"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://jturnerusa.dev/cgit/mon/?rev=34d8eeb989012b0f20041b11a60ced24ca702527#34d8eeb989012b0f20041b11a60ced24ca702527"
|
source = "git+https://jturnerusa.dev/cgit/mon/?rev=67861a4df8a5abdd70651d47cf265b20c41d2acc#67861a4df8a5abdd70651d47cf265b20c41d2acc"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proc-macro2"
|
name = "proc-macro2"
|
||||||
|
|||||||
13
Cargo.toml
13
Cargo.toml
@@ -4,18 +4,7 @@ version = "0.1.0"
|
|||||||
edition = "2024"
|
edition = "2024"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
mon = { git = "https://jturnerusa.dev/cgit/mon/", rev = "34d8eeb989012b0f20041b11a60ced24ca702527" }
|
mon = { git = "https://jturnerusa.dev/cgit/mon/", rev = "67861a4df8a5abdd70651d47cf265b20c41d2acc" }
|
||||||
get = { git = "https://jturnerusa.dev/cgit/get/", rev = "cd5f75b65777a855ab010c3137304ac05f2e56b8" }
|
get = { git = "https://jturnerusa.dev/cgit/get/", rev = "cd5f75b65777a855ab010c3137304ac05f2e56b8" }
|
||||||
itertools = "0.14.0"
|
itertools = "0.14.0"
|
||||||
thiserror = "2.0.17"
|
thiserror = "2.0.17"
|
||||||
|
|
||||||
[profile.dev]
|
|
||||||
debug = true
|
|
||||||
|
|
||||||
[[bin]]
|
|
||||||
path = "fuzz/gencorpus.rs"
|
|
||||||
name = "gencorpus"
|
|
||||||
|
|
||||||
[[test]]
|
|
||||||
path = "fuzz/fuzz.rs"
|
|
||||||
name = "fuzz"
|
|
||||||
30
check.sh
30
check.sh
@@ -1,26 +1,20 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
source /etc/profile
|
source /etc/profile
|
||||||
|
source /lib/gentoo/functions.sh
|
||||||
|
|
||||||
export CC=clang CXX=clang++
|
export PATH="${HOME}/.local/bin:${PATH}" CC=clang CXX=clang++
|
||||||
|
|
||||||
cargo fmt --check || exit $?
|
ldd=$(command -v ldd)
|
||||||
|
|
||||||
cargo clippy || exit $?
|
if [[ -n ${ldd} ]]; then
|
||||||
|
export LDFLAGS=-fuse-ld=${ldd}
|
||||||
|
fi
|
||||||
|
|
||||||
cargo test -r || exit $?
|
if [[ ! -d build ]]; then
|
||||||
|
meson setup -Dfuzz=enabled -Dtests=enabled build || exit $?
|
||||||
|
fi
|
||||||
|
|
||||||
cargo build --all --all-features || exit $?
|
ebegin "running check commands"
|
||||||
|
parallel --halt soon,fail=1 --keep-order -j$(nproc) < check_commands.txt
|
||||||
build=$(mktemp -d)
|
eend $? || exit $?
|
||||||
|
|
||||||
meson setup ${build} || exit $?
|
|
||||||
|
|
||||||
meson compile -C ${build} || exit $?
|
|
||||||
|
|
||||||
meson test -C ${build} || exit $?
|
|
||||||
|
|
||||||
rm -rf ${build}
|
|
||||||
|
|
||||||
# hack to make sure we use the system meson, since meson format from git is broken
|
|
||||||
/usr/bin/meson format --recursive --check-only || exit $?
|
|
||||||
|
|||||||
4
check_commands.txt
Normal file
4
check_commands.txt
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
/usr/bin/meson format --recursive --check-only
|
||||||
|
rustfmt --edition 2024 --check $(find src -type f -name '*.rs')
|
||||||
|
ninja clippy -C build
|
||||||
|
meson test unittests '*repo*' '*porthole*' '*profile*' -C build
|
||||||
2
fuzz/atom/meson.build
Normal file
2
fuzz/atom/meson.build
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
subdir('parser')
|
||||||
|
subdir('vercmp')
|
||||||
100
fuzz/atom/parser/fuzz.rs
Normal file
100
fuzz/atom/parser/fuzz.rs
Normal file
@@ -0,0 +1,100 @@
|
|||||||
|
use core::slice;
|
||||||
|
use gentoo_utils::{Parseable, atom::Atom};
|
||||||
|
use mon::{Parser, ParserFinishedError, input::InputIter};
|
||||||
|
use std::{
|
||||||
|
io::{BufRead, BufReader, Write},
|
||||||
|
process::{ChildStdin, ChildStdout, Command, Stdio},
|
||||||
|
sync::{LazyLock, Mutex},
|
||||||
|
};
|
||||||
|
|
||||||
|
struct PyProcess {
|
||||||
|
stdin: Mutex<ChildStdin>,
|
||||||
|
stdout: Mutex<BufReader<ChildStdout>>,
|
||||||
|
buffer: Mutex<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::missing_safety_doc, clippy::needless_return)]
|
||||||
|
#[unsafe(no_mangle)]
|
||||||
|
pub unsafe extern "C" fn LLVMFuzzerTestOneInput(input: *const u8, len: usize) -> i32 {
|
||||||
|
static PY_PROCESS: LazyLock<PyProcess> = LazyLock::new(|| {
|
||||||
|
#[allow(clippy::zombie_processes)]
|
||||||
|
let mut proc = Command::new("atom.py")
|
||||||
|
.stdin(Stdio::piped())
|
||||||
|
.stdout(Stdio::piped())
|
||||||
|
.stderr(Stdio::inherit())
|
||||||
|
.spawn()
|
||||||
|
.expect("failed to spawn atom.py");
|
||||||
|
|
||||||
|
let stdin = Mutex::new(proc.stdin.take().unwrap());
|
||||||
|
let stdout = Mutex::new(BufReader::new(proc.stdout.take().unwrap()));
|
||||||
|
|
||||||
|
PyProcess {
|
||||||
|
stdin,
|
||||||
|
stdout,
|
||||||
|
buffer: Mutex::new(String::new()),
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
let slice = unsafe { slice::from_raw_parts(input, len) };
|
||||||
|
|
||||||
|
if slice.iter().any(|b| !b.is_ascii_graphic()) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
let str = match str::from_utf8(slice) {
|
||||||
|
Ok(str) => str,
|
||||||
|
Err(_) => return -1,
|
||||||
|
};
|
||||||
|
|
||||||
|
let atom = str.trim();
|
||||||
|
|
||||||
|
let mut stdin = PY_PROCESS.stdin.lock().expect("failed to get stdin lock");
|
||||||
|
|
||||||
|
writeln!(&mut stdin, "{atom}").expect("failed to write to python stdin");
|
||||||
|
|
||||||
|
let mut stdout = PY_PROCESS.stdout.lock().expect("failed to get stdout lock");
|
||||||
|
|
||||||
|
let mut buffer = PY_PROCESS.buffer.lock().expect("failed to get buffer lock");
|
||||||
|
|
||||||
|
buffer.clear();
|
||||||
|
|
||||||
|
stdout
|
||||||
|
.read_line(&mut buffer)
|
||||||
|
.expect("failed to readline from python");
|
||||||
|
|
||||||
|
let portage_result = match buffer.as_str().trim() {
|
||||||
|
"0" => true,
|
||||||
|
"1" => false,
|
||||||
|
result => panic!("got unexpected result from python: {result}"),
|
||||||
|
};
|
||||||
|
|
||||||
|
let gentoo_utils_result = Atom::parser().parse_finished(InputIter::new(atom));
|
||||||
|
|
||||||
|
match (portage_result, gentoo_utils_result) {
|
||||||
|
(true, Ok(_)) => {
|
||||||
|
eprintln!("agreement that {atom} is valid");
|
||||||
|
}
|
||||||
|
(false, Err(_)) => {
|
||||||
|
eprintln!("agreement that {atom} is invalid");
|
||||||
|
}
|
||||||
|
(true, Err(ParserFinishedError::Err(it) | ParserFinishedError::Unfinished(it))) => {
|
||||||
|
panic!("rejected valid atom: {atom}: {}", it.rest());
|
||||||
|
}
|
||||||
|
(false, Ok(atom))
|
||||||
|
if atom.usedeps().iter().any(|usedep| {
|
||||||
|
atom.usedeps()
|
||||||
|
.iter()
|
||||||
|
.filter(|u| usedep.flag() == u.flag())
|
||||||
|
.count()
|
||||||
|
> 1
|
||||||
|
}) =>
|
||||||
|
{
|
||||||
|
eprintln!("disagreement due to duplicates in usedeps");
|
||||||
|
}
|
||||||
|
(false, Ok(_)) => {
|
||||||
|
panic!("accpeted invalid atom: {atom}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -8,7 +8,7 @@ use std::{
|
|||||||
|
|
||||||
use gentoo_utils::{
|
use gentoo_utils::{
|
||||||
atom::Atom,
|
atom::Atom,
|
||||||
ebuild::{Depend, repo::Repo},
|
repo::{Repo, ebuild::Depend},
|
||||||
};
|
};
|
||||||
|
|
||||||
fn main() -> Result<(), Box<dyn Error>> {
|
fn main() -> Result<(), Box<dyn Error>> {
|
||||||
6
fuzz/atom/parser/meson.build
Normal file
6
fuzz/atom/parser/meson.build
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
fuzzers += {
|
||||||
|
'atom_parser': [
|
||||||
|
meson.current_source_dir() / 'gencorpus.rs',
|
||||||
|
meson.current_source_dir() / 'fuzz.rs',
|
||||||
|
],
|
||||||
|
}
|
||||||
114
fuzz/atom/vercmp/fuzz.rs
Normal file
114
fuzz/atom/vercmp/fuzz.rs
Normal file
@@ -0,0 +1,114 @@
|
|||||||
|
use core::slice;
|
||||||
|
use gentoo_utils::{
|
||||||
|
Parseable,
|
||||||
|
atom::{Atom, Version},
|
||||||
|
};
|
||||||
|
use mon::{Parser, ParserFinishedError, input::InputIter};
|
||||||
|
use std::{
|
||||||
|
cmp::Ordering,
|
||||||
|
io::{BufRead, BufReader, Write},
|
||||||
|
process::{ChildStdin, ChildStdout, Command, Stdio},
|
||||||
|
sync::{LazyLock, Mutex},
|
||||||
|
};
|
||||||
|
|
||||||
|
struct PyProcess {
|
||||||
|
stdin: Mutex<ChildStdin>,
|
||||||
|
stdout: Mutex<BufReader<ChildStdout>>,
|
||||||
|
buffer: Mutex<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::missing_safety_doc, clippy::needless_return)]
|
||||||
|
#[unsafe(no_mangle)]
|
||||||
|
pub unsafe extern "C" fn LLVMFuzzerTestOneInput(input: *const u8, len: usize) -> i32 {
|
||||||
|
static PY_PROCESS: LazyLock<PyProcess> = LazyLock::new(|| {
|
||||||
|
#[allow(clippy::zombie_processes)]
|
||||||
|
let mut proc = Command::new("vercmp.py")
|
||||||
|
.stdin(Stdio::piped())
|
||||||
|
.stdout(Stdio::piped())
|
||||||
|
.stderr(Stdio::inherit())
|
||||||
|
.spawn()
|
||||||
|
.expect("failed to spawn vercmp.py");
|
||||||
|
|
||||||
|
let stdin = Mutex::new(proc.stdin.take().unwrap());
|
||||||
|
let stdout = Mutex::new(BufReader::new(proc.stdout.take().unwrap()));
|
||||||
|
|
||||||
|
PyProcess {
|
||||||
|
stdin,
|
||||||
|
stdout,
|
||||||
|
buffer: Mutex::new(String::new()),
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
let control = Version::parser()
|
||||||
|
.parse_finished(InputIter::new("1.2.0a_alpha1_beta2-r1"))
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let slice = unsafe { slice::from_raw_parts(input, len) };
|
||||||
|
|
||||||
|
if slice.iter().any(|b| !b.is_ascii_graphic()) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
let str = match str::from_utf8(slice) {
|
||||||
|
Ok(str) => str,
|
||||||
|
Err(_) => return -1,
|
||||||
|
};
|
||||||
|
|
||||||
|
let version_str = match str.split_ascii_whitespace().next() {
|
||||||
|
Some(lhs) => lhs,
|
||||||
|
None => return -1,
|
||||||
|
};
|
||||||
|
|
||||||
|
let version = match Version::parser().parse_finished(InputIter::new(version_str)) {
|
||||||
|
Ok(a) => a,
|
||||||
|
Err(_) => return -1,
|
||||||
|
};
|
||||||
|
|
||||||
|
if version.build_id().is_some() {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
let gentoo_utils = control.cmp(&version);
|
||||||
|
|
||||||
|
let portage_result = portage_vercmp(&PY_PROCESS, &control, &version);
|
||||||
|
|
||||||
|
match portage_result {
|
||||||
|
Ok(portage) if portage == gentoo_utils => {
|
||||||
|
eprintln!("agreement on {control} cmp {version} == {portage:?}");
|
||||||
|
}
|
||||||
|
Ok(portage) => {
|
||||||
|
panic!(
|
||||||
|
"disagreement on {control} == {version}:\nportage:{portage:?} gentoo_utils:{gentoo_utils:?}"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Err(_) => {
|
||||||
|
panic!("parsed invalid versions: {control} | {version}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn portage_vercmp(pyproc: &PyProcess, a: &Version, b: &Version) -> Result<Ordering, ()> {
|
||||||
|
let mut stdin = pyproc.stdin.lock().expect("failed to get stdin lock");
|
||||||
|
let mut stdout = pyproc.stdout.lock().expect("failed to get stdout lock");
|
||||||
|
let mut buffer = pyproc.buffer.lock().expect("failed to get buffer lock");
|
||||||
|
|
||||||
|
writeln!(&mut stdin, "{a} {b}").expect("failed to write line to python process");
|
||||||
|
|
||||||
|
stdin.flush().unwrap();
|
||||||
|
|
||||||
|
buffer.clear();
|
||||||
|
|
||||||
|
stdout
|
||||||
|
.read_line(&mut buffer)
|
||||||
|
.expect("failed to read line from python process");
|
||||||
|
|
||||||
|
match buffer.as_str().trim() {
|
||||||
|
"0" => Ok(Ordering::Equal),
|
||||||
|
"1" => Ok(Ordering::Greater),
|
||||||
|
"-1" => Ok(Ordering::Less),
|
||||||
|
"err" => Err(()),
|
||||||
|
other => panic!("unexpected result from python: {other}"),
|
||||||
|
}
|
||||||
|
}
|
||||||
43
fuzz/atom/vercmp/gencorpus.rs
Normal file
43
fuzz/atom/vercmp/gencorpus.rs
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
use std::{
|
||||||
|
env,
|
||||||
|
error::Error,
|
||||||
|
fs::{self, OpenOptions},
|
||||||
|
io::Write,
|
||||||
|
path::PathBuf,
|
||||||
|
};
|
||||||
|
|
||||||
|
use gentoo_utils::repo::Repo;
|
||||||
|
|
||||||
|
fn main() -> Result<(), Box<dyn Error>> {
|
||||||
|
let corpus_dir = PathBuf::from(
|
||||||
|
env::args()
|
||||||
|
.nth(1)
|
||||||
|
.expect("expected corpus directory as first argument"),
|
||||||
|
);
|
||||||
|
|
||||||
|
fs::create_dir_all(&corpus_dir)?;
|
||||||
|
|
||||||
|
let repo = Repo::new("/var/db/repos/gentoo");
|
||||||
|
let mut versions = Vec::new();
|
||||||
|
|
||||||
|
for category in repo.categories()? {
|
||||||
|
for ebuild in category?.ebuilds()? {
|
||||||
|
let version = ebuild?.version().clone();
|
||||||
|
|
||||||
|
versions.push(version);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i, version) in versions.iter().enumerate() {
|
||||||
|
let path = corpus_dir.as_path().join(i.to_string());
|
||||||
|
let mut file = OpenOptions::new()
|
||||||
|
.write(true)
|
||||||
|
.truncate(true)
|
||||||
|
.create(true)
|
||||||
|
.open(path)?;
|
||||||
|
|
||||||
|
write!(file, "{version}")?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
6
fuzz/atom/vercmp/meson.build
Normal file
6
fuzz/atom/vercmp/meson.build
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
fuzzers += {
|
||||||
|
'atom_vercmp': [
|
||||||
|
meson.current_source_dir() / 'gencorpus.rs',
|
||||||
|
meson.current_source_dir() / 'fuzz.rs',
|
||||||
|
],
|
||||||
|
}
|
||||||
50
fuzz/fuzz.rs
50
fuzz/fuzz.rs
@@ -1,50 +0,0 @@
|
|||||||
use core::slice;
|
|
||||||
use gentoo_utils::{Parseable, atom::Atom};
|
|
||||||
use mon::{Parser, ParserFinishedError, input::InputIter};
|
|
||||||
use std::{
|
|
||||||
io::Write,
|
|
||||||
process::{Command, Stdio},
|
|
||||||
};
|
|
||||||
|
|
||||||
#[allow(clippy::missing_safety_doc, clippy::needless_return)]
|
|
||||||
#[unsafe(no_mangle)]
|
|
||||||
pub unsafe extern "C" fn LLVMFuzzerTestOneInput(input: *const u8, len: usize) -> i32 {
|
|
||||||
let slice = unsafe { slice::from_raw_parts(input, len) };
|
|
||||||
|
|
||||||
let atom = match str::from_utf8(slice) {
|
|
||||||
Ok(str) => str.trim(),
|
|
||||||
_ => return -1,
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut proc = Command::new("atom.py")
|
|
||||||
.stdin(Stdio::piped())
|
|
||||||
.spawn()
|
|
||||||
.expect("failed to start atom.py");
|
|
||||||
|
|
||||||
proc.stdin
|
|
||||||
.as_mut()
|
|
||||||
.unwrap()
|
|
||||||
.write_all(atom.as_bytes())
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
let status = proc.wait().unwrap();
|
|
||||||
|
|
||||||
let result = Atom::parser().check_finished(InputIter::new(atom));
|
|
||||||
|
|
||||||
match (status.success(), result) {
|
|
||||||
(true, Ok(_)) => {
|
|
||||||
eprintln!("agreement that {atom} is valid");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
(true, Err(ParserFinishedError::Err(it) | ParserFinishedError::Unfinished(it))) => {
|
|
||||||
panic!("gentoo-utils rejected valid atom: {atom}: {}", it.rest());
|
|
||||||
}
|
|
||||||
(false, Err(_)) => {
|
|
||||||
eprintln!("agreement that {atom} is invalid");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
(false, Ok(_)) => {
|
|
||||||
panic!("gentoo-utils accepted invalid atom: {atom}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,30 +1,38 @@
|
|||||||
cbindgen = find_program('cbindgen')
|
cbindgen = find_program('cbindgen')
|
||||||
|
|
||||||
gencorpus = executable(
|
fuzzers = {}
|
||||||
'gencorpus',
|
|
||||||
'gencorpus.rs',
|
subdir('atom')
|
||||||
|
|
||||||
|
foreach fuzzer, sources : fuzzers
|
||||||
|
gencorpus_rs = sources[0]
|
||||||
|
fuzz_rs = sources[1]
|
||||||
|
|
||||||
|
gencorpus = executable(
|
||||||
|
fuzzer + '_' + 'gencorpus',
|
||||||
|
gencorpus_rs,
|
||||||
dependencies: [mon],
|
dependencies: [mon],
|
||||||
link_with: [gentoo_utils],
|
link_with: [gentoo_utils],
|
||||||
)
|
)
|
||||||
|
|
||||||
corpus_directory = meson.current_build_dir() / 'corpus'
|
corpus_directory = fuzzer + '_' + 'corpus'
|
||||||
|
|
||||||
corpus = custom_target(
|
corpus = custom_target(
|
||||||
'corpus',
|
fuzzer + '_' + 'corpus',
|
||||||
output: 'corpus',
|
output: fuzzer + '_' + 'corpus',
|
||||||
command: [gencorpus, corpus_directory],
|
command: [gencorpus, corpus_directory],
|
||||||
)
|
)
|
||||||
|
|
||||||
fuzz_h = custom_target(
|
fuzz_h = custom_target(
|
||||||
'fuzz_h',
|
fuzzer + '_' + 'fuzz_h',
|
||||||
input: 'fuzz.rs',
|
input: fuzz_rs,
|
||||||
output: 'fuzz.h',
|
output: fuzzer + '_' + 'fuzz.h',
|
||||||
command: [cbindgen, '@INPUT@', '-o', '@OUTPUT'],
|
command: [cbindgen, '@INPUT@', '-o', '@OUTPUT'],
|
||||||
)
|
)
|
||||||
|
|
||||||
fuzz_rs = static_library(
|
fuzz_rs = static_library(
|
||||||
'fuzz_rs',
|
fuzzer + '.rs',
|
||||||
'fuzz.rs',
|
fuzz_rs,
|
||||||
rust_abi: 'c',
|
rust_abi: 'c',
|
||||||
rust_args: [
|
rust_args: [
|
||||||
'-Cpasses=sancov-module',
|
'-Cpasses=sancov-module',
|
||||||
@@ -33,8 +41,19 @@ fuzz_rs = static_library(
|
|||||||
],
|
],
|
||||||
dependencies: [mon],
|
dependencies: [mon],
|
||||||
link_with: [gentoo_utils],
|
link_with: [gentoo_utils],
|
||||||
)
|
)
|
||||||
|
|
||||||
fuzz = executable('fuzz', link_args: ['-fsanitize=fuzzer'], link_with: [fuzz_rs])
|
fuzz = executable(
|
||||||
|
fuzzer + '_' + 'fuzzer',
|
||||||
|
link_args: ['-fsanitize=fuzzer'],
|
||||||
|
link_with: [fuzz_rs],
|
||||||
|
)
|
||||||
|
|
||||||
test('fuzz', fuzz, args: [corpus_directory], depends: [corpus], timeout: 0)
|
test(
|
||||||
|
fuzzer + '_' + 'fuzz',
|
||||||
|
fuzz,
|
||||||
|
args: [corpus_directory],
|
||||||
|
depends: [corpus],
|
||||||
|
timeout: 0,
|
||||||
|
)
|
||||||
|
endforeach
|
||||||
|
|||||||
@@ -20,6 +20,11 @@ gentoo_utils = static_library(
|
|||||||
link_with: [thiserror],
|
link_with: [thiserror],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if get_option('tests').enabled()
|
||||||
|
rust.test('unittests', gentoo_utils)
|
||||||
|
subdir('tests')
|
||||||
|
endif
|
||||||
|
|
||||||
if get_option('fuzz').enabled()
|
if get_option('fuzz').enabled()
|
||||||
subdir('fuzz')
|
subdir('fuzz')
|
||||||
endif
|
endif
|
||||||
|
|||||||
@@ -1 +1,2 @@
|
|||||||
option('fuzz', type: 'feature', value: 'disabled')
|
option('fuzz', type: 'feature', value: 'disabled')
|
||||||
|
option('tests', type: 'feature', value: 'disabled')
|
||||||
@@ -1,13 +1,13 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
import portage.dep as dep
|
from portage.dep import Atom
|
||||||
|
|
||||||
input = sys.stdin.read().strip()
|
for line in sys.stdin.buffer:
|
||||||
|
try:
|
||||||
try:
|
Atom(line.decode().strip())
|
||||||
dep.Atom(input)
|
sys.stdout.buffer.write(b"0\n")
|
||||||
except Exception as e:
|
except:
|
||||||
sys.exit(1)
|
sys.stdout.buffer.write(b"1\n")
|
||||||
|
finally:
|
||||||
sys.exit(0)
|
sys.stdout.buffer.flush()
|
||||||
|
|||||||
14
scripts/vercmp.py
Executable file
14
scripts/vercmp.py
Executable file
@@ -0,0 +1,14 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import portage
|
||||||
|
|
||||||
|
for line in sys.stdin.buffer:
|
||||||
|
a, b = line.decode().split(" ")
|
||||||
|
|
||||||
|
try:
|
||||||
|
sys.stdout.buffer.write(f"{portage.vercmp(a, b)}\n".encode())
|
||||||
|
except:
|
||||||
|
sys.stdout.buffer.write(b"err\n")
|
||||||
|
finally:
|
||||||
|
sys.stdout.buffer.flush()
|
||||||
332
src/atom/mod.rs
332
src/atom/mod.rs
@@ -10,15 +10,15 @@ use get::Get;
|
|||||||
|
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
|
|
||||||
pub mod parsers;
|
mod parsers;
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||||
pub enum Blocker {
|
pub enum Blocker {
|
||||||
Weak,
|
Weak,
|
||||||
Strong,
|
Strong,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||||
pub enum VersionOperator {
|
pub enum VersionOperator {
|
||||||
Lt,
|
Lt,
|
||||||
Gt,
|
Gt,
|
||||||
@@ -28,19 +28,19 @@ pub enum VersionOperator {
|
|||||||
Roughly,
|
Roughly,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Get)]
|
#[derive(Clone, Debug, PartialEq, Eq, Hash, Get)]
|
||||||
pub struct Category(#[get(method = "get", kind = "deref")] String);
|
pub struct Category(#[get(method = "get", kind = "deref")] String);
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Get)]
|
#[derive(Clone, Debug, PartialEq, Eq, Hash, Get)]
|
||||||
pub struct Name(#[get(method = "get", kind = "deref")] String);
|
pub struct Name(#[get(method = "get", kind = "deref")] String);
|
||||||
|
|
||||||
#[derive(Clone, Debug, Get)]
|
#[derive(Clone, Debug, PartialEq, Eq, Hash, Get)]
|
||||||
pub struct VersionNumber(#[get(method = "get", kind = "deref")] String);
|
pub struct VersionNumber(#[get(method = "get", kind = "deref")] String);
|
||||||
|
|
||||||
#[derive(Debug, Clone, Get)]
|
#[derive(Debug, Clone, PartialEq, Eq, Hash, Get)]
|
||||||
struct VersionNumbers(#[get(method = "get", kind = "deref")] Vec<VersionNumber>);
|
struct VersionNumbers(#[get(method = "get", kind = "deref")] Vec<VersionNumber>);
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||||
pub enum VersionSuffixKind {
|
pub enum VersionSuffixKind {
|
||||||
Alpha,
|
Alpha,
|
||||||
Beta,
|
Beta,
|
||||||
@@ -49,58 +49,75 @@ pub enum VersionSuffixKind {
|
|||||||
P,
|
P,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Get)]
|
#[derive(Clone, Debug, Hash, PartialEq, Eq, Get)]
|
||||||
pub struct VersionSuffix {
|
pub struct VersionSuffix {
|
||||||
kind: VersionSuffixKind,
|
kind: VersionSuffixKind,
|
||||||
number: Option<VersionNumber>,
|
number: Option<VersionNumber>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Get)]
|
#[derive(Debug, Clone, PartialEq, Eq, Hash, Get)]
|
||||||
pub struct VersionSuffixes(#[get(method = "get", kind = "deref")] Vec<VersionSuffix>);
|
pub struct VersionSuffixes(#[get(method = "get", kind = "deref")] Vec<VersionSuffix>);
|
||||||
|
|
||||||
#[derive(Clone, Debug, Get)]
|
#[derive(Debug, Clone, Get, PartialEq, Eq, Hash)]
|
||||||
|
pub struct BuildId(#[get(method = "get", kind = "deref")] String);
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq, Eq, Hash, Get)]
|
||||||
pub struct Version {
|
pub struct Version {
|
||||||
numbers: VersionNumbers,
|
numbers: VersionNumbers,
|
||||||
letter: Option<char>,
|
letter: Option<char>,
|
||||||
suffixes: VersionSuffixes,
|
suffixes: VersionSuffixes,
|
||||||
rev: Option<VersionNumber>,
|
rev: Option<VersionNumber>,
|
||||||
|
build_id: Option<BuildId>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||||
|
pub struct Wildcard;
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||||
pub enum SlotOperator {
|
pub enum SlotOperator {
|
||||||
Eq,
|
Eq,
|
||||||
Star,
|
Star,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Get)]
|
#[derive(Clone, Debug, PartialEq, Eq, Hash, Get)]
|
||||||
pub struct SlotName(#[get(method = "name", kind = "deref")] String);
|
pub struct SlotName(#[get(method = "name", kind = "deref")] String);
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Get)]
|
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
pub struct Slot {
|
pub enum Slot {
|
||||||
primary: Option<SlotName>,
|
Wildcard,
|
||||||
|
Equal,
|
||||||
|
NameEqual {
|
||||||
|
primary: SlotName,
|
||||||
sub: Option<SlotName>,
|
sub: Option<SlotName>,
|
||||||
operator: Option<SlotOperator>,
|
},
|
||||||
|
Name {
|
||||||
|
primary: SlotName,
|
||||||
|
sub: Option<SlotName>,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||||
pub enum UseDepNegate {
|
pub enum UseDepNegate {
|
||||||
Minus,
|
Minus,
|
||||||
Exclamation,
|
Exclamation,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||||
pub enum UseDepSign {
|
pub enum UseDepSign {
|
||||||
Enabled,
|
Enabled,
|
||||||
Disabled,
|
Disabled,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||||
pub enum UseDepCondition {
|
pub enum UseDepCondition {
|
||||||
Eq,
|
Eq,
|
||||||
Question,
|
Question,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Get)]
|
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
|
pub struct Repo(String);
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq, Eq, Hash, Get)]
|
||||||
pub struct UseDep {
|
pub struct UseDep {
|
||||||
negate: Option<UseDepNegate>,
|
negate: Option<UseDepNegate>,
|
||||||
flag: UseFlag,
|
flag: UseFlag,
|
||||||
@@ -108,13 +125,13 @@ pub struct UseDep {
|
|||||||
condition: Option<UseDepCondition>,
|
condition: Option<UseDepCondition>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Get)]
|
#[derive(Clone, Debug, PartialEq, Eq, Hash, Get)]
|
||||||
pub struct Cp {
|
pub struct Cp {
|
||||||
category: Category,
|
category: Category,
|
||||||
name: Name,
|
name: Name,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Get)]
|
#[derive(Clone, Debug, PartialEq, Eq, Hash, Get)]
|
||||||
pub struct Cpv {
|
pub struct Cpv {
|
||||||
category: Category,
|
category: Category,
|
||||||
name: Name,
|
name: Name,
|
||||||
@@ -122,13 +139,14 @@ pub struct Cpv {
|
|||||||
slot: Option<Slot>,
|
slot: Option<Slot>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Get, PartialEq, Eq)]
|
#[derive(Clone, Debug, Get, PartialEq, Eq, Hash)]
|
||||||
pub struct Atom {
|
pub struct Atom {
|
||||||
blocker: Option<Blocker>,
|
blocker: Option<Blocker>,
|
||||||
category: Category,
|
category: Category,
|
||||||
name: Name,
|
name: Name,
|
||||||
version: Option<(VersionOperator, Version)>,
|
version: Option<(VersionOperator, Version, Option<Wildcard>)>,
|
||||||
slot: Option<Slot>,
|
slot: Option<Slot>,
|
||||||
|
repo: Option<Repo>,
|
||||||
#[get(kind = "deref")]
|
#[get(kind = "deref")]
|
||||||
usedeps: Vec<UseDep>,
|
usedeps: Vec<UseDep>,
|
||||||
}
|
}
|
||||||
@@ -146,7 +164,7 @@ impl Cpv {
|
|||||||
impl Atom {
|
impl Atom {
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn version_operator(&self) -> Option<VersionOperator> {
|
pub fn version_operator(&self) -> Option<VersionOperator> {
|
||||||
self.version.clone().map(|(oper, _)| oper)
|
self.version.clone().map(|(oper, _, _)| oper)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
@@ -160,7 +178,7 @@ impl Atom {
|
|||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn into_cpv(self) -> Option<Cpv> {
|
pub fn into_cpv(self) -> Option<Cpv> {
|
||||||
match self.version {
|
match self.version {
|
||||||
Some((_, version)) => Some(Cpv {
|
Some((_, version, _)) => Some(Cpv {
|
||||||
category: self.category,
|
category: self.category,
|
||||||
name: self.name,
|
name: self.name,
|
||||||
version,
|
version,
|
||||||
@@ -171,20 +189,43 @@ impl Atom {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PartialEq for VersionSuffix {
|
impl VersionNumber {
|
||||||
fn eq(&self, other: &Self) -> bool {
|
#[must_use]
|
||||||
self.kind == other.kind
|
pub fn cmp_as_ints(&self, other: &Self) -> Ordering {
|
||||||
&& match (&self.number, &other.number) {
|
let a = self.get().trim_start_matches('0');
|
||||||
(Some(a), Some(b)) => a.0 == b.0,
|
let b = other.get().trim_start_matches('0');
|
||||||
(Some(a), None) if a.get().chars().all(|c| c == '0') => true,
|
|
||||||
(None, Some(b)) if b.get().chars().all(|c| c == '0') => true,
|
a.len().cmp(&b.len()).then_with(|| a.cmp(b))
|
||||||
(Some(_), None) | (None, Some(_)) => false,
|
}
|
||||||
(None, None) => true,
|
|
||||||
|
#[must_use]
|
||||||
|
pub fn cmp_as_str(&self, other: &Self) -> Ordering {
|
||||||
|
if self.get().starts_with('0') || other.get().starts_with('0') {
|
||||||
|
let a = self.get().trim_end_matches('0');
|
||||||
|
let b = other.get().trim_end_matches('0');
|
||||||
|
|
||||||
|
a.cmp(b)
|
||||||
|
} else {
|
||||||
|
self.cmp_as_ints(other)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Eq for VersionSuffix {}
|
impl PartialOrd for BuildId {
|
||||||
|
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||||
|
Some(self.cmp(other))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Ord for BuildId {
|
||||||
|
fn cmp(&self, other: &Self) -> Ordering {
|
||||||
|
// build-id may not start with a zero so we dont need to strip them
|
||||||
|
self.get()
|
||||||
|
.len()
|
||||||
|
.cmp(&other.get().len())
|
||||||
|
.then_with(|| self.get().cmp(other.get()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl PartialOrd for VersionSuffix {
|
impl PartialOrd for VersionSuffix {
|
||||||
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
|
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
|
||||||
@@ -198,11 +239,7 @@ impl Ord for VersionSuffix {
|
|||||||
Ordering::Less => Ordering::Less,
|
Ordering::Less => Ordering::Less,
|
||||||
Ordering::Greater => Ordering::Greater,
|
Ordering::Greater => Ordering::Greater,
|
||||||
Ordering::Equal => match (&self.number, &other.number) {
|
Ordering::Equal => match (&self.number, &other.number) {
|
||||||
(Some(a), Some(b)) => {
|
(Some(a), Some(b)) => a.cmp_as_ints(b),
|
||||||
a.0.parse::<u64>()
|
|
||||||
.unwrap()
|
|
||||||
.cmp(&b.0.parse::<u64>().unwrap())
|
|
||||||
}
|
|
||||||
(Some(a), None) if a.get().chars().all(|c| c == '0') => Ordering::Equal,
|
(Some(a), None) if a.get().chars().all(|c| c == '0') => Ordering::Equal,
|
||||||
(None, Some(b)) if b.get().chars().all(|c| c == '0') => Ordering::Equal,
|
(None, Some(b)) if b.get().chars().all(|c| c == '0') => Ordering::Equal,
|
||||||
(Some(_), None) => Ordering::Greater,
|
(Some(_), None) => Ordering::Greater,
|
||||||
@@ -213,23 +250,6 @@ impl Ord for VersionSuffix {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PartialEq for VersionSuffixes {
|
|
||||||
fn eq(&self, other: &Self) -> bool {
|
|
||||||
let mut a = self.get().iter();
|
|
||||||
let mut b = other.get().iter();
|
|
||||||
|
|
||||||
loop {
|
|
||||||
match (a.next(), b.next()) {
|
|
||||||
(Some(a), Some(b)) if a == b => (),
|
|
||||||
(Some(_) | None, Some(_)) | (Some(_), None) => break false,
|
|
||||||
(None, None) => break true,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Eq for VersionSuffixes {}
|
|
||||||
|
|
||||||
impl PartialOrd for VersionSuffixes {
|
impl PartialOrd for VersionSuffixes {
|
||||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||||
Some(self.cmp(other))
|
Some(self.cmp(other))
|
||||||
@@ -260,41 +280,6 @@ impl Ord for VersionSuffixes {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PartialEq for VersionNumbers {
|
|
||||||
fn eq(&self, other: &Self) -> bool {
|
|
||||||
self.get().first().unwrap().get().parse::<u64>().unwrap()
|
|
||||||
== other.get().first().unwrap().get().parse().unwrap()
|
|
||||||
&& {
|
|
||||||
let mut a = self.get().iter().skip(1);
|
|
||||||
let mut b = other.get().iter().skip(1);
|
|
||||||
|
|
||||||
loop {
|
|
||||||
match (a.next(), b.next()) {
|
|
||||||
(Some(a), Some(b)) if a.get().starts_with('0') => {
|
|
||||||
let a = a.get().trim_end_matches('0');
|
|
||||||
let b = b.get().trim_end_matches('0');
|
|
||||||
|
|
||||||
if a != b {
|
|
||||||
break false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
(Some(a), Some(b)) => {
|
|
||||||
if a.get().parse::<u64>().unwrap() != b.get().parse::<u64>().unwrap() {
|
|
||||||
break false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
(Some(a), None) if a.get().chars().all(|c| c == '0') => (),
|
|
||||||
(None, Some(b)) if b.get().chars().all(|c| c == '0') => (),
|
|
||||||
(None, None) => break true,
|
|
||||||
_ => break false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Eq for VersionNumbers {}
|
|
||||||
|
|
||||||
impl PartialOrd for VersionNumbers {
|
impl PartialOrd for VersionNumbers {
|
||||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||||
Some(self.cmp(other))
|
Some(self.cmp(other))
|
||||||
@@ -307,10 +292,7 @@ impl Ord for VersionNumbers {
|
|||||||
.get()
|
.get()
|
||||||
.first()
|
.first()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.get()
|
.cmp_as_ints(other.get().first().unwrap())
|
||||||
.parse::<u64>()
|
|
||||||
.unwrap()
|
|
||||||
.cmp(&other.get().first().unwrap().get().parse::<u64>().unwrap())
|
|
||||||
{
|
{
|
||||||
Ordering::Less => Ordering::Less,
|
Ordering::Less => Ordering::Less,
|
||||||
Ordering::Greater => Ordering::Greater,
|
Ordering::Greater => Ordering::Greater,
|
||||||
@@ -320,24 +302,7 @@ impl Ord for VersionNumbers {
|
|||||||
|
|
||||||
loop {
|
loop {
|
||||||
match (a.next(), b.next()) {
|
match (a.next(), b.next()) {
|
||||||
(Some(a), Some(b))
|
(Some(a), Some(b)) => match a.cmp_as_str(b) {
|
||||||
if a.get().starts_with('0') || b.get().starts_with('0') =>
|
|
||||||
{
|
|
||||||
let a = a.get().trim_end_matches('0');
|
|
||||||
let b = b.get().trim_end_matches('0');
|
|
||||||
|
|
||||||
match a.cmp(b) {
|
|
||||||
Ordering::Less => break Ordering::Less,
|
|
||||||
Ordering::Greater => break Ordering::Greater,
|
|
||||||
Ordering::Equal => (),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
(Some(a), Some(b)) => match a
|
|
||||||
.get()
|
|
||||||
.parse::<u64>()
|
|
||||||
.unwrap()
|
|
||||||
.cmp(&b.get().parse::<u64>().unwrap())
|
|
||||||
{
|
|
||||||
Ordering::Less => break Ordering::Less,
|
Ordering::Less => break Ordering::Less,
|
||||||
Ordering::Greater => break Ordering::Greater,
|
Ordering::Greater => break Ordering::Greater,
|
||||||
Ordering::Equal => (),
|
Ordering::Equal => (),
|
||||||
@@ -353,25 +318,6 @@ impl Ord for VersionNumbers {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PartialEq for Version {
|
|
||||||
fn eq(&self, other: &Self) -> bool {
|
|
||||||
self.numbers == other.numbers
|
|
||||||
&& self.suffixes == other.suffixes
|
|
||||||
&& self.letter == other.letter
|
|
||||||
&& match (&self.rev, &other.rev) {
|
|
||||||
(Some(a), Some(b)) => {
|
|
||||||
a.get().parse::<u64>().unwrap() == b.get().parse::<u64>().unwrap()
|
|
||||||
}
|
|
||||||
(Some(a), None) if a.get().chars().all(|c| c == '0') => true,
|
|
||||||
(None, Some(b)) if b.get().chars().all(|c| c == '0') => true,
|
|
||||||
(Some(_), None) | (None, Some(_)) => false,
|
|
||||||
(None, None) => true,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Eq for Version {}
|
|
||||||
|
|
||||||
impl PartialOrd for Version {
|
impl PartialOrd for Version {
|
||||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||||
Some(self.cmp(other))
|
Some(self.cmp(other))
|
||||||
@@ -386,12 +332,6 @@ impl Ord for Version {
|
|||||||
Ordering::Equal => (),
|
Ordering::Equal => (),
|
||||||
}
|
}
|
||||||
|
|
||||||
match self.suffixes.cmp(&other.suffixes) {
|
|
||||||
Ordering::Less => return Ordering::Less,
|
|
||||||
Ordering::Greater => return Ordering::Greater,
|
|
||||||
Ordering::Equal => (),
|
|
||||||
}
|
|
||||||
|
|
||||||
match (self.letter, other.letter) {
|
match (self.letter, other.letter) {
|
||||||
(Some(a), Some(b)) if a < b => return Ordering::Less,
|
(Some(a), Some(b)) if a < b => return Ordering::Less,
|
||||||
(Some(a), Some(b)) if a > b => return Ordering::Greater,
|
(Some(a), Some(b)) if a > b => return Ordering::Greater,
|
||||||
@@ -402,15 +342,28 @@ impl Ord for Version {
|
|||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
match self.suffixes.cmp(&other.suffixes) {
|
||||||
|
Ordering::Less => return Ordering::Less,
|
||||||
|
Ordering::Greater => return Ordering::Greater,
|
||||||
|
Ordering::Equal => (),
|
||||||
|
}
|
||||||
|
|
||||||
match (&self.rev, &other.rev) {
|
match (&self.rev, &other.rev) {
|
||||||
(Some(a), Some(b)) => a
|
(Some(a), Some(b)) => match a.cmp_as_ints(b) {
|
||||||
.get()
|
Ordering::Less => return Ordering::Less,
|
||||||
.parse::<u64>()
|
Ordering::Greater => return Ordering::Greater,
|
||||||
.unwrap()
|
Ordering::Equal => (),
|
||||||
.cmp(&b.get().parse().unwrap()),
|
},
|
||||||
(Some(a), None) if a.get().chars().all(|c| c == '0') => Ordering::Equal,
|
(Some(a), None) if a.get().chars().all(|c| c == '0') => (),
|
||||||
|
(Some(_), None) => return Ordering::Greater,
|
||||||
|
(None, Some(b)) if b.get().chars().all(|c| c == '0') => (),
|
||||||
|
(None, Some(_)) => return Ordering::Less,
|
||||||
|
(None, None) => (),
|
||||||
|
}
|
||||||
|
|
||||||
|
match (&self.build_id, &other.build_id) {
|
||||||
|
(Some(a), Some(b)) => a.cmp(b),
|
||||||
(Some(_), None) => Ordering::Greater,
|
(Some(_), None) => Ordering::Greater,
|
||||||
(None, Some(b)) if b.get().chars().all(|c| c == '0') => Ordering::Equal,
|
|
||||||
(None, Some(_)) => Ordering::Less,
|
(None, Some(_)) => Ordering::Less,
|
||||||
(None, None) => Ordering::Equal,
|
(None, None) => Ordering::Equal,
|
||||||
}
|
}
|
||||||
@@ -467,6 +420,12 @@ impl fmt::Display for VersionNumber {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for BuildId {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
write!(f, "{}", self.get())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl fmt::Display for VersionSuffixKind {
|
impl fmt::Display for VersionSuffixKind {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
@@ -523,6 +482,10 @@ impl fmt::Display for Version {
|
|||||||
write!(f, "-r{rev}")?;
|
write!(f, "-r{rev}")?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let Some(build_id) = self.build_id.as_ref() {
|
||||||
|
write!(f, "-{build_id}")?;
|
||||||
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -544,20 +507,31 @@ impl fmt::Display for SlotName {
|
|||||||
|
|
||||||
impl fmt::Display for Slot {
|
impl fmt::Display for Slot {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
if let Some(slot) = self.primary.as_ref() {
|
match self {
|
||||||
write!(f, "{slot}")?;
|
Self::Wildcard => write!(f, "*"),
|
||||||
|
Self::Equal => {
|
||||||
|
write!(f, "=")
|
||||||
}
|
}
|
||||||
|
Self::NameEqual { primary, sub } => {
|
||||||
|
write!(f, "{primary}")?;
|
||||||
|
|
||||||
if let Some(sub) = self.sub.as_ref() {
|
if let Some(sub) = sub {
|
||||||
write!(f, "/{sub}")?;
|
write!(f, "/{sub}")?;
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(operator) = self.operator.as_ref() {
|
write!(f, "=")
|
||||||
write!(f, "{operator}")?;
|
}
|
||||||
|
Self::Name { primary, sub } => {
|
||||||
|
write!(f, "{primary}")?;
|
||||||
|
|
||||||
|
if let Some(sub) = sub {
|
||||||
|
write!(f, "/{sub}")?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for UseDepNegate {
|
impl fmt::Display for UseDepNegate {
|
||||||
@@ -639,8 +613,10 @@ impl fmt::Display for Atom {
|
|||||||
write!(f, "/")?;
|
write!(f, "/")?;
|
||||||
write!(f, "{}", self.name)?;
|
write!(f, "{}", self.name)?;
|
||||||
|
|
||||||
if let Some((_, version)) = self.version.as_ref() {
|
if let Some((_, version, None)) = self.version() {
|
||||||
write!(f, "-{version}")?;
|
write!(f, "-{version}")?;
|
||||||
|
} else if let Some((_, version, Some(_))) = self.version() {
|
||||||
|
write!(f, "-{version}*")?;
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(slot) = self.slot.as_ref() {
|
if let Some(slot) = self.slot.as_ref() {
|
||||||
@@ -710,38 +686,6 @@ mod test {
|
|||||||
assert_eq!(atom.to_string().as_str(), s);
|
assert_eq!(atom.to_string().as_str(), s);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_version_suffix_eq() {
|
|
||||||
let a = VersionSuffix::parser()
|
|
||||||
.parse_finished(InputIter::new("alpha0"))
|
|
||||||
.unwrap();
|
|
||||||
let b = VersionSuffix::parser()
|
|
||||||
.parse_finished(InputIter::new("alpha"))
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
assert_eq_display!(a, b);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_version_eq() {
|
|
||||||
let versions = [
|
|
||||||
("1", "1"),
|
|
||||||
("1", "1.0.0"),
|
|
||||||
("1.0", "1.0.0"),
|
|
||||||
("1.0.0_alpha0", "1.0.0_alpha"),
|
|
||||||
("1.0.0", "1.0.0-r0"),
|
|
||||||
];
|
|
||||||
|
|
||||||
for (a, b) in versions.map(|(a, b)| {
|
|
||||||
(
|
|
||||||
Version::parser().parse_finished(InputIter::new(a)).unwrap(),
|
|
||||||
Version::parser().parse_finished(InputIter::new(b)).unwrap(),
|
|
||||||
)
|
|
||||||
}) {
|
|
||||||
assert_eq_display!(a, b);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_version_cmp() {
|
fn test_version_cmp() {
|
||||||
let versions = [
|
let versions = [
|
||||||
@@ -750,6 +694,7 @@ mod test {
|
|||||||
("1.0.0_alpha", "1.0.0_alpha_p", Ordering::Less),
|
("1.0.0_alpha", "1.0.0_alpha_p", Ordering::Less),
|
||||||
("1.0.0-r0", "1.0.0", Ordering::Equal),
|
("1.0.0-r0", "1.0.0", Ordering::Equal),
|
||||||
("1.0.0-r0000", "1.0.0", Ordering::Equal),
|
("1.0.0-r0000", "1.0.0", Ordering::Equal),
|
||||||
|
("1.0.0-r1-1", "1.0.0-r1-2", Ordering::Less),
|
||||||
];
|
];
|
||||||
|
|
||||||
for (a, b, ordering) in versions.iter().map(|(a, b, ordering)| {
|
for (a, b, ordering) in versions.iter().map(|(a, b, ordering)| {
|
||||||
@@ -816,4 +761,19 @@ mod test {
|
|||||||
|
|
||||||
assert_cmp_display!(a, b, Ordering::Greater);
|
assert_cmp_display!(a, b, Ordering::Greater);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_fuzzer_cases() {
|
||||||
|
let control = Version::parser()
|
||||||
|
.parse_finished(InputIter::new("1.2.0a_alpha1_beta2-r1-8"))
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
for (version_str, expected) in [("1.2.0", Ordering::Greater)] {
|
||||||
|
let version = Version::parser()
|
||||||
|
.parse_finished(InputIter::new(version_str))
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
assert_cmp_display!(control, version, expected);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +1,16 @@
|
|||||||
use core::option::Option::None;
|
use core::option::Option::None;
|
||||||
|
|
||||||
use mon::{Parser, ParserIter, alphanumeric, r#if, numeric1, one_of, tag};
|
use mon::{
|
||||||
|
Parser, ParserIter, ascii_alphanumeric, ascii_numeric, ascii_numeric1, eof, r#if,
|
||||||
|
input::InputIter, one_of, tag,
|
||||||
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
Parseable,
|
Parseable,
|
||||||
atom::{
|
atom::{
|
||||||
Atom, Blocker, Category, Cp, Cpv, Name, Slot, SlotName, SlotOperator, UseDep,
|
Atom, Blocker, BuildId, Category, Cp, Cpv, Name, Repo, Slot, SlotName, SlotOperator,
|
||||||
UseDepCondition, UseDepNegate, UseDepSign, Version, VersionNumber, VersionNumbers,
|
UseDep, UseDepCondition, UseDepNegate, UseDepSign, Version, VersionNumber, VersionNumbers,
|
||||||
VersionOperator, VersionSuffix, VersionSuffixKind, VersionSuffixes,
|
VersionOperator, VersionSuffix, VersionSuffixKind, VersionSuffixes, Wildcard,
|
||||||
},
|
},
|
||||||
useflag::UseFlag,
|
useflag::UseFlag,
|
||||||
};
|
};
|
||||||
@@ -40,7 +43,22 @@ impl<'a> Parseable<'a, &'a str> for VersionNumber {
|
|||||||
type Parser = impl Parser<&'a str, Output = Self>;
|
type Parser = impl Parser<&'a str, Output = Self>;
|
||||||
|
|
||||||
fn parser() -> Self::Parser {
|
fn parser() -> Self::Parser {
|
||||||
numeric1().map(|output: &str| VersionNumber(output.to_string()))
|
ascii_numeric1().map(|output: &str| VersionNumber(output.to_string()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Parseable<'a, &'a str> for BuildId {
|
||||||
|
type Parser = impl Parser<&'a str, Output = Self>;
|
||||||
|
|
||||||
|
fn parser() -> Self::Parser {
|
||||||
|
let start = ascii_numeric().and_not(tag("0"));
|
||||||
|
let rest = ascii_numeric().repeated().many();
|
||||||
|
|
||||||
|
start
|
||||||
|
.and(rest)
|
||||||
|
.recognize()
|
||||||
|
.or(tag("0"))
|
||||||
|
.map(|output: &str| BuildId(output.to_string()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -72,9 +90,6 @@ impl<'a> Parseable<'a, &'a str> for VersionNumbers {
|
|||||||
|
|
||||||
fn parser() -> Self::Parser {
|
fn parser() -> Self::Parser {
|
||||||
VersionNumber::parser()
|
VersionNumber::parser()
|
||||||
.followed_by(tag("*").opt())
|
|
||||||
.recognize()
|
|
||||||
.map(|output: &str| VersionNumber(output.to_string()))
|
|
||||||
.separated_by(tag("."))
|
.separated_by(tag("."))
|
||||||
.at_least(1)
|
.at_least(1)
|
||||||
.map(VersionNumbers)
|
.map(VersionNumbers)
|
||||||
@@ -97,16 +112,19 @@ impl<'a> Parseable<'a, &'a str> for Version {
|
|||||||
|
|
||||||
fn parser() -> Self::Parser {
|
fn parser() -> Self::Parser {
|
||||||
let rev = VersionNumber::parser().preceded_by(tag("-r"));
|
let rev = VersionNumber::parser().preceded_by(tag("-r"));
|
||||||
|
let build_id = BuildId::parser().preceded_by(tag("-"));
|
||||||
|
|
||||||
VersionNumbers::parser()
|
VersionNumbers::parser()
|
||||||
.and(r#if(|c: &char| c.is_ascii_alphabetic() && c.is_ascii_lowercase()).opt())
|
.and(r#if(|c: &char| c.is_ascii_alphabetic() && c.is_ascii_lowercase()).opt())
|
||||||
.and(VersionSuffixes::parser().preceded_by(tag("_")).opt())
|
.and(VersionSuffixes::parser().preceded_by(tag("_")).opt())
|
||||||
.and(rev.opt())
|
.and(rev.opt())
|
||||||
.map(|(((numbers, letter), suffixes), rev)| Version {
|
.and(build_id.opt())
|
||||||
|
.map(|((((numbers, letter), suffixes), rev), build_id)| Version {
|
||||||
numbers,
|
numbers,
|
||||||
letter,
|
letter,
|
||||||
suffixes: suffixes.unwrap_or(VersionSuffixes(Vec::new())),
|
suffixes: suffixes.unwrap_or(VersionSuffixes(Vec::new())),
|
||||||
rev,
|
rev,
|
||||||
|
build_id,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -115,8 +133,11 @@ impl<'a> Parseable<'a, &'a str> for Category {
|
|||||||
type Parser = impl Parser<&'a str, Output = Self>;
|
type Parser = impl Parser<&'a str, Output = Self>;
|
||||||
|
|
||||||
fn parser() -> Self::Parser {
|
fn parser() -> Self::Parser {
|
||||||
let start = alphanumeric().or(one_of("_".chars()));
|
let start = ascii_alphanumeric().or(one_of("_".chars()));
|
||||||
let rest = alphanumeric().or(one_of("+_.-".chars())).repeated().many();
|
let rest = ascii_alphanumeric()
|
||||||
|
.or(one_of("+_.-".chars()))
|
||||||
|
.repeated()
|
||||||
|
.many();
|
||||||
|
|
||||||
start
|
start
|
||||||
.and(rest)
|
.and(rest)
|
||||||
@@ -129,21 +150,31 @@ impl<'a> Parseable<'a, &'a str> for Name {
|
|||||||
type Parser = impl Parser<&'a str, Output = Self>;
|
type Parser = impl Parser<&'a str, Output = Self>;
|
||||||
|
|
||||||
fn parser() -> Self::Parser {
|
fn parser() -> Self::Parser {
|
||||||
let start = alphanumeric().or(one_of("_".chars()));
|
let start = || ascii_alphanumeric().or(one_of("_".chars()));
|
||||||
|
|
||||||
let rest = alphanumeric()
|
let rest = ascii_alphanumeric()
|
||||||
.or(one_of("_+".chars()))
|
.or(one_of("_+".chars()))
|
||||||
.or(one_of("-".chars()).and_not(
|
.or(one_of("-".chars()).and_not(
|
||||||
Version::parser()
|
Version::parser()
|
||||||
.preceded_by(tag("-"))
|
.preceded_by(tag("-"))
|
||||||
.followed_by(alphanumeric().or(one_of("_+-".chars())).not()),
|
.followed_by(ascii_alphanumeric().or(one_of("_+-".chars())).not()),
|
||||||
))
|
))
|
||||||
.repeated()
|
.repeated()
|
||||||
.many();
|
.many();
|
||||||
|
|
||||||
start
|
let verify = ascii_alphanumeric()
|
||||||
|
.or(one_of("_+".chars()))
|
||||||
|
.or(one_of("-".chars())
|
||||||
|
.and_not(Version::parser().preceded_by(tag("-")).followed_by(eof())))
|
||||||
|
.repeated()
|
||||||
|
.many();
|
||||||
|
|
||||||
|
start()
|
||||||
.and(rest)
|
.and(rest)
|
||||||
.recognize()
|
.recognize()
|
||||||
|
.verify_output(move |output: &&str| {
|
||||||
|
verify.check_finished(InputIter::new(*output)).is_ok()
|
||||||
|
})
|
||||||
.map(|output: &str| Name(output.to_string()))
|
.map(|output: &str| Name(output.to_string()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -162,8 +193,11 @@ impl<'a> Parseable<'a, &'a str> for SlotName {
|
|||||||
type Parser = impl Parser<&'a str, Output = Self>;
|
type Parser = impl Parser<&'a str, Output = Self>;
|
||||||
|
|
||||||
fn parser() -> Self::Parser {
|
fn parser() -> Self::Parser {
|
||||||
let start = alphanumeric().or(one_of("_".chars()));
|
let start = ascii_alphanumeric().or(one_of("_".chars()));
|
||||||
let rest = alphanumeric().or(one_of("+_.-".chars())).repeated().many();
|
let rest = ascii_alphanumeric()
|
||||||
|
.or(one_of("+_.-".chars()))
|
||||||
|
.repeated()
|
||||||
|
.many();
|
||||||
|
|
||||||
start
|
start
|
||||||
.and(rest)
|
.and(rest)
|
||||||
@@ -176,15 +210,17 @@ impl<'a> Parseable<'a, &'a str> for Slot {
|
|||||||
type Parser = impl Parser<&'a str, Output = Self>;
|
type Parser = impl Parser<&'a str, Output = Self>;
|
||||||
|
|
||||||
fn parser() -> Self::Parser {
|
fn parser() -> Self::Parser {
|
||||||
SlotName::parser()
|
let wildcard = tag("*").map(|_| Slot::Wildcard);
|
||||||
.opt()
|
let equal = tag("=").map(|_| Slot::Equal);
|
||||||
|
let name_equal = SlotName::parser()
|
||||||
.and(SlotName::parser().preceded_by(tag("/")).opt())
|
.and(SlotName::parser().preceded_by(tag("/")).opt())
|
||||||
.and(SlotOperator::parser().opt())
|
.followed_by(tag("="))
|
||||||
.map(|((primary, sub), operator)| Slot {
|
.map(|(primary, sub)| Slot::NameEqual { primary, sub });
|
||||||
primary,
|
let name = SlotName::parser()
|
||||||
sub,
|
.and(SlotName::parser().preceded_by(tag("/")).opt())
|
||||||
operator,
|
.map(|(primary, sub)| Self::Name { primary, sub });
|
||||||
})
|
|
||||||
|
wildcard.or(equal).or(name_equal).or(name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -198,6 +234,28 @@ impl<'a> Parseable<'a, &'a str> for UseDepSign {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'a> Parseable<'a, &'a str> for Repo {
|
||||||
|
type Parser = impl Parser<&'a str, Output = Self>;
|
||||||
|
|
||||||
|
fn parser() -> Self::Parser {
|
||||||
|
let start = ascii_alphanumeric().or(one_of("_".chars()));
|
||||||
|
let rest = ascii_alphanumeric()
|
||||||
|
.or(one_of("_-".chars()))
|
||||||
|
.repeated()
|
||||||
|
.many();
|
||||||
|
|
||||||
|
start
|
||||||
|
.and(rest)
|
||||||
|
.recognize()
|
||||||
|
.verify_output(move |output: &&str| {
|
||||||
|
Name::parser()
|
||||||
|
.check_finished(InputIter::new(*output))
|
||||||
|
.is_ok()
|
||||||
|
})
|
||||||
|
.map(|output: &str| Repo(output.to_string()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'a> Parseable<'a, &'a str> for UseDep {
|
impl<'a> Parseable<'a, &'a str> for UseDep {
|
||||||
type Parser = impl Parser<&'a str, Output = Self>;
|
type Parser = impl Parser<&'a str, Output = Self>;
|
||||||
|
|
||||||
@@ -275,7 +333,7 @@ impl<'a> Parseable<'a, &'a str> for Atom {
|
|||||||
let usedeps = || {
|
let usedeps = || {
|
||||||
UseDep::parser()
|
UseDep::parser()
|
||||||
.separated_by(tag(","))
|
.separated_by(tag(","))
|
||||||
.many()
|
.at_least(1)
|
||||||
.delimited_by(tag("["), tag("]"))
|
.delimited_by(tag("["), tag("]"))
|
||||||
.opt()
|
.opt()
|
||||||
};
|
};
|
||||||
@@ -285,15 +343,19 @@ impl<'a> Parseable<'a, &'a str> for Atom {
|
|||||||
.and(Category::parser())
|
.and(Category::parser())
|
||||||
.and(Name::parser().preceded_by(tag("/")))
|
.and(Name::parser().preceded_by(tag("/")))
|
||||||
.and(Slot::parser().preceded_by(tag(":")).opt())
|
.and(Slot::parser().preceded_by(tag(":")).opt())
|
||||||
|
.and(Repo::parser().preceded_by(tag("::")).opt())
|
||||||
.and(usedeps())
|
.and(usedeps())
|
||||||
.map(|((((blocker, category), name), slot), usedeps)| Atom {
|
.map(
|
||||||
|
|(((((blocker, category), name), slot), repo), usedeps)| Atom {
|
||||||
blocker,
|
blocker,
|
||||||
category,
|
category,
|
||||||
name,
|
name,
|
||||||
version: None,
|
version: None,
|
||||||
slot,
|
slot,
|
||||||
|
repo,
|
||||||
usedeps: usedeps.unwrap_or(Vec::new()),
|
usedeps: usedeps.unwrap_or(Vec::new()),
|
||||||
});
|
},
|
||||||
|
);
|
||||||
|
|
||||||
let with_version = Blocker::parser()
|
let with_version = Blocker::parser()
|
||||||
.opt()
|
.opt()
|
||||||
@@ -301,33 +363,37 @@ impl<'a> Parseable<'a, &'a str> for Atom {
|
|||||||
.and(Category::parser())
|
.and(Category::parser())
|
||||||
.and(Name::parser().preceded_by(tag("/")))
|
.and(Name::parser().preceded_by(tag("/")))
|
||||||
.and(Version::parser().preceded_by(tag("-")))
|
.and(Version::parser().preceded_by(tag("-")))
|
||||||
|
.and(tag("*").map(|_| Wildcard).opt())
|
||||||
.and(Slot::parser().preceded_by(tag(":")).opt())
|
.and(Slot::parser().preceded_by(tag(":")).opt())
|
||||||
|
.and(Repo::parser().preceded_by(tag("::")).opt())
|
||||||
.and(usedeps())
|
.and(usedeps())
|
||||||
|
.verify_output(
|
||||||
|
|((((((((_, version_operator), _), _), version), star), _), _), _)| {
|
||||||
|
matches!(
|
||||||
|
(version_operator, star),
|
||||||
|
(VersionOperator::Eq, Some(_) | None) | (_, None)
|
||||||
|
) && matches!((version.build_id(), star), (Some(_), None) | (None, _))
|
||||||
|
},
|
||||||
|
)
|
||||||
.map(
|
.map(
|
||||||
|((((((blocker, version_operator), category), name), version), slot), usedeps)| {
|
|(
|
||||||
|
(
|
||||||
|
((((((blocker, version_operator), category), name), version), star), slot),
|
||||||
|
repo,
|
||||||
|
),
|
||||||
|
usedeps,
|
||||||
|
)| {
|
||||||
Atom {
|
Atom {
|
||||||
blocker,
|
blocker,
|
||||||
category,
|
category,
|
||||||
name,
|
name,
|
||||||
version: Some((version_operator, version)),
|
version: Some((version_operator, version, star)),
|
||||||
slot,
|
slot,
|
||||||
|
repo,
|
||||||
usedeps: usedeps.unwrap_or(Vec::new()),
|
usedeps: usedeps.unwrap_or(Vec::new()),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
)
|
);
|
||||||
.verify_output(|atom| match &atom.version {
|
|
||||||
Some((VersionOperator::Eq, _)) => true,
|
|
||||||
Some((_, version))
|
|
||||||
if !version
|
|
||||||
.numbers()
|
|
||||||
.get()
|
|
||||||
.iter()
|
|
||||||
.any(|number| number.get().contains('*')) =>
|
|
||||||
{
|
|
||||||
true
|
|
||||||
}
|
|
||||||
_ => false,
|
|
||||||
});
|
|
||||||
|
|
||||||
with_version.or(without_version)
|
with_version.or(without_version)
|
||||||
}
|
}
|
||||||
@@ -420,9 +486,9 @@ mod test {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_empty_slot() {
|
fn test_empty_slot() {
|
||||||
let it = InputIter::new("foo/bar:=");
|
let it = InputIter::new("=dev-ml/uucp-17*:");
|
||||||
|
|
||||||
Atom::parser().check_finished(it).unwrap();
|
assert!(Atom::parser().check_finished(it).is_err());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -494,4 +560,40 @@ mod test {
|
|||||||
|
|
||||||
assert!(Cpv::parser().parse_finished(it).is_err());
|
assert!(Cpv::parser().parse_finished(it).is_err());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_empty_slot_with_operator() {
|
||||||
|
let it = InputIter::new("foo/bar:=");
|
||||||
|
|
||||||
|
Atom::parser().check_finished(it).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_with_repo() {
|
||||||
|
let it = InputIter::new("=foo/bar-1.0.0:slot/sub=::gentoo[a,b,c]");
|
||||||
|
|
||||||
|
Atom::parser().check_finished(it).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_against_fuzzer_false_positives() {
|
||||||
|
let atoms = [
|
||||||
|
"media-libs/libsdl2[haptitick(+),sound(+)vd,eio(+)]",
|
||||||
|
"=kde-frameworks/kcodecs-6.19*86",
|
||||||
|
"=dev-ml/stdio-0.17*t:=[ocamlopt?]",
|
||||||
|
">=dev-libs/libgee-0-8.5:0..8=",
|
||||||
|
"<dev-haskell/wai-3.3:=[]",
|
||||||
|
">=kde-frameworks/kcrash-2.16.0:6*",
|
||||||
|
"0-f/merreka+m::k+",
|
||||||
|
"iev-a/h:/n=",
|
||||||
|
"=dev-ml/stdio-0-17*:=[ocamlopt?]",
|
||||||
|
];
|
||||||
|
|
||||||
|
for atom in atoms {
|
||||||
|
assert!(
|
||||||
|
Atom::parser().check_finished(InputIter::new(atom)).is_err(),
|
||||||
|
"{atom}"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,10 @@
|
|||||||
#![deny(clippy::pedantic, unused_imports)]
|
#![deny(clippy::pedantic, unused_imports)]
|
||||||
#![allow(dead_code, unstable_name_collisions, clippy::missing_errors_doc)]
|
#![allow(
|
||||||
|
dead_code,
|
||||||
|
unstable_name_collisions,
|
||||||
|
clippy::missing_errors_doc,
|
||||||
|
clippy::missing_panics_doc
|
||||||
|
)]
|
||||||
#![feature(impl_trait_in_assoc_type)]
|
#![feature(impl_trait_in_assoc_type)]
|
||||||
|
|
||||||
use mon::{Parser, input::Input};
|
use mon::{Parser, input::Input};
|
||||||
@@ -11,5 +16,5 @@ pub trait Parseable<'a, I: Input + 'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub mod atom;
|
pub mod atom;
|
||||||
pub mod ebuild;
|
pub mod repo;
|
||||||
pub mod useflag;
|
pub mod useflag;
|
||||||
|
|||||||
@@ -6,8 +6,7 @@ use crate::{
|
|||||||
useflag::{IUseFlag, UseFlag},
|
useflag::{IUseFlag, UseFlag},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub mod parsers;
|
mod parsers;
|
||||||
pub mod repo;
|
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub enum Conditional {
|
pub enum Conditional {
|
||||||
@@ -59,26 +58,26 @@ pub struct Eclass(#[get(method = "get", kind = "deref")] String);
|
|||||||
|
|
||||||
#[derive(Debug, Clone, Get)]
|
#[derive(Debug, Clone, Get)]
|
||||||
pub struct Ebuild {
|
pub struct Ebuild {
|
||||||
name: Name,
|
pub(super) name: Name,
|
||||||
version: Version,
|
pub(super) version: Version,
|
||||||
slot: Option<Slot>,
|
pub(super) slot: Option<Slot>,
|
||||||
homepage: Option<String>,
|
pub(super) homepage: Option<String>,
|
||||||
#[get(kind = "deref")]
|
#[get(kind = "deref")]
|
||||||
src_uri: Vec<Depend<SrcUri>>,
|
pub(super) src_uri: Vec<Depend<SrcUri>>,
|
||||||
eapi: Option<Eapi>,
|
pub(super) eapi: Option<Eapi>,
|
||||||
#[get(kind = "deref")]
|
#[get(kind = "deref")]
|
||||||
inherit: Vec<Eclass>,
|
pub(super) inherit: Vec<Eclass>,
|
||||||
#[get(kind = "deref")]
|
#[get(kind = "deref")]
|
||||||
iuse: Vec<IUseFlag>,
|
pub(super) iuse: Vec<IUseFlag>,
|
||||||
#[get(kind = "deref")]
|
#[get(kind = "deref")]
|
||||||
license: Vec<Depend<License>>,
|
pub(super) license: Vec<Depend<License>>,
|
||||||
description: Option<String>,
|
pub(super) description: Option<String>,
|
||||||
#[get(kind = "deref")]
|
#[get(kind = "deref")]
|
||||||
depend: Vec<Depend<Atom>>,
|
pub(super) depend: Vec<Depend<Atom>>,
|
||||||
#[get(kind = "deref")]
|
#[get(kind = "deref")]
|
||||||
bdepend: Vec<Depend<Atom>>,
|
pub(super) bdepend: Vec<Depend<Atom>>,
|
||||||
#[get(kind = "deref")]
|
#[get(kind = "deref")]
|
||||||
rdepend: Vec<Depend<Atom>>,
|
pub(super) rdepend: Vec<Depend<Atom>>,
|
||||||
#[get(kind = "deref")]
|
#[get(kind = "deref")]
|
||||||
idepend: Vec<Depend<Atom>>,
|
pub(super) idepend: Vec<Depend<Atom>>,
|
||||||
}
|
}
|
||||||
@@ -1,10 +1,12 @@
|
|||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
use mon::{Parser, ParserIter, alpha1, alphanumeric, r#if, one_of, tag, whitespace1};
|
use mon::{
|
||||||
|
Parser, ParserIter, ascii_alpha1, ascii_alphanumeric, ascii_whitespace1, r#if, one_of, tag,
|
||||||
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
Parseable,
|
Parseable,
|
||||||
ebuild::{Conditional, Depend, Eapi, Eclass, License, SrcUri, Uri, UriPrefix},
|
repo::ebuild::{Conditional, Depend, Eapi, Eclass, License, SrcUri, Uri, UriPrefix},
|
||||||
useflag::UseFlag,
|
useflag::UseFlag,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -22,7 +24,7 @@ impl<'a> Parseable<'a, &'a str> for Uri {
|
|||||||
type Parser = impl Parser<&'a str, Output = Self>;
|
type Parser = impl Parser<&'a str, Output = Self>;
|
||||||
|
|
||||||
fn parser() -> Self::Parser {
|
fn parser() -> Self::Parser {
|
||||||
let protocol = alpha1::<&str>()
|
let protocol = ascii_alpha1::<&str>()
|
||||||
.followed_by(tag("://"))
|
.followed_by(tag("://"))
|
||||||
.map(|output: &str| output.to_string());
|
.map(|output: &str| output.to_string());
|
||||||
let path = r#if(|c: &char| !c.is_ascii_whitespace())
|
let path = r#if(|c: &char| !c.is_ascii_whitespace())
|
||||||
@@ -67,8 +69,11 @@ impl<'a> Parseable<'a, &'a str> for License {
|
|||||||
type Parser = impl Parser<&'a str, Output = Self>;
|
type Parser = impl Parser<&'a str, Output = Self>;
|
||||||
|
|
||||||
fn parser() -> Self::Parser {
|
fn parser() -> Self::Parser {
|
||||||
let start = alphanumeric().or(one_of("_".chars()));
|
let start = ascii_alphanumeric().or(one_of("_".chars()));
|
||||||
let rest = alphanumeric().or(one_of("+_.-".chars())).repeated().many();
|
let rest = ascii_alphanumeric()
|
||||||
|
.or(one_of("+_.-".chars()))
|
||||||
|
.repeated()
|
||||||
|
.many();
|
||||||
|
|
||||||
start
|
start
|
||||||
.and(rest)
|
.and(rest)
|
||||||
@@ -81,8 +86,11 @@ impl<'a> Parseable<'a, &'a str> for Eapi {
|
|||||||
type Parser = impl Parser<&'a str, Output = Self>;
|
type Parser = impl Parser<&'a str, Output = Self>;
|
||||||
|
|
||||||
fn parser() -> Self::Parser {
|
fn parser() -> Self::Parser {
|
||||||
let start = alphanumeric().or(one_of("_".chars()));
|
let start = ascii_alphanumeric().or(one_of("_".chars()));
|
||||||
let rest = alphanumeric().or(one_of("+_.-".chars())).repeated().many();
|
let rest = ascii_alphanumeric()
|
||||||
|
.or(one_of("+_.-".chars()))
|
||||||
|
.repeated()
|
||||||
|
.many();
|
||||||
|
|
||||||
start
|
start
|
||||||
.and(rest)
|
.and(rest)
|
||||||
@@ -116,23 +124,23 @@ where
|
|||||||
|it| {
|
|it| {
|
||||||
let exprs = || {
|
let exprs = || {
|
||||||
Depend::parser()
|
Depend::parser()
|
||||||
.separated_by_with_trailing(whitespace1())
|
.separated_by_with_trailing(ascii_whitespace1())
|
||||||
.at_least(1)
|
.at_least(1)
|
||||||
.delimited_by(tag("(").followed_by(whitespace1()), tag(")"))
|
.delimited_by(tag("(").followed_by(ascii_whitespace1()), tag(")"))
|
||||||
};
|
};
|
||||||
|
|
||||||
let all_of_group = exprs().map(|exprs| Depend::AllOf(exprs));
|
let all_of_group = exprs().map(|exprs| Depend::AllOf(exprs));
|
||||||
|
|
||||||
let any_of_group = exprs()
|
let any_of_group = exprs()
|
||||||
.preceded_by(tag("||").followed_by(whitespace1()))
|
.preceded_by(tag("||").followed_by(ascii_whitespace1()))
|
||||||
.map(|exprs| Depend::AnyOf(exprs));
|
.map(|exprs| Depend::AnyOf(exprs));
|
||||||
|
|
||||||
let one_of_group = exprs()
|
let one_of_group = exprs()
|
||||||
.preceded_by(tag("^^").followed_by(whitespace1()))
|
.preceded_by(tag("^^").followed_by(ascii_whitespace1()))
|
||||||
.map(|exprs| Depend::OneOf(exprs));
|
.map(|exprs| Depend::OneOf(exprs));
|
||||||
|
|
||||||
let conditional_group = Conditional::parser()
|
let conditional_group = Conditional::parser()
|
||||||
.followed_by(whitespace1())
|
.followed_by(ascii_whitespace1())
|
||||||
.and(exprs())
|
.and(exprs())
|
||||||
.map(|(conditional, exprs)| Depend::ConditionalGroup(conditional, exprs));
|
.map(|(conditional, exprs)| Depend::ConditionalGroup(conditional, exprs));
|
||||||
|
|
||||||
@@ -166,7 +174,7 @@ mod test {
|
|||||||
|
|
||||||
use mon::{ParserIter, input::InputIter};
|
use mon::{ParserIter, input::InputIter};
|
||||||
|
|
||||||
use crate::{atom::Atom, ebuild::Depend};
|
use crate::{atom::Atom, repo::ebuild::Depend};
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
@@ -189,7 +197,7 @@ mod test {
|
|||||||
let it = InputIter::new("flag? ( || ( foo/bar foo/bar ) )");
|
let it = InputIter::new("flag? ( || ( foo/bar foo/bar ) )");
|
||||||
|
|
||||||
Depend::<Atom>::parser()
|
Depend::<Atom>::parser()
|
||||||
.separated_by(whitespace1())
|
.separated_by(ascii_whitespace1())
|
||||||
.many()
|
.many()
|
||||||
.check_finished(it)
|
.check_finished(it)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
@@ -5,15 +5,21 @@ use std::{
|
|||||||
|
|
||||||
use get::Get;
|
use get::Get;
|
||||||
|
|
||||||
use mon::{Parser, ParserIter, input::InputIter, tag, whitespace1};
|
use mon::{Parser, ParserIter, ascii_whitespace1, input::InputIter, tag};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
Parseable,
|
Parseable,
|
||||||
atom::{self, Atom},
|
atom::{self, Atom},
|
||||||
|
repo::{
|
||||||
ebuild::{Depend, Eapi, Ebuild, Eclass, License, SrcUri},
|
ebuild::{Depend, Eapi, Ebuild, Eclass, License, SrcUri},
|
||||||
|
profile::Profile,
|
||||||
|
},
|
||||||
useflag::IUseFlag,
|
useflag::IUseFlag,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pub mod ebuild;
|
||||||
|
pub mod profile;
|
||||||
|
|
||||||
#[derive(Debug, thiserror::Error)]
|
#[derive(Debug, thiserror::Error)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
#[error("io error: {0}")]
|
#[error("io error: {0}")]
|
||||||
@@ -24,6 +30,8 @@ pub enum Error {
|
|||||||
Unicode(PathBuf),
|
Unicode(PathBuf),
|
||||||
#[error("parser error: {0}")]
|
#[error("parser error: {0}")]
|
||||||
Parser(String),
|
Parser(String),
|
||||||
|
#[error("profile error: {0}")]
|
||||||
|
Profile(profile::Error),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Get)]
|
#[derive(Debug, Clone, Get)]
|
||||||
@@ -60,6 +68,10 @@ impl Repo {
|
|||||||
fs::read_dir(&path).map_err(|e| Error::Io(path, e))?,
|
fs::read_dir(&path).map_err(|e| Error::Io(path, e))?,
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn evaluate_profile<P: AsRef<Path>>(&self, path: P) -> Result<Profile, Error> {
|
||||||
|
Profile::evaluate(self.path.join("profiles").join(path)).map_err(Error::Profile)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Category {
|
impl Category {
|
||||||
@@ -208,7 +220,7 @@ fn read_src_uri(input: &str) -> Option<Result<Vec<Depend<SrcUri>>, Error>> {
|
|||||||
.find_map(|line| line.strip_prefix("SRC_URI="))?;
|
.find_map(|line| line.strip_prefix("SRC_URI="))?;
|
||||||
|
|
||||||
match Depend::<SrcUri>::parser()
|
match Depend::<SrcUri>::parser()
|
||||||
.separated_by(whitespace1())
|
.separated_by(ascii_whitespace1())
|
||||||
.many()
|
.many()
|
||||||
.parse_finished(InputIter::new(line))
|
.parse_finished(InputIter::new(line))
|
||||||
{
|
{
|
||||||
@@ -232,7 +244,7 @@ fn read_inherit(input: &str) -> Option<Result<Vec<Eclass>, Error>> {
|
|||||||
.find_map(|line| line.strip_prefix("INHERIT="))?;
|
.find_map(|line| line.strip_prefix("INHERIT="))?;
|
||||||
|
|
||||||
match Eclass::parser()
|
match Eclass::parser()
|
||||||
.separated_by(whitespace1())
|
.separated_by(ascii_whitespace1())
|
||||||
.many()
|
.many()
|
||||||
.parse_finished(InputIter::new(line))
|
.parse_finished(InputIter::new(line))
|
||||||
{
|
{
|
||||||
@@ -245,7 +257,7 @@ fn read_iuse(input: &str) -> Option<Result<Vec<IUseFlag>, Error>> {
|
|||||||
let line = input.lines().find_map(|line| line.strip_prefix("IUSE="))?;
|
let line = input.lines().find_map(|line| line.strip_prefix("IUSE="))?;
|
||||||
|
|
||||||
match IUseFlag::parser()
|
match IUseFlag::parser()
|
||||||
.separated_by(whitespace1())
|
.separated_by(ascii_whitespace1())
|
||||||
.many()
|
.many()
|
||||||
.parse_finished(InputIter::new(line))
|
.parse_finished(InputIter::new(line))
|
||||||
{
|
{
|
||||||
@@ -260,7 +272,7 @@ fn read_license(input: &str) -> Option<Result<Vec<Depend<License>>, Error>> {
|
|||||||
.find_map(|line| line.strip_suffix("LICENSE="))?;
|
.find_map(|line| line.strip_suffix("LICENSE="))?;
|
||||||
|
|
||||||
match Depend::<License>::parser()
|
match Depend::<License>::parser()
|
||||||
.separated_by(whitespace1())
|
.separated_by(ascii_whitespace1())
|
||||||
.many()
|
.many()
|
||||||
.parse_finished(InputIter::new(line))
|
.parse_finished(InputIter::new(line))
|
||||||
{
|
{
|
||||||
@@ -309,7 +321,7 @@ fn read_idepend(input: &str) -> Option<Result<Vec<Depend<Atom>>, Error>> {
|
|||||||
|
|
||||||
fn parse_depends(line: &str) -> Result<Vec<Depend<Atom>>, Error> {
|
fn parse_depends(line: &str) -> Result<Vec<Depend<Atom>>, Error> {
|
||||||
Depend::<Atom>::parser()
|
Depend::<Atom>::parser()
|
||||||
.separated_by(whitespace1())
|
.separated_by(ascii_whitespace1())
|
||||||
.many()
|
.many()
|
||||||
.parse_finished(InputIter::new(line))
|
.parse_finished(InputIter::new(line))
|
||||||
.map_err(|_| Error::Parser(line.to_string()))
|
.map_err(|_| Error::Parser(line.to_string()))
|
||||||
135
src/repo/profile/make_defaults/mod.rs
Normal file
135
src/repo/profile/make_defaults/mod.rs
Normal file
@@ -0,0 +1,135 @@
|
|||||||
|
use std::{
|
||||||
|
collections::{HashMap, HashSet},
|
||||||
|
fs, io,
|
||||||
|
path::{Path, PathBuf},
|
||||||
|
};
|
||||||
|
|
||||||
|
use mon::{Parser, ParserIter, ascii_whitespace1, input::InputIter};
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
Parseable,
|
||||||
|
repo::profile::{LineBasedFileExpr, Profile},
|
||||||
|
};
|
||||||
|
|
||||||
|
mod parsers;
|
||||||
|
|
||||||
|
#[derive(Debug, thiserror::Error)]
|
||||||
|
pub enum Error {
|
||||||
|
#[error("{0}: io error: {1}")]
|
||||||
|
Io(PathBuf, io::Error),
|
||||||
|
#[error("parser error: {0}")]
|
||||||
|
Parser(String),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
|
struct Key(String);
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
struct Literal(String);
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
struct Interpolation(String);
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
enum Segment {
|
||||||
|
Literal(Literal),
|
||||||
|
Interpolation(Interpolation),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
struct Assignment(Key, Vec<Segment>);
|
||||||
|
|
||||||
|
pub(super) fn evaluate<P: AsRef<Path>>(
|
||||||
|
parents: &[Profile],
|
||||||
|
path: P,
|
||||||
|
) -> Result<HashMap<String, String>, Error> {
|
||||||
|
let parsed = match fs::read_to_string(path.as_ref().join("make.defaults")) {
|
||||||
|
Ok(contents) => parse(&contents)?,
|
||||||
|
Err(e) if matches!(e.kind(), io::ErrorKind::NotFound) => HashMap::new(),
|
||||||
|
Err(e) => return Err(Error::Io(path.as_ref().to_path_buf(), e)),
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut vars = interpolate(parents, parsed);
|
||||||
|
|
||||||
|
incremental(parents, &mut vars);
|
||||||
|
|
||||||
|
Ok(vars)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn incremental(parents: &[Profile], vars: &mut HashMap<String, String>) {
|
||||||
|
for key in [
|
||||||
|
"USE",
|
||||||
|
"USE_EXPAND",
|
||||||
|
"USE_EXPAND_HIDDEN",
|
||||||
|
"CONFIG_PROTECT",
|
||||||
|
"CONFIG_PROTECT_MASK",
|
||||||
|
] {
|
||||||
|
let mut accumulated = Vec::new();
|
||||||
|
|
||||||
|
for parent in parents {
|
||||||
|
if let Some(values) = parent.make_defaults().get(key) {
|
||||||
|
accumulated.extend(values.split_ascii_whitespace());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(values) = vars.get(key) {
|
||||||
|
accumulated.extend(values.split_ascii_whitespace());
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut final_values = Vec::new();
|
||||||
|
|
||||||
|
for var in accumulated {
|
||||||
|
if var == "-*" {
|
||||||
|
final_values.clear();
|
||||||
|
} else if let Some(stripped) = var.strip_prefix("-") {
|
||||||
|
final_values.retain(|v| *v != stripped);
|
||||||
|
} else {
|
||||||
|
final_values.push(var);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut seen = HashSet::new();
|
||||||
|
final_values.retain(|v| seen.insert(*v));
|
||||||
|
|
||||||
|
if !final_values.is_empty() {
|
||||||
|
vars.insert(key.to_string(), final_values.join(" "));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn interpolate(parents: &[Profile], vars: HashMap<Key, Vec<Segment>>) -> HashMap<String, String> {
|
||||||
|
let parent_vars = parents
|
||||||
|
.iter()
|
||||||
|
.flat_map(|parent| parent.make_defaults().clone().into_iter())
|
||||||
|
.collect::<HashMap<_, _>>();
|
||||||
|
|
||||||
|
vars.into_iter()
|
||||||
|
.map(|(key, segments)| {
|
||||||
|
let interpolated = segments
|
||||||
|
.into_iter()
|
||||||
|
.map(|segment| match segment {
|
||||||
|
Segment::Interpolation(i) => parent_vars.get(&i.0).cloned().unwrap_or_default(),
|
||||||
|
Segment::Literal(literal) => literal.0.trim().to_string(),
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
let joined = interpolated.join("");
|
||||||
|
|
||||||
|
(key.0, joined)
|
||||||
|
})
|
||||||
|
.collect::<HashMap<String, String>>()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse(contents: &str) -> Result<HashMap<Key, Vec<Segment>>, Error> {
|
||||||
|
Ok(LineBasedFileExpr::<Assignment>::parser()
|
||||||
|
.separated_by_with_opt_trailing(ascii_whitespace1())
|
||||||
|
.many()
|
||||||
|
.parse_finished(InputIter::new(contents))
|
||||||
|
.map_err(|e| Error::Parser(dbg!(e).rest().to_string()))?
|
||||||
|
.into_iter()
|
||||||
|
.filter_map(|expr| match expr {
|
||||||
|
LineBasedFileExpr::Comment => None,
|
||||||
|
LineBasedFileExpr::Expr(Assignment(key, value)) => Some((key, value)),
|
||||||
|
})
|
||||||
|
.collect())
|
||||||
|
}
|
||||||
88
src/repo/profile/make_defaults/parsers.rs
Normal file
88
src/repo/profile/make_defaults/parsers.rs
Normal file
@@ -0,0 +1,88 @@
|
|||||||
|
use mon::{Parser, ParserIter, ascii_alpha, ascii_alphanumeric, r#if, one_of, tag};
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
Parseable,
|
||||||
|
repo::profile::make_defaults::{Assignment, Interpolation, Key, Literal, Segment},
|
||||||
|
};
|
||||||
|
|
||||||
|
impl<'a> Parseable<'a, &'a str> for Key {
|
||||||
|
type Parser = impl Parser<&'a str, Output = Self>;
|
||||||
|
|
||||||
|
fn parser() -> Self::Parser {
|
||||||
|
let start = ascii_alpha();
|
||||||
|
let rest = ascii_alphanumeric()
|
||||||
|
.or(one_of("_".chars()))
|
||||||
|
.repeated()
|
||||||
|
.many();
|
||||||
|
|
||||||
|
start
|
||||||
|
.followed_by(rest)
|
||||||
|
.recognize()
|
||||||
|
.map(|output: &str| Key(output.to_string()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Parseable<'a, &'a str> for Literal {
|
||||||
|
type Parser = impl Parser<&'a str, Output = Self>;
|
||||||
|
|
||||||
|
fn parser() -> Self::Parser {
|
||||||
|
r#if(|c: &char| *c != '"')
|
||||||
|
.and_not(Interpolation::parser())
|
||||||
|
.repeated()
|
||||||
|
.at_least(1)
|
||||||
|
.recognize()
|
||||||
|
.map(|output: &str| Literal(output.to_string()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Parseable<'a, &'a str> for Interpolation {
|
||||||
|
type Parser = impl Parser<&'a str, Output = Self>;
|
||||||
|
|
||||||
|
fn parser() -> Self::Parser {
|
||||||
|
Key::parser()
|
||||||
|
.recognize()
|
||||||
|
.delimited_by(tag("{"), tag("}"))
|
||||||
|
.preceded_by(tag("$"))
|
||||||
|
.map(|output: &str| Interpolation(output.to_string()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Parseable<'a, &'a str> for Segment {
|
||||||
|
type Parser = impl Parser<&'a str, Output = Self>;
|
||||||
|
|
||||||
|
fn parser() -> Self::Parser {
|
||||||
|
Literal::parser()
|
||||||
|
.map(Segment::Literal)
|
||||||
|
.or(Interpolation::parser().map(Segment::Interpolation))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Parseable<'a, &'a str> for Assignment {
|
||||||
|
type Parser = impl Parser<&'a str, Output = Self>;
|
||||||
|
|
||||||
|
fn parser() -> Self::Parser {
|
||||||
|
Key::parser()
|
||||||
|
.followed_by(tag("="))
|
||||||
|
.and(
|
||||||
|
Segment::parser()
|
||||||
|
.repeated()
|
||||||
|
.many()
|
||||||
|
.delimited_by(tag("\""), tag("\"")),
|
||||||
|
)
|
||||||
|
.map(|(key, value)| Assignment(key, value))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use mon::input::InputIter;
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_parse_value() {
|
||||||
|
let it = InputIter::new(r#"KEY="foo ${bar}""#);
|
||||||
|
|
||||||
|
Assignment::parser().check_finished(it).unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
157
src/repo/profile/mod.rs
Normal file
157
src/repo/profile/mod.rs
Normal file
@@ -0,0 +1,157 @@
|
|||||||
|
use std::{
|
||||||
|
collections::HashMap,
|
||||||
|
fs::{self, File},
|
||||||
|
io::{self, Read},
|
||||||
|
path::{Path, PathBuf},
|
||||||
|
};
|
||||||
|
|
||||||
|
use get::Get;
|
||||||
|
use itertools::Itertools;
|
||||||
|
|
||||||
|
use crate::{atom::Atom, useflag::UseFlag};
|
||||||
|
|
||||||
|
mod make_defaults;
|
||||||
|
mod package;
|
||||||
|
mod package_use;
|
||||||
|
mod packages;
|
||||||
|
mod parsers;
|
||||||
|
mod useflags;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
enum LineBasedFileExpr<T> {
|
||||||
|
Comment,
|
||||||
|
Expr(T),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
enum FlagOperation {
|
||||||
|
Add(UseFlag),
|
||||||
|
Remove(UseFlag),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, thiserror::Error)]
|
||||||
|
pub enum Error {
|
||||||
|
#[error("{0}: io error: {1}")]
|
||||||
|
Io(PathBuf, io::Error),
|
||||||
|
#[error("error evaluating make.defaults settings: {0}")]
|
||||||
|
MakeDefaults(#[from] make_defaults::Error),
|
||||||
|
#[error("error evaluating packages settings: {0}")]
|
||||||
|
Packages(#[from] packages::Error),
|
||||||
|
#[error("error evaluating package settings: {0}")]
|
||||||
|
Package(#[from] package::Error),
|
||||||
|
#[error("error evaluating package.use settings: {0}")]
|
||||||
|
PackageUse(#[from] package_use::Error),
|
||||||
|
#[error("error evaluating use settings: {0}")]
|
||||||
|
Use(#[from] useflags::Error),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Get)]
|
||||||
|
pub struct Profile {
|
||||||
|
#[get(kind = "deref")]
|
||||||
|
path: PathBuf,
|
||||||
|
#[get(kind = "deref")]
|
||||||
|
parents: Vec<Profile>,
|
||||||
|
make_defaults: HashMap<String, String>,
|
||||||
|
#[get(kind = "deref")]
|
||||||
|
packages: Vec<Atom>,
|
||||||
|
#[get(kind = "deref")]
|
||||||
|
package_mask: Vec<Atom>,
|
||||||
|
#[get(kind = "deref")]
|
||||||
|
package_provided: Vec<Atom>,
|
||||||
|
package_use: HashMap<Atom, Vec<UseFlag>>,
|
||||||
|
package_use_force: HashMap<Atom, Vec<UseFlag>>,
|
||||||
|
package_use_mask: HashMap<Atom, Vec<UseFlag>>,
|
||||||
|
package_use_stable_force: HashMap<Atom, Vec<UseFlag>>,
|
||||||
|
package_use_stable_mask: HashMap<Atom, Vec<UseFlag>>,
|
||||||
|
#[get(kind = "deref")]
|
||||||
|
use_force: Vec<UseFlag>,
|
||||||
|
#[get(kind = "deref")]
|
||||||
|
use_mask: Vec<UseFlag>,
|
||||||
|
#[get(kind = "deref")]
|
||||||
|
use_stable_force: Vec<UseFlag>,
|
||||||
|
#[get(kind = "deref")]
|
||||||
|
use_stable_mask: Vec<UseFlag>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Profile {
|
||||||
|
pub(super) fn evaluate<P: AsRef<Path>>(path: P) -> Result<Self, Error> {
|
||||||
|
let parents_path = path.as_ref().join("parent");
|
||||||
|
|
||||||
|
let parents = match fs::read_to_string(&parents_path) {
|
||||||
|
Ok(parents) => parents
|
||||||
|
.lines()
|
||||||
|
.map(|line| path.as_ref().join(line))
|
||||||
|
.map(Profile::evaluate)
|
||||||
|
.collect::<Result<_, _>>()?,
|
||||||
|
Err(e) if matches!(e.kind(), io::ErrorKind::NotFound) => Vec::new(),
|
||||||
|
Err(e) => return Err(Error::Io(parents_path, e)),
|
||||||
|
};
|
||||||
|
|
||||||
|
let make_defaults = make_defaults::evaluate(&parents, &path)?;
|
||||||
|
|
||||||
|
let packages = packages::evaluate(&parents, &path)?;
|
||||||
|
|
||||||
|
let package_mask = package::evaluate(&parents, package::Kind::Mask, &path)?;
|
||||||
|
let package_provided = package::evaluate(&parents, package::Kind::Provided, &path)?;
|
||||||
|
|
||||||
|
let package_use = package_use::evaluate(&parents, package_use::Kind::Use, &path)?;
|
||||||
|
let package_use_force = package_use::evaluate(&parents, package_use::Kind::Force, &path)?;
|
||||||
|
let package_use_mask = package_use::evaluate(&parents, package_use::Kind::Mask, &path)?;
|
||||||
|
let package_use_stable_force =
|
||||||
|
package_use::evaluate(&parents, package_use::Kind::StableForce, &path)?;
|
||||||
|
let package_use_stable_mask =
|
||||||
|
package_use::evaluate(&parents, package_use::Kind::StableMask, &path)?;
|
||||||
|
|
||||||
|
let use_force = useflags::evaluate(&parents, useflags::Kind::Force, &path)?;
|
||||||
|
let use_mask = useflags::evaluate(&parents, useflags::Kind::Mask, &path)?;
|
||||||
|
let use_stable_force = useflags::evaluate(&parents, useflags::Kind::StableForce, &path)?;
|
||||||
|
let use_stable_mask = useflags::evaluate(&parents, useflags::Kind::StableMask, &path)?;
|
||||||
|
|
||||||
|
Ok(Self {
|
||||||
|
path: path.as_ref().to_path_buf(),
|
||||||
|
parents,
|
||||||
|
make_defaults,
|
||||||
|
packages,
|
||||||
|
package_mask,
|
||||||
|
package_provided,
|
||||||
|
package_use,
|
||||||
|
package_use_force,
|
||||||
|
package_use_mask,
|
||||||
|
package_use_stable_force,
|
||||||
|
package_use_stable_mask,
|
||||||
|
use_force,
|
||||||
|
use_mask,
|
||||||
|
use_stable_force,
|
||||||
|
use_stable_mask,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read_config_files<P: AsRef<Path>>(path: P) -> Result<String, io::Error> {
|
||||||
|
let metadata = fs::metadata(&path)?;
|
||||||
|
|
||||||
|
if metadata.is_file() {
|
||||||
|
fs::read_to_string(&path)
|
||||||
|
} else if metadata.is_dir() {
|
||||||
|
let mut buffer = String::new();
|
||||||
|
let paths = fs::read_dir(&path)?
|
||||||
|
.collect::<Result<Vec<_>, _>>()?
|
||||||
|
.into_iter()
|
||||||
|
.map(|entry| entry.path())
|
||||||
|
.filter(|path| path.starts_with("."))
|
||||||
|
.sorted()
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
for path in &paths {
|
||||||
|
let mut file = File::open(path)?;
|
||||||
|
|
||||||
|
file.read_to_string(&mut buffer)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(buffer)
|
||||||
|
} else {
|
||||||
|
let path = fs::canonicalize(&path)?;
|
||||||
|
|
||||||
|
read_config_files(path)
|
||||||
|
}
|
||||||
|
}
|
||||||
95
src/repo/profile/package/mod.rs
Normal file
95
src/repo/profile/package/mod.rs
Normal file
@@ -0,0 +1,95 @@
|
|||||||
|
use std::{
|
||||||
|
io,
|
||||||
|
path::{Path, PathBuf},
|
||||||
|
};
|
||||||
|
|
||||||
|
use mon::{Parser, ParserIter, ascii_whitespace1, input::InputIter};
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
Parseable,
|
||||||
|
atom::Atom,
|
||||||
|
repo::profile::{LineBasedFileExpr, Profile, read_config_files},
|
||||||
|
};
|
||||||
|
|
||||||
|
mod parsers;
|
||||||
|
|
||||||
|
#[derive(Debug, thiserror::Error)]
|
||||||
|
pub enum Error {
|
||||||
|
#[error("{0}: io error: {1}")]
|
||||||
|
Io(PathBuf, io::Error),
|
||||||
|
#[error("parser error: {0}")]
|
||||||
|
Parser(String),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
pub(super) enum Kind {
|
||||||
|
Mask,
|
||||||
|
Provided,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
enum Package {
|
||||||
|
Add(Atom),
|
||||||
|
Remove(Atom),
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) fn evaluate<P: AsRef<Path>>(
|
||||||
|
parents: &[Profile],
|
||||||
|
kind: Kind,
|
||||||
|
path: P,
|
||||||
|
) -> Result<Vec<Atom>, Error> {
|
||||||
|
let file_path = match kind {
|
||||||
|
Kind::Mask => "package.mask",
|
||||||
|
Kind::Provided => "package.provided",
|
||||||
|
};
|
||||||
|
|
||||||
|
let parsed = match read_config_files(path.as_ref().join(file_path)) {
|
||||||
|
Ok(contents) => parse(&contents)?,
|
||||||
|
Err(e) if matches!(e.kind(), io::ErrorKind::NotFound) => Vec::new(),
|
||||||
|
Err(e) => return Err(Error::Io(path.as_ref().to_path_buf(), e)),
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(inherit(parents, kind, parsed))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn inherit(parents: &[Profile], kind: Kind, packages: Vec<Package>) -> Vec<Atom> {
|
||||||
|
let mut accumulated = Vec::new();
|
||||||
|
|
||||||
|
for parent in parents {
|
||||||
|
let source = match kind {
|
||||||
|
Kind::Mask => parent.package_mask(),
|
||||||
|
Kind::Provided => parent.package_provided(),
|
||||||
|
};
|
||||||
|
|
||||||
|
for package in source {
|
||||||
|
accumulated.push(package.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for package in packages {
|
||||||
|
match package {
|
||||||
|
Package::Add(package) => {
|
||||||
|
accumulated.push(package);
|
||||||
|
}
|
||||||
|
Package::Remove(package) => {
|
||||||
|
accumulated.retain(|p| *p != package);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
accumulated
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse(contents: &str) -> Result<Vec<Package>, Error> {
|
||||||
|
Ok(LineBasedFileExpr::<Package>::parser()
|
||||||
|
.separated_by_with_opt_trailing(ascii_whitespace1())
|
||||||
|
.many()
|
||||||
|
.parse_finished(InputIter::new(contents))
|
||||||
|
.map_err(|e| Error::Parser(e.rest().to_string()))?
|
||||||
|
.into_iter()
|
||||||
|
.filter_map(|expr| match expr {
|
||||||
|
LineBasedFileExpr::Comment => None,
|
||||||
|
LineBasedFileExpr::Expr(package) => Some(package),
|
||||||
|
})
|
||||||
|
.collect())
|
||||||
|
}
|
||||||
13
src/repo/profile/package/parsers.rs
Normal file
13
src/repo/profile/package/parsers.rs
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
use mon::{Parser, tag};
|
||||||
|
|
||||||
|
use crate::{Parseable, atom::Atom, repo::profile::package::Package};
|
||||||
|
|
||||||
|
impl<'a> Parseable<'a, &'a str> for Package {
|
||||||
|
type Parser = impl Parser<&'a str, Output = Self>;
|
||||||
|
|
||||||
|
fn parser() -> Self::Parser {
|
||||||
|
Atom::parser()
|
||||||
|
.map(Package::Add)
|
||||||
|
.or(Atom::parser().preceded_by(tag("-")).map(Package::Remove))
|
||||||
|
}
|
||||||
|
}
|
||||||
125
src/repo/profile/package_use/mod.rs
Normal file
125
src/repo/profile/package_use/mod.rs
Normal file
@@ -0,0 +1,125 @@
|
|||||||
|
use std::{
|
||||||
|
collections::HashMap,
|
||||||
|
io,
|
||||||
|
path::{Path, PathBuf},
|
||||||
|
};
|
||||||
|
|
||||||
|
use mon::{Parser, ParserIter, ascii_whitespace1, input::InputIter};
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
Parseable,
|
||||||
|
atom::Atom,
|
||||||
|
repo::profile::{FlagOperation, LineBasedFileExpr, Profile, read_config_files},
|
||||||
|
useflag::UseFlag,
|
||||||
|
};
|
||||||
|
|
||||||
|
mod parsers;
|
||||||
|
|
||||||
|
#[derive(Debug, thiserror::Error)]
|
||||||
|
pub enum Error {
|
||||||
|
#[error("{0}: io error: {1}")]
|
||||||
|
Io(PathBuf, io::Error),
|
||||||
|
#[error("parser error: {0}")]
|
||||||
|
Parser(String),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
struct Expr(Atom, Vec<FlagOperation>);
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
pub(super) enum Kind {
|
||||||
|
Use,
|
||||||
|
Force,
|
||||||
|
Mask,
|
||||||
|
StableForce,
|
||||||
|
StableMask,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) fn evaluate<P: AsRef<Path>>(
|
||||||
|
parents: &[Profile],
|
||||||
|
kind: Kind,
|
||||||
|
path: P,
|
||||||
|
) -> Result<HashMap<Atom, Vec<UseFlag>>, Error> {
|
||||||
|
let file_path = match kind {
|
||||||
|
Kind::Use => "package.use",
|
||||||
|
Kind::Force => "package.use.force",
|
||||||
|
Kind::Mask => "package.use.mask",
|
||||||
|
Kind::StableForce => "package.use.stable.force",
|
||||||
|
Kind::StableMask => "package.use.stable.mask",
|
||||||
|
};
|
||||||
|
|
||||||
|
let parsed = match read_config_files(path.as_ref().join(file_path)) {
|
||||||
|
Ok(contents) => parse(&contents)?,
|
||||||
|
Err(e) if matches!(e.kind(), io::ErrorKind::NotFound) => HashMap::new(),
|
||||||
|
Err(e) => return Err(Error::Io(path.as_ref().to_path_buf(), e)),
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(inherit(parents, kind, parsed))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn inherit(
|
||||||
|
parents: &[Profile],
|
||||||
|
kind: Kind,
|
||||||
|
vars: HashMap<Atom, Vec<FlagOperation>>,
|
||||||
|
) -> HashMap<Atom, Vec<UseFlag>> {
|
||||||
|
let mut accumulated: HashMap<Atom, Vec<UseFlag>> = HashMap::new();
|
||||||
|
|
||||||
|
for parent in parents {
|
||||||
|
let source = match kind {
|
||||||
|
Kind::Use => parent.package_use(),
|
||||||
|
Kind::Force => parent.package_use_force(),
|
||||||
|
Kind::Mask => parent.package_use_mask(),
|
||||||
|
Kind::StableForce => parent.package_use_stable_force(),
|
||||||
|
Kind::StableMask => parent.package_use_stable_mask(),
|
||||||
|
};
|
||||||
|
|
||||||
|
for (atom, flags) in source {
|
||||||
|
accumulated
|
||||||
|
.entry(atom.clone())
|
||||||
|
.and_modify(|f| f.extend(flags.iter().cloned()))
|
||||||
|
.or_insert(flags.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (atom, flags) in vars {
|
||||||
|
match accumulated.get_mut(&atom) {
|
||||||
|
Some(accumulated) => {
|
||||||
|
for flag in flags {
|
||||||
|
match flag {
|
||||||
|
FlagOperation::Add(flag) => accumulated.push(flag),
|
||||||
|
FlagOperation::Remove(flag) => accumulated.retain(|v| *v != flag),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
accumulated.insert(
|
||||||
|
atom.clone(),
|
||||||
|
flags
|
||||||
|
.iter()
|
||||||
|
.filter_map(|flag| match flag {
|
||||||
|
FlagOperation::Add(flag) => Some(flag),
|
||||||
|
FlagOperation::Remove(_) => None,
|
||||||
|
})
|
||||||
|
.cloned()
|
||||||
|
.collect(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
accumulated
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse(contents: &str) -> Result<HashMap<Atom, Vec<FlagOperation>>, Error> {
|
||||||
|
Ok(LineBasedFileExpr::<Expr>::parser()
|
||||||
|
.separated_by_with_opt_trailing(ascii_whitespace1())
|
||||||
|
.many()
|
||||||
|
.parse_finished(InputIter::new(contents))
|
||||||
|
.map_err(|e| Error::Parser(e.rest().to_string()))?
|
||||||
|
.into_iter()
|
||||||
|
.filter_map(|expr| match expr {
|
||||||
|
LineBasedFileExpr::Comment => None,
|
||||||
|
LineBasedFileExpr::Expr(Expr(atom, operations)) => Some((atom, operations)),
|
||||||
|
})
|
||||||
|
.collect())
|
||||||
|
}
|
||||||
36
src/repo/profile/package_use/parsers.rs
Normal file
36
src/repo/profile/package_use/parsers.rs
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
use mon::{Parser, ParserIter, ascii_whitespace, ascii_whitespace1, tag};
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
Parseable,
|
||||||
|
atom::Atom,
|
||||||
|
repo::profile::{FlagOperation, package_use::Expr},
|
||||||
|
};
|
||||||
|
|
||||||
|
impl<'a> Parseable<'a, &'a str> for Expr {
|
||||||
|
type Parser = impl Parser<&'a str, Output = Self>;
|
||||||
|
|
||||||
|
fn parser() -> Self::Parser {
|
||||||
|
Atom::parser()
|
||||||
|
.followed_by(ascii_whitespace1())
|
||||||
|
.and(
|
||||||
|
FlagOperation::parser()
|
||||||
|
.separated_by(ascii_whitespace().and_not(tag("\n")).repeated().at_least(1))
|
||||||
|
.at_least(1),
|
||||||
|
)
|
||||||
|
.map(|(atom, operations)| Expr(atom, operations))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use mon::input::InputIter;
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_parse_expr() {
|
||||||
|
let it = InputIter::new("foo/bar a -b");
|
||||||
|
|
||||||
|
Expr::parser().check_finished(it).unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
75
src/repo/profile/packages/mod.rs
Normal file
75
src/repo/profile/packages/mod.rs
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
use std::{
|
||||||
|
fs, io,
|
||||||
|
path::{Path, PathBuf},
|
||||||
|
};
|
||||||
|
|
||||||
|
use mon::{Parser, ParserIter, ascii_whitespace1, input::InputIter};
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
Parseable,
|
||||||
|
atom::Atom,
|
||||||
|
repo::profile::{LineBasedFileExpr, Profile},
|
||||||
|
};
|
||||||
|
|
||||||
|
mod parsers;
|
||||||
|
|
||||||
|
#[derive(Debug, thiserror::Error)]
|
||||||
|
pub enum Error {
|
||||||
|
#[error("{0}: io error: {1}")]
|
||||||
|
Io(PathBuf, io::Error),
|
||||||
|
#[error("parser error: {0}")]
|
||||||
|
Parser(String),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
enum Package {
|
||||||
|
Add(Atom),
|
||||||
|
Remove(Atom),
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) fn evaluate<P: AsRef<Path>>(parents: &[Profile], path: P) -> Result<Vec<Atom>, Error> {
|
||||||
|
let parsed = match fs::read_to_string(path.as_ref().join("packages")) {
|
||||||
|
Ok(contents) => parse(&contents)?,
|
||||||
|
Err(e) if matches!(e.kind(), io::ErrorKind::NotFound) => Vec::new(),
|
||||||
|
Err(e) => return Err(Error::Io(path.as_ref().to_path_buf(), e)),
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(inherit(parents, parsed))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn inherit(parents: &[Profile], packages: Vec<Package>) -> Vec<Atom> {
|
||||||
|
let mut accumulated = Vec::new();
|
||||||
|
|
||||||
|
for parent in parents {
|
||||||
|
for package in parent.packages() {
|
||||||
|
accumulated.push(package.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for package in packages {
|
||||||
|
match package {
|
||||||
|
Package::Add(package) => {
|
||||||
|
accumulated.push(package);
|
||||||
|
}
|
||||||
|
Package::Remove(package) => {
|
||||||
|
accumulated.retain(|p| *p != package);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
accumulated
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse(contents: &str) -> Result<Vec<Package>, Error> {
|
||||||
|
Ok(LineBasedFileExpr::<Package>::parser()
|
||||||
|
.separated_by_with_opt_trailing(ascii_whitespace1())
|
||||||
|
.many()
|
||||||
|
.parse_finished(InputIter::new(contents))
|
||||||
|
.map_err(|e| Error::Parser(e.rest().to_string()))?
|
||||||
|
.into_iter()
|
||||||
|
.filter_map(|expr| match expr {
|
||||||
|
LineBasedFileExpr::Comment => None,
|
||||||
|
LineBasedFileExpr::Expr(package) => Some(package),
|
||||||
|
})
|
||||||
|
.collect())
|
||||||
|
}
|
||||||
14
src/repo/profile/packages/parsers.rs
Normal file
14
src/repo/profile/packages/parsers.rs
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
use mon::{Parser, tag};
|
||||||
|
|
||||||
|
use crate::{Parseable, atom::Atom, repo::profile::packages::Package};
|
||||||
|
|
||||||
|
impl<'a> Parseable<'a, &'a str> for Package {
|
||||||
|
type Parser = impl Parser<&'a str, Output = Self>;
|
||||||
|
|
||||||
|
fn parser() -> Self::Parser {
|
||||||
|
Atom::parser()
|
||||||
|
.preceded_by(tag("*"))
|
||||||
|
.map(Package::Add)
|
||||||
|
.or(Atom::parser().preceded_by(tag("-*")).map(Package::Remove))
|
||||||
|
}
|
||||||
|
}
|
||||||
35
src/repo/profile/parsers.rs
Normal file
35
src/repo/profile/parsers.rs
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
use mon::{Parser, ParserIter, any, ascii_whitespace1, tag};
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
Parseable,
|
||||||
|
repo::profile::{FlagOperation, LineBasedFileExpr},
|
||||||
|
useflag::UseFlag,
|
||||||
|
};
|
||||||
|
|
||||||
|
impl<'a, T> Parseable<'a, &'a str> for LineBasedFileExpr<T>
|
||||||
|
where
|
||||||
|
T: Parseable<'a, &'a str>,
|
||||||
|
{
|
||||||
|
type Parser = impl Parser<&'a str, Output = Self>;
|
||||||
|
|
||||||
|
fn parser() -> Self::Parser {
|
||||||
|
let comment = tag("#")
|
||||||
|
.preceded_by(ascii_whitespace1().opt())
|
||||||
|
.followed_by(any().and_not(tag("\n")).repeated().many())
|
||||||
|
.map(|_| LineBasedFileExpr::Comment);
|
||||||
|
let expr = T::parser().map(|expr| LineBasedFileExpr::Expr(expr));
|
||||||
|
|
||||||
|
comment.or(expr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Parseable<'a, &'a str> for FlagOperation {
|
||||||
|
type Parser = impl Parser<&'a str, Output = Self>;
|
||||||
|
|
||||||
|
fn parser() -> Self::Parser {
|
||||||
|
UseFlag::parser()
|
||||||
|
.preceded_by(tag("-"))
|
||||||
|
.map(FlagOperation::Remove)
|
||||||
|
.or(UseFlag::parser().map(FlagOperation::Add))
|
||||||
|
}
|
||||||
|
}
|
||||||
94
src/repo/profile/useflags/mod.rs
Normal file
94
src/repo/profile/useflags/mod.rs
Normal file
@@ -0,0 +1,94 @@
|
|||||||
|
use std::{
|
||||||
|
io,
|
||||||
|
path::{Path, PathBuf},
|
||||||
|
};
|
||||||
|
|
||||||
|
use mon::{Parser, ParserIter, ascii_whitespace1, input::InputIter};
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
Parseable,
|
||||||
|
repo::profile::{FlagOperation, LineBasedFileExpr, Profile, read_config_files},
|
||||||
|
useflag::UseFlag,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Debug, thiserror::Error)]
|
||||||
|
pub enum Error {
|
||||||
|
#[error("{0}: io error: {1}")]
|
||||||
|
Io(PathBuf, io::Error),
|
||||||
|
#[error("parser error: {0}")]
|
||||||
|
Parser(String),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
pub(super) enum Kind {
|
||||||
|
Force,
|
||||||
|
Mask,
|
||||||
|
StableForce,
|
||||||
|
StableMask,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::unnecessary_wraps)]
|
||||||
|
pub(super) fn evaluate<P: AsRef<Path>>(
|
||||||
|
parents: &[Profile],
|
||||||
|
kind: Kind,
|
||||||
|
path: P,
|
||||||
|
) -> Result<Vec<UseFlag>, Error> {
|
||||||
|
let file_path = match kind {
|
||||||
|
Kind::Force => "use.force",
|
||||||
|
Kind::Mask => "use.mask",
|
||||||
|
Kind::StableForce => "use.stable.force",
|
||||||
|
Kind::StableMask => "use.stable.mask",
|
||||||
|
};
|
||||||
|
|
||||||
|
let parsed = match read_config_files(path.as_ref().join(file_path)) {
|
||||||
|
Ok(contents) => parse(&contents)?,
|
||||||
|
Err(e) if matches!(e.kind(), io::ErrorKind::NotFound) => Vec::new(),
|
||||||
|
Err(e) => return Err(Error::Io(path.as_ref().to_path_buf(), e)),
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(inherit(parents, kind, parsed))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn inherit(parents: &[Profile], kind: Kind, operations: Vec<FlagOperation>) -> Vec<UseFlag> {
|
||||||
|
let mut accumulated = Vec::new();
|
||||||
|
|
||||||
|
for parent in parents {
|
||||||
|
let source = match kind {
|
||||||
|
Kind::Force => parent.use_force(),
|
||||||
|
Kind::Mask => parent.use_mask(),
|
||||||
|
Kind::StableForce => parent.use_stable_force(),
|
||||||
|
Kind::StableMask => parent.use_stable_mask(),
|
||||||
|
};
|
||||||
|
|
||||||
|
for flag in source {
|
||||||
|
accumulated.push(flag.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for operation in operations {
|
||||||
|
match operation {
|
||||||
|
FlagOperation::Add(flag) => {
|
||||||
|
accumulated.push(flag);
|
||||||
|
}
|
||||||
|
FlagOperation::Remove(flag) => {
|
||||||
|
accumulated.retain(|v| *v != flag);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
accumulated
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse(contents: &str) -> Result<Vec<FlagOperation>, Error> {
|
||||||
|
Ok(LineBasedFileExpr::<FlagOperation>::parser()
|
||||||
|
.separated_by_with_opt_trailing(ascii_whitespace1())
|
||||||
|
.many()
|
||||||
|
.parse_finished(InputIter::new(contents))
|
||||||
|
.map_err(|e| Error::Parser(e.rest().to_string()))?
|
||||||
|
.into_iter()
|
||||||
|
.filter_map(|expr| match expr {
|
||||||
|
LineBasedFileExpr::Comment => None,
|
||||||
|
LineBasedFileExpr::Expr(flag_operation) => Some(flag_operation),
|
||||||
|
})
|
||||||
|
.collect())
|
||||||
|
}
|
||||||
@@ -2,12 +2,12 @@ use core::fmt;
|
|||||||
|
|
||||||
use get::Get;
|
use get::Get;
|
||||||
|
|
||||||
pub mod parsers;
|
mod parsers;
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Get)]
|
#[derive(Clone, Debug, PartialEq, Eq, Hash, Get)]
|
||||||
pub struct UseFlag(#[get(method = "name", kind = "deref")] String);
|
pub struct UseFlag(#[get(method = "name", kind = "deref")] String);
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Get)]
|
#[derive(Clone, Debug, PartialEq, Eq, Hash, Get)]
|
||||||
pub struct IUseFlag {
|
pub struct IUseFlag {
|
||||||
default: bool,
|
default: bool,
|
||||||
flag: UseFlag,
|
flag: UseFlag,
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
use mon::{Parser, ParserIter, alphanumeric, one_of, tag};
|
use mon::{Parser, ParserIter, ascii_alphanumeric, one_of, tag};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
Parseable,
|
Parseable,
|
||||||
@@ -9,8 +9,11 @@ impl<'a> Parseable<'a, &'a str> for UseFlag {
|
|||||||
type Parser = impl Parser<&'a str, Output = Self>;
|
type Parser = impl Parser<&'a str, Output = Self>;
|
||||||
|
|
||||||
fn parser() -> Self::Parser {
|
fn parser() -> Self::Parser {
|
||||||
let start = alphanumeric();
|
let start = ascii_alphanumeric();
|
||||||
let rest = alphanumeric().or(one_of("+_@-".chars())).repeated().many();
|
let rest = ascii_alphanumeric()
|
||||||
|
.or(one_of("+_@-".chars()))
|
||||||
|
.repeated()
|
||||||
|
.many();
|
||||||
|
|
||||||
start
|
start
|
||||||
.and(rest)
|
.and(rest)
|
||||||
|
|||||||
@@ -1 +1,21 @@
|
|||||||
subdir('fuzz')
|
tests = {}
|
||||||
|
|
||||||
|
subdir('porthole')
|
||||||
|
subdir('repo')
|
||||||
|
subdir('profile')
|
||||||
|
|
||||||
|
foreach test, test_args : tests
|
||||||
|
stem = fs.stem(test)
|
||||||
|
|
||||||
|
test(
|
||||||
|
f'test_@stem@',
|
||||||
|
executable(
|
||||||
|
f'test_@stem@',
|
||||||
|
test,
|
||||||
|
dependencies: [mon, itertools],
|
||||||
|
link_with: [gentoo_utils],
|
||||||
|
),
|
||||||
|
args: test_args,
|
||||||
|
timeout: 0,
|
||||||
|
)
|
||||||
|
endforeach
|
||||||
|
|||||||
5
tests/porthole/meson.build
Normal file
5
tests/porthole/meson.build
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
tests += {
|
||||||
|
meson.current_source_dir() / 'porthole.rs': [
|
||||||
|
meson.current_source_dir() / 'porthole.txt',
|
||||||
|
],
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
use std::cmp::Ordering;
|
use std::{cmp::Ordering, env, fs};
|
||||||
|
|
||||||
use gentoo_utils::{
|
use gentoo_utils::{
|
||||||
Parseable,
|
Parseable,
|
||||||
@@ -6,11 +6,6 @@ use gentoo_utils::{
|
|||||||
};
|
};
|
||||||
use mon::{Parser, input::InputIter, tag};
|
use mon::{Parser, input::InputIter, tag};
|
||||||
|
|
||||||
static PORTHOLE_TXT: &'static str = include_str!(concat!(
|
|
||||||
env!("CARGO_MANIFEST_DIR"),
|
|
||||||
"/testdata/porthole.txt"
|
|
||||||
));
|
|
||||||
|
|
||||||
enum Operator {
|
enum Operator {
|
||||||
Comment,
|
Comment,
|
||||||
Yes,
|
Yes,
|
||||||
@@ -31,16 +26,21 @@ fn parse_operator<'a>() -> impl Parser<&'a str, Output = Operator> {
|
|||||||
comment.or(yes).or(no).or(eq).or(gt).or(lt)
|
comment.or(yes).or(no).or(eq).or(gt).or(lt)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
fn main() {
|
||||||
fn test_porthole() {
|
let path = env::args()
|
||||||
for line in PORTHOLE_TXT.lines() {
|
.nth(1)
|
||||||
|
.expect("pass path to porthole.txt as first parameter");
|
||||||
|
|
||||||
|
let porthole_txt = fs::read_to_string(&path).expect("failed to open porthole.txt");
|
||||||
|
|
||||||
|
for line in porthole_txt.lines() {
|
||||||
if line.is_empty() {
|
if line.is_empty() {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
let operator = parse_operator()
|
let operator = parse_operator()
|
||||||
.parse_finished(InputIter::new(
|
.parse_finished(InputIter::new(
|
||||||
line.split_ascii_whitespace().nth(0).unwrap(),
|
line.split_ascii_whitespace().next().unwrap(),
|
||||||
))
|
))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
1
tests/profile/meson.build
Normal file
1
tests/profile/meson.build
Normal file
@@ -0,0 +1 @@
|
|||||||
|
tests += {meson.current_source_dir() / 'read_all_profiles.rs': []}
|
||||||
483
tests/profile/read_all_profiles.rs
Normal file
483
tests/profile/read_all_profiles.rs
Normal file
@@ -0,0 +1,483 @@
|
|||||||
|
use gentoo_utils::repo::Repo;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let profiles = [
|
||||||
|
"default/linux/alpha/23.0",
|
||||||
|
"default/linux/alpha/23.0/systemd",
|
||||||
|
"default/linux/alpha/23.0/desktop",
|
||||||
|
"default/linux/alpha/23.0/desktop/gnome",
|
||||||
|
"default/linux/alpha/23.0/desktop/gnome/systemd",
|
||||||
|
"default/linux/alpha/23.0/split-usr",
|
||||||
|
"default/linux/alpha/23.0/split-usr/desktop",
|
||||||
|
"default/linux/alpha/23.0/split-usr/desktop/gnome",
|
||||||
|
"default/linux/amd64/23.0",
|
||||||
|
"default/linux/amd64/23.0/systemd",
|
||||||
|
"default/linux/amd64/23.0/desktop",
|
||||||
|
"default/linux/amd64/23.0/desktop/systemd",
|
||||||
|
"default/linux/amd64/23.0/desktop/gnome",
|
||||||
|
"default/linux/amd64/23.0/desktop/gnome/systemd",
|
||||||
|
"default/linux/amd64/23.0/desktop/plasma",
|
||||||
|
"default/linux/amd64/23.0/desktop/plasma/systemd",
|
||||||
|
"default/linux/amd64/23.0/no-multilib",
|
||||||
|
"default/linux/amd64/23.0/no-multilib/systemd",
|
||||||
|
"default/linux/amd64/23.0/no-multilib/hardened",
|
||||||
|
"default/linux/amd64/23.0/no-multilib/hardened/systemd",
|
||||||
|
"default/linux/amd64/23.0/no-multilib/hardened/selinux",
|
||||||
|
"default/linux/amd64/23.0/no-multilib/hardened/selinux/systemd",
|
||||||
|
"default/linux/amd64/23.0/no-multilib/prefix",
|
||||||
|
"default/linux/amd64/23.0/no-multilib/prefix/kernel-2.6.32+",
|
||||||
|
"default/linux/amd64/23.0/no-multilib/prefix/kernel-2.6.16+",
|
||||||
|
"default/linux/amd64/23.0/no-multilib/prefix/kernel-3.2+",
|
||||||
|
"default/linux/amd64/23.0/llvm",
|
||||||
|
"default/linux/amd64/23.0/llvm/systemd",
|
||||||
|
"default/linux/amd64/23.0/hardened",
|
||||||
|
"default/linux/amd64/23.0/hardened/systemd",
|
||||||
|
"default/linux/amd64/23.0/hardened/selinux",
|
||||||
|
"default/linux/amd64/23.0/hardened/selinux/systemd",
|
||||||
|
"default/linux/amd64/23.0/split-usr",
|
||||||
|
"default/linux/amd64/23.0/split-usr/desktop",
|
||||||
|
"default/linux/amd64/23.0/split-usr/desktop/gnome",
|
||||||
|
"default/linux/amd64/23.0/split-usr/desktop/plasma",
|
||||||
|
"default/linux/amd64/23.0/split-usr/no-multilib",
|
||||||
|
"default/linux/amd64/23.0/split-usr/no-multilib/selinux",
|
||||||
|
"default/linux/amd64/23.0/split-usr/no-multilib/hardened",
|
||||||
|
"default/linux/amd64/23.0/split-usr/no-multilib/hardened/selinux",
|
||||||
|
"default/linux/amd64/23.0/split-usr/no-multilib/prefix",
|
||||||
|
"default/linux/amd64/23.0/split-usr/no-multilib/prefix/kernel-2.6.32+",
|
||||||
|
"default/linux/amd64/23.0/split-usr/no-multilib/prefix/kernel-2.6.16+",
|
||||||
|
"default/linux/amd64/23.0/split-usr/no-multilib/prefix/kernel-3.2+",
|
||||||
|
"default/linux/amd64/23.0/split-usr/llvm",
|
||||||
|
"default/linux/amd64/23.0/split-usr/hardened",
|
||||||
|
"default/linux/amd64/23.0/split-usr/hardened/selinux",
|
||||||
|
"default/linux/amd64/23.0/x32",
|
||||||
|
"default/linux/amd64/23.0/x32/systemd",
|
||||||
|
"default/linux/amd64/23.0/split-usr/x32",
|
||||||
|
"default/linux/arm/23.0",
|
||||||
|
"default/linux/arm/23.0/desktop",
|
||||||
|
"default/linux/arm/23.0/desktop/gnome",
|
||||||
|
"default/linux/arm/23.0/desktop/gnome/systemd",
|
||||||
|
"default/linux/arm/23.0/desktop/plasma",
|
||||||
|
"default/linux/arm/23.0/desktop/plasma/systemd",
|
||||||
|
"default/linux/arm/23.0/armv4",
|
||||||
|
"default/linux/arm/23.0/armv4t",
|
||||||
|
"default/linux/arm/23.0/armv4t/systemd",
|
||||||
|
"default/linux/arm/23.0/armv5te",
|
||||||
|
"default/linux/arm/23.0/armv5te/systemd",
|
||||||
|
"default/linux/arm/23.0/armv6j_sf",
|
||||||
|
"default/linux/arm/23.0/armv6j_sf/hardened",
|
||||||
|
"default/linux/arm/23.0/armv6j_sf/hardened/selinux",
|
||||||
|
"default/linux/arm/23.0/armv6j_sf/systemd",
|
||||||
|
"default/linux/arm/23.0/armv6j_hf",
|
||||||
|
"default/linux/arm/23.0/armv6j_hf/hardened",
|
||||||
|
"default/linux/arm/23.0/armv6j_hf/hardened/selinux",
|
||||||
|
"default/linux/arm/23.0/armv6j_hf/systemd",
|
||||||
|
"default/linux/arm/23.0/armv7a_sf",
|
||||||
|
"default/linux/arm/23.0/armv7a_sf/hardened",
|
||||||
|
"default/linux/arm/23.0/armv7a_sf/hardened/selinux",
|
||||||
|
"default/linux/arm/23.0/armv7a_sf/desktop",
|
||||||
|
"default/linux/arm/23.0/armv7a_sf/desktop/gnome",
|
||||||
|
"default/linux/arm/23.0/armv7a_sf/desktop/gnome/systemd",
|
||||||
|
"default/linux/arm/23.0/armv7a_sf/desktop/plasma",
|
||||||
|
"default/linux/arm/23.0/armv7a_sf/desktop/plasma/systemd",
|
||||||
|
"default/linux/arm/23.0/armv7a_sf/systemd",
|
||||||
|
"default/linux/arm/23.0/armv7a_hf",
|
||||||
|
"default/linux/arm/23.0/armv7a_hf/hardened",
|
||||||
|
"default/linux/arm/23.0/armv7a_hf/hardened/selinux",
|
||||||
|
"default/linux/arm/23.0/armv7a_hf/desktop",
|
||||||
|
"default/linux/arm/23.0/armv7a_hf/desktop/gnome",
|
||||||
|
"default/linux/arm/23.0/armv7a_hf/desktop/gnome/systemd",
|
||||||
|
"default/linux/arm/23.0/armv7a_hf/desktop/plasma",
|
||||||
|
"default/linux/arm/23.0/armv7a_hf/desktop/plasma/systemd",
|
||||||
|
"default/linux/arm/23.0/armv7a_hf/systemd",
|
||||||
|
"default/linux/arm/23.0/split-usr",
|
||||||
|
"default/linux/arm/23.0/split-usr/desktop",
|
||||||
|
"default/linux/arm/23.0/split-usr/desktop/gnome",
|
||||||
|
"default/linux/arm/23.0/split-usr/desktop/plasma",
|
||||||
|
"default/linux/arm/23.0/split-usr/armv4",
|
||||||
|
"default/linux/arm/23.0/split-usr/armv4t",
|
||||||
|
"default/linux/arm/23.0/split-usr/armv5te",
|
||||||
|
"default/linux/arm/23.0/split-usr/armv6j_sf",
|
||||||
|
"default/linux/arm/23.0/split-usr/armv6j_sf/hardened",
|
||||||
|
"default/linux/arm/23.0/split-usr/armv6j_sf/hardened/selinux",
|
||||||
|
"default/linux/arm/23.0/split-usr/armv6j_hf",
|
||||||
|
"default/linux/arm/23.0/split-usr/armv6j_hf/hardened",
|
||||||
|
"default/linux/arm/23.0/split-usr/armv6j_hf/hardened/selinux",
|
||||||
|
"default/linux/arm/23.0/split-usr/armv7a_sf",
|
||||||
|
"default/linux/arm/23.0/split-usr/armv7a_sf/hardened",
|
||||||
|
"default/linux/arm/23.0/split-usr/armv7a_sf/hardened/selinux",
|
||||||
|
"default/linux/arm/23.0/split-usr/armv7a_sf/desktop",
|
||||||
|
"default/linux/arm/23.0/split-usr/armv7a_sf/desktop/gnome",
|
||||||
|
"default/linux/arm/23.0/split-usr/armv7a_sf/desktop/plasma",
|
||||||
|
"default/linux/arm/23.0/split-usr/armv7a_hf",
|
||||||
|
"default/linux/arm/23.0/split-usr/armv7a_hf/hardened",
|
||||||
|
"default/linux/arm/23.0/split-usr/armv7a_hf/hardened/selinux",
|
||||||
|
"default/linux/arm/23.0/split-usr/armv7a_hf/desktop",
|
||||||
|
"default/linux/arm/23.0/split-usr/armv7a_hf/desktop/gnome",
|
||||||
|
"default/linux/arm/23.0/split-usr/armv7a_hf/desktop/plasma",
|
||||||
|
"default/linux/arm64/23.0",
|
||||||
|
"default/linux/arm64/23.0/hardened",
|
||||||
|
"default/linux/arm64/23.0/hardened/systemd",
|
||||||
|
"default/linux/arm64/23.0/hardened/selinux",
|
||||||
|
"default/linux/arm64/23.0/hardened/selinux/systemd",
|
||||||
|
"default/linux/arm64/23.0/desktop",
|
||||||
|
"default/linux/arm64/23.0/desktop/gnome",
|
||||||
|
"default/linux/arm64/23.0/desktop/gnome/systemd",
|
||||||
|
"default/linux/arm64/23.0/desktop/plasma",
|
||||||
|
"default/linux/arm64/23.0/desktop/plasma/systemd",
|
||||||
|
"default/linux/arm64/23.0/desktop/systemd",
|
||||||
|
"default/linux/arm64/23.0/systemd",
|
||||||
|
"default/linux/arm64/23.0/llvm",
|
||||||
|
"default/linux/arm64/23.0/llvm/systemd",
|
||||||
|
"default/linux/arm64/23.0/split-usr",
|
||||||
|
"default/linux/arm64/23.0/split-usr/hardened",
|
||||||
|
"default/linux/arm64/23.0/split-usr/hardened/selinux",
|
||||||
|
"default/linux/arm64/23.0/split-usr/desktop",
|
||||||
|
"default/linux/arm64/23.0/split-usr/desktop/gnome",
|
||||||
|
"default/linux/arm64/23.0/split-usr/desktop/plasma",
|
||||||
|
"default/linux/arm64/23.0/split-usr/llvm",
|
||||||
|
"default/linux/arm64/23.0/big-endian",
|
||||||
|
"default/linux/arm64/23.0/big-endian/systemd",
|
||||||
|
"default/linux/arm64/23.0/split-usr/big-endian",
|
||||||
|
"default/linux/hppa/23.0/hppa1.1",
|
||||||
|
"default/linux/hppa/23.0/hppa1.1/systemd",
|
||||||
|
"default/linux/hppa/23.0/hppa1.1/desktop",
|
||||||
|
"default/linux/hppa/23.0/hppa1.1/desktop/systemd",
|
||||||
|
"default/linux/hppa/23.0/hppa1.1/split-usr",
|
||||||
|
"default/linux/hppa/23.0/hppa1.1/split-usr/desktop",
|
||||||
|
"default/linux/hppa/23.0/hppa2.0",
|
||||||
|
"default/linux/hppa/23.0/hppa2.0/systemd",
|
||||||
|
"default/linux/hppa/23.0/hppa2.0/desktop",
|
||||||
|
"default/linux/hppa/23.0/hppa2.0/desktop/systemd",
|
||||||
|
"default/linux/hppa/23.0/hppa2.0/split-usr",
|
||||||
|
"default/linux/hppa/23.0/hppa2.0/split-usr/desktop",
|
||||||
|
"default/linux/loong/23.0/la64v100/lp64d",
|
||||||
|
"default/linux/loong/23.0/la64v100/lp64d/llvm",
|
||||||
|
"default/linux/loong/23.0/la64v100/lp64d/llvm/systemd",
|
||||||
|
"default/linux/loong/23.0/la64v100/lp64d/desktop",
|
||||||
|
"default/linux/loong/23.0/la64v100/lp64d/desktop/gnome",
|
||||||
|
"default/linux/loong/23.0/la64v100/lp64d/desktop/gnome/systemd",
|
||||||
|
"default/linux/loong/23.0/la64v100/lp64d/desktop/plasma",
|
||||||
|
"default/linux/loong/23.0/la64v100/lp64d/desktop/plasma/systemd",
|
||||||
|
"default/linux/loong/23.0/la64v100/lp64d/desktop/systemd",
|
||||||
|
"default/linux/loong/23.0/la64v100/lp64d/systemd",
|
||||||
|
"default/linux/loong/23.0/la64v100/split-usr/lp64d",
|
||||||
|
"default/linux/loong/23.0/la64v100/split-usr/lp64d/desktop",
|
||||||
|
"default/linux/loong/23.0/la64v100/split-usr/lp64d/desktop/gnome",
|
||||||
|
"default/linux/loong/23.0/la64v100/split-usr/lp64d/desktop/plasma",
|
||||||
|
"default/linux/m68k/23.0",
|
||||||
|
"default/linux/m68k/23.0/systemd",
|
||||||
|
"default/linux/m68k/23.0/split-usr",
|
||||||
|
"default/linux/m68k/23.0/time64",
|
||||||
|
"default/linux/mips/23.0/mipsel/o32_sf",
|
||||||
|
"default/linux/mips/23.0/mipsel/o32_sf/systemd",
|
||||||
|
"default/linux/mips/23.0/mipsel/o32",
|
||||||
|
"default/linux/mips/23.0/mipsel/o32/systemd",
|
||||||
|
"default/linux/mips/23.0/mipsel/n32",
|
||||||
|
"default/linux/mips/23.0/mipsel/n32/systemd",
|
||||||
|
"default/linux/mips/23.0/mipsel/n64",
|
||||||
|
"default/linux/mips/23.0/mipsel/n64/systemd",
|
||||||
|
"default/linux/mips/23.0/mipsel/multilib/n32",
|
||||||
|
"default/linux/mips/23.0/mipsel/multilib/n32/systemd",
|
||||||
|
"default/linux/mips/23.0/mipsel/multilib/n64",
|
||||||
|
"default/linux/mips/23.0/mipsel/multilib/n64/systemd",
|
||||||
|
"default/linux/mips/23.0/o32_sf",
|
||||||
|
"default/linux/mips/23.0/o32_sf/systemd",
|
||||||
|
"default/linux/mips/23.0/o32",
|
||||||
|
"default/linux/mips/23.0/o32/systemd",
|
||||||
|
"default/linux/mips/23.0/n32",
|
||||||
|
"default/linux/mips/23.0/n32/systemd",
|
||||||
|
"default/linux/mips/23.0/n64",
|
||||||
|
"default/linux/mips/23.0/n64/systemd",
|
||||||
|
"default/linux/mips/23.0/multilib/n32",
|
||||||
|
"default/linux/mips/23.0/multilib/n32/systemd",
|
||||||
|
"default/linux/mips/23.0/multilib/n64",
|
||||||
|
"default/linux/mips/23.0/multilib/n64/systemd",
|
||||||
|
"default/linux/mips/23.0/split-usr/mipsel/o32_sf",
|
||||||
|
"default/linux/mips/23.0/split-usr/mipsel/o32",
|
||||||
|
"default/linux/mips/23.0/split-usr/mipsel/n32",
|
||||||
|
"default/linux/mips/23.0/split-usr/mipsel/n64",
|
||||||
|
"default/linux/mips/23.0/split-usr/mipsel/multilib/n32",
|
||||||
|
"default/linux/mips/23.0/split-usr/mipsel/multilib/n64",
|
||||||
|
"default/linux/mips/23.0/split-usr/o32_sf",
|
||||||
|
"default/linux/mips/23.0/split-usr/o32",
|
||||||
|
"default/linux/mips/23.0/split-usr/n32",
|
||||||
|
"default/linux/mips/23.0/split-usr/n64",
|
||||||
|
"default/linux/mips/23.0/split-usr/multilib/n32",
|
||||||
|
"default/linux/mips/23.0/split-usr/multilib/n64",
|
||||||
|
"default/linux/mips/23.0/time64/mipsel/o32_sf",
|
||||||
|
"default/linux/mips/23.0/time64/mipsel/o32_sf/systemd",
|
||||||
|
"default/linux/mips/23.0/time64/mipsel/o32",
|
||||||
|
"default/linux/mips/23.0/time64/mipsel/o32/systemd",
|
||||||
|
"default/linux/mips/23.0/time64/mipsel/n32",
|
||||||
|
"default/linux/mips/23.0/time64/mipsel/n32/systemd",
|
||||||
|
"default/linux/mips/23.0/time64/mipsel/multilib/n32",
|
||||||
|
"default/linux/mips/23.0/time64/mipsel/multilib/n32/systemd",
|
||||||
|
"default/linux/mips/23.0/time64/mipsel/multilib/n64",
|
||||||
|
"default/linux/mips/23.0/time64/mipsel/multilib/n64/systemd",
|
||||||
|
"default/linux/mips/23.0/time64/o32_sf",
|
||||||
|
"default/linux/mips/23.0/time64/o32_sf/systemd",
|
||||||
|
"default/linux/mips/23.0/time64/o32",
|
||||||
|
"default/linux/mips/23.0/time64/o32/systemd",
|
||||||
|
"default/linux/mips/23.0/time64/n32",
|
||||||
|
"default/linux/mips/23.0/time64/n32/systemd",
|
||||||
|
"default/linux/mips/23.0/time64/multilib/n32",
|
||||||
|
"default/linux/mips/23.0/time64/multilib/n32/systemd",
|
||||||
|
"default/linux/mips/23.0/time64/multilib/n64",
|
||||||
|
"default/linux/mips/23.0/time64/multilib/n64/systemd",
|
||||||
|
"default/linux/mips/23.0/time64/split-usr/mipsel/o32_sf",
|
||||||
|
"default/linux/mips/23.0/time64/split-usr/mipsel/o32",
|
||||||
|
"default/linux/mips/23.0/time64/split-usr/mipsel/n32",
|
||||||
|
"default/linux/mips/23.0/time64/split-usr/mipsel/multilib/n32",
|
||||||
|
"default/linux/mips/23.0/time64/split-usr/mipsel/multilib/n64",
|
||||||
|
"default/linux/mips/23.0/time64/split-usr/o32_sf",
|
||||||
|
"default/linux/mips/23.0/time64/split-usr/o32",
|
||||||
|
"default/linux/mips/23.0/time64/split-usr/n32",
|
||||||
|
"default/linux/mips/23.0/time64/split-usr/multilib/n32",
|
||||||
|
"default/linux/mips/23.0/time64/split-usr/multilib/n64",
|
||||||
|
"default/linux/ppc/23.0",
|
||||||
|
"default/linux/ppc/23.0/desktop",
|
||||||
|
"default/linux/ppc/23.0/desktop/gnome",
|
||||||
|
"default/linux/ppc/23.0/desktop/gnome/systemd",
|
||||||
|
"default/linux/ppc/23.0/systemd",
|
||||||
|
"default/linux/ppc/23.0/split-usr",
|
||||||
|
"default/linux/ppc/23.0/split-usr/desktop",
|
||||||
|
"default/linux/ppc/23.0/split-usr/desktop/gnome",
|
||||||
|
"default/linux/ppc/23.0/time64",
|
||||||
|
"default/linux/ppc/23.0/time64/desktop",
|
||||||
|
"default/linux/ppc/23.0/time64/desktop/gnome",
|
||||||
|
"default/linux/ppc/23.0/time64/desktop/gnome/systemd",
|
||||||
|
"default/linux/ppc/23.0/time64/systemd",
|
||||||
|
"default/linux/ppc/23.0/time64/split-usr",
|
||||||
|
"default/linux/ppc/23.0/time64/split-usr/desktop",
|
||||||
|
"default/linux/ppc/23.0/time64/split-usr/desktop/gnome",
|
||||||
|
"default/linux/ppc64/23.0",
|
||||||
|
"default/linux/ppc64/23.0/desktop",
|
||||||
|
"default/linux/ppc64/23.0/desktop/gnome",
|
||||||
|
"default/linux/ppc64/23.0/desktop/gnome/systemd",
|
||||||
|
"default/linux/ppc64/23.0/systemd",
|
||||||
|
"default/linux/ppc64/23.0/split-usr",
|
||||||
|
"default/linux/ppc64/23.0/split-usr/desktop",
|
||||||
|
"default/linux/ppc64/23.0/split-usr/desktop/gnome",
|
||||||
|
"default/linux/ppc64le/23.0",
|
||||||
|
"default/linux/ppc64le/23.0/desktop",
|
||||||
|
"default/linux/ppc64le/23.0/desktop/gnome",
|
||||||
|
"default/linux/ppc64le/23.0/desktop/gnome/systemd",
|
||||||
|
"default/linux/ppc64le/23.0/desktop/plasma",
|
||||||
|
"default/linux/ppc64le/23.0/desktop/plasma/systemd",
|
||||||
|
"default/linux/ppc64le/23.0/desktop/systemd",
|
||||||
|
"default/linux/ppc64le/23.0/systemd",
|
||||||
|
"default/linux/ppc64le/23.0/split-usr",
|
||||||
|
"default/linux/ppc64le/23.0/split-usr/desktop",
|
||||||
|
"default/linux/ppc64le/23.0/split-usr/desktop/gnome",
|
||||||
|
"default/linux/ppc64le/23.0/split-usr/desktop/plasma",
|
||||||
|
"default/linux/riscv/23.0/rv64/lp64d",
|
||||||
|
"default/linux/riscv/23.0/rv64/lp64d/desktop",
|
||||||
|
"default/linux/riscv/23.0/rv64/lp64d/desktop/gnome",
|
||||||
|
"default/linux/riscv/23.0/rv64/lp64d/desktop/gnome/systemd",
|
||||||
|
"default/linux/riscv/23.0/rv64/lp64d/desktop/plasma",
|
||||||
|
"default/linux/riscv/23.0/rv64/lp64d/desktop/plasma/systemd",
|
||||||
|
"default/linux/riscv/23.0/rv64/lp64d/desktop/systemd",
|
||||||
|
"default/linux/riscv/23.0/rv64/lp64d/systemd",
|
||||||
|
"default/linux/riscv/23.0/rv64/lp64",
|
||||||
|
"default/linux/riscv/23.0/rv64/lp64/desktop",
|
||||||
|
"default/linux/riscv/23.0/rv64/lp64/desktop/gnome",
|
||||||
|
"default/linux/riscv/23.0/rv64/lp64/desktop/gnome/systemd",
|
||||||
|
"default/linux/riscv/23.0/rv64/lp64/desktop/plasma",
|
||||||
|
"default/linux/riscv/23.0/rv64/lp64/desktop/plasma/systemd",
|
||||||
|
"default/linux/riscv/23.0/rv64/lp64/desktop/systemd",
|
||||||
|
"default/linux/riscv/23.0/rv64/lp64/systemd",
|
||||||
|
"default/linux/riscv/23.0/rv64/multilib",
|
||||||
|
"default/linux/riscv/23.0/rv64/multilib/systemd",
|
||||||
|
"default/linux/riscv/23.0/rv32/ilp32d",
|
||||||
|
"default/linux/riscv/23.0/rv32/ilp32d/systemd",
|
||||||
|
"default/linux/riscv/23.0/rv32/ilp32",
|
||||||
|
"default/linux/riscv/23.0/rv32/ilp32/systemd",
|
||||||
|
"default/linux/riscv/23.0/rv64/split-usr/lp64d",
|
||||||
|
"default/linux/riscv/23.0/rv64/split-usr/lp64d/desktop",
|
||||||
|
"default/linux/riscv/23.0/rv64/split-usr/lp64d/desktop/gnome",
|
||||||
|
"default/linux/riscv/23.0/rv64/split-usr/lp64d/desktop/plasma",
|
||||||
|
"default/linux/riscv/23.0/rv64/split-usr/lp64",
|
||||||
|
"default/linux/riscv/23.0/rv64/split-usr/lp64/desktop",
|
||||||
|
"default/linux/riscv/23.0/rv64/split-usr/lp64/desktop/gnome",
|
||||||
|
"default/linux/riscv/23.0/rv64/split-usr/lp64/desktop/plasma",
|
||||||
|
"default/linux/riscv/23.0/rv64/split-usr/multilib",
|
||||||
|
"default/linux/riscv/23.0/rv32/split-usr/ilp32d",
|
||||||
|
"default/linux/riscv/23.0/rv32/split-usr/ilp32",
|
||||||
|
"default/linux/s390/23.0",
|
||||||
|
"default/linux/s390/23.0/systemd",
|
||||||
|
"default/linux/s390/23.0/split-usr",
|
||||||
|
"default/linux/s390/23.0/split-usr/s390x",
|
||||||
|
"default/linux/s390/23.0/s390x",
|
||||||
|
"default/linux/s390/23.0/s390x/systemd",
|
||||||
|
"default/linux/s390/23.0/time64",
|
||||||
|
"default/linux/s390/23.0/time64/systemd",
|
||||||
|
"default/linux/s390/23.0/time64/split-usr",
|
||||||
|
"default/linux/sparc/23.0",
|
||||||
|
"default/linux/sparc/23.0/desktop",
|
||||||
|
"default/linux/sparc/23.0/systemd",
|
||||||
|
"default/linux/sparc/23.0/64ul",
|
||||||
|
"default/linux/sparc/23.0/64ul/desktop",
|
||||||
|
"default/linux/sparc/23.0/64ul/systemd",
|
||||||
|
"default/linux/sparc/23.0/split-usr",
|
||||||
|
"default/linux/sparc/23.0/split-usr/desktop",
|
||||||
|
"default/linux/sparc/23.0/split-usr/64ul",
|
||||||
|
"default/linux/sparc/23.0/split-usr/64ul/desktop",
|
||||||
|
"default/linux/x86/23.0/i686",
|
||||||
|
"default/linux/x86/23.0/i686/systemd",
|
||||||
|
"default/linux/x86/23.0/i686/hardened",
|
||||||
|
"default/linux/x86/23.0/i686/hardened/selinux",
|
||||||
|
"default/linux/x86/23.0/i686/desktop",
|
||||||
|
"default/linux/x86/23.0/i686/desktop/gnome",
|
||||||
|
"default/linux/x86/23.0/i686/desktop/gnome/systemd",
|
||||||
|
"default/linux/x86/23.0/i686/desktop/plasma",
|
||||||
|
"default/linux/x86/23.0/i686/desktop/plasma/systemd",
|
||||||
|
"default/linux/x86/23.0/i686/prefix",
|
||||||
|
"default/linux/x86/23.0/i686/prefix/kernel-2.6.32+",
|
||||||
|
"default/linux/x86/23.0/i686/prefix/kernel-2.6.16+",
|
||||||
|
"default/linux/x86/23.0/i686/prefix/kernel-3.2+",
|
||||||
|
"default/linux/x86/23.0/i686/split-usr",
|
||||||
|
"default/linux/x86/23.0/i686/split-usr/hardened",
|
||||||
|
"default/linux/x86/23.0/i686/split-usr/hardened/selinux",
|
||||||
|
"default/linux/x86/23.0/i686/split-usr/desktop",
|
||||||
|
"default/linux/x86/23.0/i686/split-usr/desktop/gnome",
|
||||||
|
"default/linux/x86/23.0/i686/split-usr/desktop/plasma",
|
||||||
|
"default/linux/x86/23.0/i686/split-usr/prefix",
|
||||||
|
"default/linux/x86/23.0/i686/split-usr/prefix/kernel-2.6.32+",
|
||||||
|
"default/linux/x86/23.0/i686/split-usr/prefix/kernel-2.6.16+",
|
||||||
|
"default/linux/x86/23.0/i686/split-usr/prefix/kernel-3.2+",
|
||||||
|
"default/linux/x86/23.0/i686/time64",
|
||||||
|
"default/linux/x86/23.0/i686/time64/systemd",
|
||||||
|
"default/linux/x86/23.0/i686/time64/hardened",
|
||||||
|
"default/linux/x86/23.0/i686/time64/hardened/selinux",
|
||||||
|
"default/linux/x86/23.0/i686/time64/desktop",
|
||||||
|
"default/linux/x86/23.0/i686/time64/desktop/gnome",
|
||||||
|
"default/linux/x86/23.0/i686/time64/desktop/gnome/systemd",
|
||||||
|
"default/linux/x86/23.0/i686/time64/desktop/plasma",
|
||||||
|
"default/linux/x86/23.0/i686/time64/desktop/plasma/systemd",
|
||||||
|
"default/linux/x86/23.0/i686/time64/split-usr",
|
||||||
|
"default/linux/x86/23.0/i686/time64/split-usr/hardened",
|
||||||
|
"default/linux/x86/23.0/i686/time64/split-usr/hardened/selinux",
|
||||||
|
"default/linux/x86/23.0/i686/time64/split-usr/desktop",
|
||||||
|
"default/linux/x86/23.0/i686/time64/split-usr/desktop/gnome",
|
||||||
|
"default/linux/x86/23.0/i686/time64/split-usr/desktop/plasma",
|
||||||
|
"default/linux/x86/23.0/i486",
|
||||||
|
"default/linux/x86/23.0/i486/systemd",
|
||||||
|
"default/linux/x86/23.0/i486/hardened",
|
||||||
|
"default/linux/x86/23.0/i486/hardened/selinux",
|
||||||
|
"default/linux/x86/23.0/i486/split-usr",
|
||||||
|
"default/linux/x86/23.0/i486/split-usr/hardened",
|
||||||
|
"default/linux/x86/23.0/i486/split-usr/hardened/selinux",
|
||||||
|
"default/linux/x86/23.0/i486/time64",
|
||||||
|
"default/linux/x86/23.0/i486/time64/systemd",
|
||||||
|
"default/linux/x86/23.0/i486/time64/hardened",
|
||||||
|
"default/linux/x86/23.0/i486/time64/hardened/selinux",
|
||||||
|
"default/linux/x86/23.0/i486/time64/split-usr",
|
||||||
|
"default/linux/x86/23.0/i486/time64/split-usr/hardened",
|
||||||
|
"default/linux/x86/23.0/i486/time64/split-usr/hardened/selinux",
|
||||||
|
"default/linux/amd64/23.0/musl",
|
||||||
|
"default/linux/amd64/23.0/musl/llvm",
|
||||||
|
"default/linux/amd64/23.0/musl/hardened",
|
||||||
|
"default/linux/amd64/23.0/musl/hardened/selinux",
|
||||||
|
"default/linux/amd64/23.0/split-usr/musl",
|
||||||
|
"default/linux/amd64/23.0/split-usr/musl/llvm",
|
||||||
|
"default/linux/amd64/23.0/split-usr/musl/hardened",
|
||||||
|
"default/linux/amd64/23.0/split-usr/musl/hardened/selinux",
|
||||||
|
"default/linux/arm/23.0/armv6j_hf/musl",
|
||||||
|
"default/linux/arm/23.0/armv6j_hf/musl/hardened",
|
||||||
|
"default/linux/arm/23.0/armv6j_hf/musl/hardened/selinux",
|
||||||
|
"default/linux/arm/23.0/armv7a_hf/musl",
|
||||||
|
"default/linux/arm/23.0/armv7a_hf/musl/hardened",
|
||||||
|
"default/linux/arm/23.0/armv7a_hf/musl/hardened/selinux",
|
||||||
|
"default/linux/arm/23.0/split-usr/armv6j_hf/musl",
|
||||||
|
"default/linux/arm/23.0/split-usr/armv6j_hf/musl/hardened",
|
||||||
|
"default/linux/arm/23.0/split-usr/armv6j_hf/musl/hardened/selinux",
|
||||||
|
"default/linux/arm/23.0/split-usr/armv7a_hf/musl",
|
||||||
|
"default/linux/arm/23.0/split-usr/armv7a_hf/musl/hardened",
|
||||||
|
"default/linux/arm/23.0/split-usr/armv7a_hf/musl/hardened/selinux",
|
||||||
|
"default/linux/arm64/23.0/musl",
|
||||||
|
"default/linux/arm64/23.0/musl/llvm",
|
||||||
|
"default/linux/arm64/23.0/musl/hardened",
|
||||||
|
"default/linux/arm64/23.0/musl/hardened/selinux",
|
||||||
|
"default/linux/arm64/23.0/split-usr/musl",
|
||||||
|
"default/linux/arm64/23.0/split-usr/musl/llvm",
|
||||||
|
"default/linux/arm64/23.0/split-usr/musl/hardened",
|
||||||
|
"default/linux/arm64/23.0/split-usr/musl/hardened/selinux",
|
||||||
|
"default/linux/m68k/23.0/musl",
|
||||||
|
"default/linux/m68k/23.0/split-usr/musl",
|
||||||
|
"default/linux/mips/23.0/mipsel/o32/musl",
|
||||||
|
"default/linux/mips/23.0/mipsel/n64/musl",
|
||||||
|
"default/linux/mips/23.0/o32/musl",
|
||||||
|
"default/linux/mips/23.0/n64/musl",
|
||||||
|
"default/linux/mips/23.0/split-usr/mipsel/o32/musl",
|
||||||
|
"default/linux/mips/23.0/split-usr/mipsel/n64/musl",
|
||||||
|
"default/linux/mips/23.0/split-usr/o32/musl",
|
||||||
|
"default/linux/mips/23.0/split-usr/n64/musl",
|
||||||
|
"default/linux/ppc/23.0/musl",
|
||||||
|
"default/linux/ppc/23.0/musl/hardened",
|
||||||
|
"default/linux/ppc/23.0/split-usr/musl",
|
||||||
|
"default/linux/ppc/23.0/split-usr/musl/hardened",
|
||||||
|
"default/linux/ppc64/23.0/musl",
|
||||||
|
"default/linux/ppc64/23.0/musl/hardened",
|
||||||
|
"default/linux/ppc64/23.0/split-usr/musl",
|
||||||
|
"default/linux/ppc64/23.0/split-usr/musl/hardened",
|
||||||
|
"default/linux/ppc64le/23.0/musl",
|
||||||
|
"default/linux/ppc64le/23.0/musl/hardened",
|
||||||
|
"default/linux/ppc64le/23.0/split-usr/musl",
|
||||||
|
"default/linux/ppc64le/23.0/split-usr/musl/hardened",
|
||||||
|
"default/linux/riscv/23.0/rv64/lp64d/musl",
|
||||||
|
"default/linux/riscv/23.0/rv64/lp64/musl",
|
||||||
|
"default/linux/riscv/23.0/rv64/split-usr/lp64d/musl",
|
||||||
|
"default/linux/riscv/23.0/rv64/split-usr/lp64/musl",
|
||||||
|
"default/linux/riscv/23.0/rv32/ilp32d/musl",
|
||||||
|
"default/linux/riscv/23.0/rv32/ilp32/musl",
|
||||||
|
"default/linux/riscv/23.0/rv32/split-usr/ilp32d/musl",
|
||||||
|
"default/linux/riscv/23.0/rv32/split-usr/ilp32/musl",
|
||||||
|
"default/linux/x86/23.0/i686/musl",
|
||||||
|
"default/linux/x86/23.0/i686/musl/selinux",
|
||||||
|
"default/linux/x86/23.0/i686/split-usr/musl",
|
||||||
|
"default/linux/x86/23.0/i686/split-usr/musl/selinux",
|
||||||
|
"default/linux/x86/23.0/i486/musl",
|
||||||
|
"default/linux/x86/23.0/i486/musl/selinux",
|
||||||
|
"default/linux/x86/23.0/i486/split-usr/musl",
|
||||||
|
"default/linux/x86/23.0/i486/split-usr/musl/selinux",
|
||||||
|
"prefix/linux/amd64",
|
||||||
|
"prefix/linux/arm",
|
||||||
|
"prefix/linux/ppc64",
|
||||||
|
"prefix/linux/ppc64le",
|
||||||
|
"prefix/linux/riscv",
|
||||||
|
"prefix/linux/x86",
|
||||||
|
"prefix/darwin/macos/10.5/ppc/gcc",
|
||||||
|
"prefix/darwin/macos/10.5/x86/gcc",
|
||||||
|
"prefix/darwin/macos/10.11/x64",
|
||||||
|
"prefix/darwin/macos/10.13/x64",
|
||||||
|
"prefix/darwin/macos/10.13/x64/gcc",
|
||||||
|
"prefix/darwin/macos/10.14/x64",
|
||||||
|
"prefix/darwin/macos/10.14/x64/gcc",
|
||||||
|
"prefix/darwin/macos/10.15/x64",
|
||||||
|
"prefix/darwin/macos/10.15/x64/gcc",
|
||||||
|
"prefix/darwin/macos/11.0/x64",
|
||||||
|
"prefix/darwin/macos/11.0/x64/gcc",
|
||||||
|
"prefix/darwin/macos/12.0/x64",
|
||||||
|
"prefix/darwin/macos/12.0/x64/gcc",
|
||||||
|
"prefix/darwin/macos/13.0/x64/gcc",
|
||||||
|
"prefix/darwin/macos/14.0/x64/gcc",
|
||||||
|
"prefix/darwin/macos/15.0/x64/gcc",
|
||||||
|
"prefix/darwin/macos/26.0/x64/gcc",
|
||||||
|
"prefix/darwin/macos/11.0/arm64",
|
||||||
|
"prefix/darwin/macos/11.0/arm64/gcc",
|
||||||
|
"prefix/darwin/macos/12.0/arm64",
|
||||||
|
"prefix/darwin/macos/12.0/arm64/gcc",
|
||||||
|
"prefix/darwin/macos/13.0/arm64/gcc",
|
||||||
|
"prefix/darwin/macos/14.0/arm64/gcc",
|
||||||
|
"prefix/darwin/macos/15.0/arm64/gcc",
|
||||||
|
"prefix/darwin/macos/26.0/arm64/gcc",
|
||||||
|
"prefix/sunos/solaris/5.11/x64",
|
||||||
|
];
|
||||||
|
|
||||||
|
let repo = Repo::new("/var/db/repos/gentoo");
|
||||||
|
|
||||||
|
for profile in profiles {
|
||||||
|
repo.evaluate_profile(profile)
|
||||||
|
.unwrap_or_else(|e| panic!("failed to evaluate profile: {profile}: {e}"));
|
||||||
|
}
|
||||||
|
}
|
||||||
1
tests/repo/meson.build
Normal file
1
tests/repo/meson.build
Normal file
@@ -0,0 +1 @@
|
|||||||
|
tests += {meson.current_source_dir() / 'repo.rs': []}
|
||||||
17
tests/repo/repo.rs
Normal file
17
tests/repo/repo.rs
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
use std::error::Error;
|
||||||
|
|
||||||
|
use gentoo_utils::repo::Repo;
|
||||||
|
|
||||||
|
fn main() -> Result<(), Box<dyn Error>> {
|
||||||
|
let repo = Repo::new("/var/db/repos/gentoo");
|
||||||
|
|
||||||
|
for result in repo.categories()? {
|
||||||
|
let cat = result?;
|
||||||
|
|
||||||
|
for result in cat.ebuilds()? {
|
||||||
|
let _ = result?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user