Skip to content

Commit d52c97b

Browse files
committed
add tests
1 parent a386864 commit d52c97b

File tree

9 files changed

+814
-105
lines changed

9 files changed

+814
-105
lines changed

build.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ pub fn main() {
77
mod binary {
88
use std::{collections::HashMap, fs, path::Path};
99

10-
use system_deps_meta::{read_metadata, Binary, BinaryPaths, BUILD_TARGET_DIR};
10+
use system_deps_meta::BUILD_TARGET_DIR;
1111

1212
pub fn build() {
1313
// Add pkg-config paths to the overrides

meta/Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ apple-flat-package = { version = "0.20", optional = true }
2222
toml = "0.8"
2323

2424
[features]
25-
default = [ ]
25+
default = [ "binary" ]
2626
binary = [ "dep:sha256", "dep:reqwest" ]
2727
gz = [ "dep:flate2", "dep:tar" ]
2828
xz = [ "dep:xz", "dep:tar" ]

meta/src/binary.rs

+78-68
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,13 @@ use std::{
55
};
66

77
use serde::Deserialize;
8+
use serde_json::Value;
89

9-
use crate::error::BinaryError;
10+
use crate::{
11+
error::{BinaryError, Error},
12+
parse::MetadataList,
13+
utils::merge_default,
14+
};
1015

1116
/// The extension of the binary archive.
1217
/// Support for different extensions is enabled using features.
@@ -25,11 +30,16 @@ enum Extension {
2530
// Pkg,
2631
}
2732

28-
// TODO: Change follow and global for includes
33+
#[derive(Debug, Deserialize)]
34+
#[serde(untagged)]
35+
pub enum Binary {
36+
Url(UrlBinary),
37+
Follow(FollowBinary),
38+
}
2939

3040
/// Represents one location from where to download library binaries.
3141
#[derive(Debug, Deserialize)]
32-
pub struct Binary {
42+
pub struct UrlBinary {
3343
/// The url from which to download the archived binaries. It suppports:
3444
///
3545
/// - Web urls, in the form `http[s]://website/archive.ext`.
@@ -47,67 +57,44 @@ pub struct Binary {
4757
/// A list of relative paths inside the binary archive that point to a folder containing
4858
/// package config files. These directories will be prepended to the `PKG_CONFIG_PATH` when
4959
/// compiling the affected libraries.
50-
pkg_paths: Vec<String>,
60+
paths: Option<Vec<String>>,
61+
///
62+
provides: Option<Vec<String>>,
63+
}
5164

52-
/// Controls if the paths from this binary apply to all packages or just to this one.
53-
global: Option<bool>,
54-
/// The `system-deps` formatted name of another library which has binaries specified.
55-
/// This library will alias the configuration of the followed one. If `url` is specified
56-
/// alongside this field, it will no longer follow the original configuration.
57-
_follows: Option<String>,
65+
#[derive(Debug, Deserialize)]
66+
pub struct FollowBinary {
67+
follows: String,
5868
}
5969

60-
impl Binary {
61-
pub fn paths(&self, name: &str) -> Result<HashSet<PathBuf>, BinaryError> {
62-
// TODO: Set this binary to follow
63-
//if let Some(follows) = self.follows {
64-
// follow_list.insert(name.clone(), follows);
65-
//}
70+
pub trait BinaryMetadataListExt {
71+
fn paths(&self, package: &str) -> Result<HashSet<PathBuf>, Error>;
72+
}
6673

74+
impl BinaryMetadataListExt for MetadataList {
75+
fn paths(&self, package: &str) -> Result<HashSet<PathBuf>, Error> {
6776
// The binaries are stored in the target dir set by `system_deps_meta`.
77+
6878
// If they are specific to a dependency, they live in a subfolder.
69-
let mut dst = PathBuf::from(&crate::BUILD_TARGET_DIR);
70-
if !name.is_empty() {
71-
dst.push(name);
72-
};
79+
let binary_list: HashMap<String, Binary> = self.get(package, merge_binary)?;
7380

74-
// Only download the binaries if there isn't already a valid copy
75-
if !check_valid_dir(&dst, self.checksum.as_deref())? {
76-
download(&self.url, &dst)?;
81+
match binary_list.get(package).unwrap() {
82+
Binary::Url(bin) => {
83+
let dst = Path::new(&crate::BUILD_TARGET_DIR).join(package);
84+
// Only download the binaries if there isn't already a valid copy
85+
if !check_valid_dir(&dst, bin.checksum.as_deref())? {
86+
download(&bin.url, &dst)?;
87+
}
88+
Ok(bin.paths.iter().flatten().map(|p| dst.join(p)).collect())
89+
}
90+
Binary::Follow(dep) => self.paths(&dep.follows),
7791
}
78-
79-
Ok(self.pkg_paths.iter().map(|p| dst.join(p)).collect())
80-
}
81-
82-
pub fn is_global(&self) -> bool {
83-
self.global.unwrap_or_default()
8492
}
8593
}
8694

8795
#[derive(Debug)]
8896
pub struct BinaryPaths(HashMap<String, Vec<PathBuf>>);
8997

90-
impl<I: IntoIterator<Item = (String, Binary)>> From<I> for BinaryPaths {
91-
/// Uses the metadata from the cargo manifests and the environment to build a list of urls
92-
/// from where to download binaries for dependencies and adds them to their `PKG_CONFIG_PATH`.
93-
fn from(binaries: I) -> Self {
94-
let mut paths: HashMap<String, Vec<PathBuf>> = HashMap::new();
95-
96-
for (name, bin) in binaries {
97-
let p = bin.paths(&name).unwrap();
98-
if bin.is_global() {
99-
paths
100-
.entry("".into())
101-
.or_default()
102-
.extend(p.iter().cloned())
103-
}
104-
paths.entry(name).or_default().extend(p.into_iter());
105-
}
106-
107-
Self(paths)
108-
}
109-
}
110-
11198
impl BinaryPaths {
11299
pub fn build(self) -> String {
113100
let options = self
@@ -119,7 +106,6 @@ impl BinaryPaths {
119106

120107
format!(
121108
r#"
122-
/// TODO:
123109
pub fn get_path(name: &str) -> &[&'static str] {{
124110
match name {{
125111
{}
@@ -156,23 +142,6 @@ pub fn get_path(name: &str) -> &[&'static str] {{
156142
// }),
157143
// );
158144
//}
159-
160-
// Go through the list of follows and if they don't already have binaries,
161-
// link them to the followed one.
162-
//for (from, to) in follow_list {
163-
// if !paths.contains_key(&from) {
164-
// let followed = paths
165-
// .get(to.as_str())
166-
// .unwrap_or_else(|| {
167-
// panic!(
168-
// "The library `{}` tried to follow `{}` but it doesn't exist",
169-
// from, to,
170-
// )
171-
// })
172-
// .clone();
173-
// paths.insert(from, followed);
174-
// };
175-
//}
176145
}
177146

178147
/// Checks if the target directory is valid and if binaries need to be redownloaded.
@@ -314,3 +283,44 @@ fn decompress(file: &[u8], dst: &Path, ext: Extension) -> Result<(), BinaryError
314283
}
315284
Ok(())
316285
}
286+
287+
pub fn merge_binary(rhs: Value, lhs: &Value, overwrite: bool) -> Result<Value, Error> {
288+
let mut res = merge_default(rhs, lhs, overwrite)?;
289+
290+
//if overwrite {
291+
// resolve_follow(&mut res);
292+
//}
293+
294+
Ok(res)
295+
}
296+
297+
//fn resolve_follow(res: &mut Value) -> Option<()> {
298+
// let mut follows = Vec::new();
299+
//
300+
// for value in res.as_object_mut()?.values_mut() {
301+
// let Some(provides) = value.get_mut("provides") else {
302+
// continue;
303+
// };
304+
// let provides = provides.take();
305+
// let Some(arr) = provides.as_array().cloned() else {
306+
// continue;
307+
// };
308+
// follows.push((arr, value.clone()));
309+
// }
310+
//
311+
// let res = res.as_object_mut()?;
312+
// for (provides, value) in follows {
313+
// for to in provides {
314+
// let to = to.as_str()?;
315+
// let entry = res.entry(to).or_insert(Value::Object(Map::new()));
316+
// let Some(map) = entry.as_object_mut() else {
317+
// continue;
318+
// };
319+
// let _ = map.entry("follows").or_insert(to.into());
320+
// }
321+
// }
322+
//
323+
// println!("res {:?}", res);
324+
//
325+
// Some(())
326+
//}

meta/src/parse.rs

+3-23
Original file line numberDiff line numberDiff line change
@@ -132,18 +132,10 @@ impl MetadataList {
132132
/// and whether it should allow the second value to overwrite the first. When traveling up the tree
133133
/// this is true since we want dependent crates to have priority, but when comparing horizontally
134134
/// it is false to avoid conflicts.
135-
///
136-
/// `reduce` will take the output of merge and apply rules to modify the returned structure.
137-
/// For example, checking cfg conditions and library versions.
138-
pub fn get<
139-
T: DeserializeOwned,
140-
M: Fn(Value, &Value, bool) -> Result<Value, Error>,
141-
R: Fn(Value, &M) -> Result<Value, Error>,
142-
>(
135+
pub fn get<T: DeserializeOwned>(
143136
&self,
144137
package: &str,
145-
merge: M,
146-
reduce: R,
138+
merge: impl Fn(Value, &Value, bool) -> Result<Value, Error>,
147139
) -> Result<T, Error> {
148140
let base = self
149141
.nodes
@@ -154,7 +146,6 @@ impl MetadataList {
154146
let mut res = Value::Null;
155147
let mut curr = Value::Null;
156148

157-
// Merge
158149
while let Some(node) = nodes.pop_front() {
159150
for p in node.parents.iter().rev() {
160151
let next = self.nodes.get(p).ok_or(Error::PackageNotFound(p.into()))?;
@@ -167,17 +158,6 @@ impl MetadataList {
167158
}
168159
}
169160

170-
// Reduce
171-
res = reduce(res, &merge)?;
172-
173-
// Get package
174-
let Value::Object(mut map) = res else {
175-
return Err(Error::IncompatibleMerge);
176-
};
177-
let Some(value) = map.remove(package) else {
178-
return Err(Error::PackageNotFound(package.into()));
179-
};
180-
181-
from_value::<T>(value).map_err(Error::SerializationError)
161+
from_value::<T>(res).map_err(Error::SerializationError)
182162
}
183163
}

meta/src/test.rs

+114
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
use std::{
2+
collections::HashSet,
3+
fs, io,
4+
path::{Path, PathBuf},
5+
};
6+
7+
use toml::{Table, Value};
8+
9+
use crate::{error::Error, parse::MetadataList, utils::merge_default};
10+
11+
#[cfg(feature = "binary")]
12+
mod binary;
13+
mod conditional;
14+
mod metadata;
15+
16+
macro_rules! entry {
17+
($table:expr, $key:expr) => {
18+
$table
19+
.entry($key)
20+
.or_insert_with(|| Value::Table(Table::default()))
21+
.as_table_mut()
22+
.unwrap()
23+
};
24+
}
25+
26+
#[derive(Debug, Default)]
27+
struct Package {
28+
name: &'static str,
29+
deps: Vec<&'static str>,
30+
config: Table,
31+
}
32+
33+
impl Package {
34+
fn write_toml(self, test_name: &str) -> io::Result<PathBuf> {
35+
let mut table = self.config;
36+
37+
let package = entry!(table, "package");
38+
package.insert("name".into(), self.name.into());
39+
40+
if !self.deps.is_empty() {
41+
let dependencies = entry!(table, "dependencies");
42+
for name in self.deps {
43+
let dep = entry!(dependencies, name);
44+
dep.insert("path".into(), format!("../{}", name).into());
45+
}
46+
}
47+
48+
let mut out = Path::new(env!("OUT_DIR")).join(format!("tests/{}/{}", test_name, self.name));
49+
let _ = fs::remove_dir_all(&out);
50+
51+
out.push("src");
52+
fs::create_dir_all(&out)?;
53+
fs::write(out.join("lib.rs"), "")?;
54+
out.pop();
55+
56+
out.push("Cargo.toml");
57+
fs::write(&out, table.to_string())?;
58+
59+
Ok(out)
60+
}
61+
}
62+
63+
#[derive(Debug)]
64+
struct Test {
65+
metadata: MetadataList,
66+
manifest: PathBuf,
67+
}
68+
69+
impl Test {
70+
fn new(name: impl AsRef<str>, packages: Vec<Package>) -> Self {
71+
assert!(!packages.is_empty());
72+
73+
println!("\n# Dependencies\n");
74+
let mut manifest = None;
75+
for pkg in packages {
76+
let out = pkg
77+
.write_toml(name.as_ref())
78+
.expect("Error writing Cargo.toml for test package");
79+
println!("- {}", out.display());
80+
manifest.get_or_insert(out);
81+
}
82+
83+
let manifest = manifest.expect("There is no main test case");
84+
let metadata = MetadataList::from(&manifest, "system-deps");
85+
86+
Self { metadata, manifest }
87+
}
88+
89+
fn check(&self, key: &str) -> Result<Table, Error> {
90+
println!("{} {:#?}", key, self.metadata);
91+
let resolved = self
92+
.metadata
93+
.get::<Table>(key, merge_default)?
94+
.remove(key)
95+
.ok_or(Error::PackageNotFound(key.into()))?;
96+
97+
println!("\n# Final\n");
98+
println!("{}", toml::to_string_pretty(&resolved).unwrap());
99+
100+
match resolved {
101+
Value::Table(v) => Ok(v),
102+
_ => Err(Error::IncompatibleMerge),
103+
}
104+
}
105+
}
106+
107+
fn assert_set<T: std::fmt::Debug + Eq + std::hash::Hash>(
108+
rhs: impl IntoIterator<Item = T>,
109+
lhs: impl IntoIterator<Item = T>,
110+
) {
111+
let r = rhs.into_iter().collect::<HashSet<_>>();
112+
let l = lhs.into_iter().collect::<HashSet<_>>();
113+
assert_eq!(r, l);
114+
}

0 commit comments

Comments
 (0)