Skip to content

Commit aef321c

Browse files
committed
polishing touches
1 parent 4472359 commit aef321c

17 files changed

+911
-745
lines changed

Cargo.toml

+5-1
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ documentation.workspace = true
3636
readme = "README.md"
3737

3838
[dependencies]
39+
system-deps-meta = { workspace = true, optional = true }
3940
pkg-config = "0.3.25"
4041
toml = { version = "0.8", default-features = false, features = ["parse"] }
4142
version-compare = "0.2"
@@ -46,12 +47,15 @@ cfg-expr = { version = "0.17", features = ["targets"] }
4647
system-deps-meta = { workspace = true, optional = true }
4748

4849
[dev-dependencies]
50+
system-deps-meta = { workspace = true, features = ["test"] }
4951
itertools = "0.13"
5052
assert_matches = "1.5"
53+
tiny_http = "0.12"
5154

5255
[features]
5356
default = [ ]
57+
# How to do this using resolver v2? Since features are separated
5458
binary = [ "system-deps-meta/binary" ]
55-
gx = [ "system-deps-meta/gz" ]
59+
gz = [ "system-deps-meta/gz" ]
5660
xz = [ "system-deps-meta/xz" ]
5761
zip = [ "system-deps-meta/zip" ]

build.rs

+6-6
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ pub fn main() {
55

66
#[cfg(feature = "binary")]
77
mod binary {
8-
use std::path::Path;
8+
use std::{fs, path::Path};
99

1010
use system_deps_meta::{
1111
binary::{merge_binary, Paths},
@@ -23,10 +23,10 @@ mod binary {
2323
let paths: Paths = metadata.build(merge_binary)?.into_iter().collect();
2424

2525
// Write the binary paths to a file for later use
26-
let dest_path = Path::new(BUILD_TARGET_DIR).join("binary_config.rs");
27-
println!("cargo:rustc-env=BINARY_CONFIG={}", dest_path.display());
28-
paths
29-
.build(dest_path)
30-
.map_err(|e| BinaryError::InvalidDirectory(e).into())
26+
let dest = Path::new(BUILD_TARGET_DIR).join("paths.toml");
27+
fs::write(&dest, paths.to_string()?).map_err(BinaryError::InvalidDirectory)?;
28+
println!("cargo:rustc-env=BINARY_PATHS={}", dest.display());
29+
30+
Ok(())
3131
}
3232
}

meta/Cargo.toml

+1-4
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,9 @@ xz = { version = "0.1", optional = true }
2020
tar = { version = "0.4", optional = true }
2121
zip = { version = "2.2", optional = true }
2222

23-
[dev-dependencies]
24-
tiny_http = "0.12"
25-
2623
[features]
27-
default = [ ]
2824
binary = [ "dep:sha256", "dep:attohttpc" ]
2925
gz = [ "dep:flate2", "dep:tar" ]
3026
xz = [ "dep:xz", "dep:tar" ]
3127
zip = [ "dep:zip" ]
28+
test = [ ]

meta/src/binary.rs

+42-33
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,13 @@ use std::{
22
collections::HashMap,
33
convert::{TryFrom, TryInto},
44
fs,
5-
io::{self, Write},
65
iter::FromIterator,
76
path::{Path, PathBuf},
87
sync::{Mutex, OnceLock},
98
thread,
109
};
1110

12-
use serde::Deserialize;
11+
use serde::{Deserialize, Serialize};
1312
use toml::{Table, Value};
1413

1514
use crate::{
@@ -47,9 +46,8 @@ impl TryFrom<&Path> for Extension {
4746
return Ok(Self::Folder);
4847
};
4948
let Some(ext) = path.extension() else {
50-
return Err(BinaryError::UnsupportedExtension("".into()));
49+
return Err(BinaryError::UnsupportedExtension("<error>".into()));
5150
};
52-
5351
match ext {
5452
#[cfg(feature = "gz")]
5553
e if e == "gz" || e == "tgz" => Ok(Extension::TarGz),
@@ -123,8 +121,12 @@ pub struct UrlBinary {
123121
paths: Option<Vec<String>>,
124122
}
125123

126-
#[derive(Debug)]
127-
pub struct Paths(HashMap<String, Vec<PathBuf>>);
124+
#[derive(Debug, Default, Deserialize, Serialize)]
125+
pub struct Paths {
126+
paths: HashMap<String, Vec<PathBuf>>,
127+
follows: HashMap<String, String>,
128+
wildcards: HashMap<String, String>,
129+
}
128130

129131
impl<T> FromIterator<(String, T)> for Paths
130132
where
@@ -137,7 +139,7 @@ where
137139
/// decompressing errors. While it would possible to pass these values to the caller, in this
138140
/// particular instance it would be hard to use this trait and it complicates error management.
139141
fn from_iter<I: IntoIterator<Item = (String, T)>>(binaries: I) -> Self {
140-
let mut paths: HashMap<String, Vec<PathBuf>> = HashMap::new();
142+
let mut res = Self::default();
141143

142144
let (url_binaries, follow_binaries): (Vec<_>, Vec<_>) = binaries
143145
.into_iter()
@@ -152,7 +154,7 @@ where
152154
};
153155

154156
let dst = Path::new(&crate::BUILD_TARGET_DIR).join(&name);
155-
paths.insert(
157+
res.paths.insert(
156158
name,
157159
bin.paths.iter().flatten().map(|p| dst.join(p)).collect(),
158160
);
@@ -175,39 +177,41 @@ where
175177
let Binary::Follow(bin) = bin else {
176178
unreachable!();
177179
};
178-
let other = paths
179-
.get(&bin.follows)
180-
.ok_or_else(|| BinaryError::InvalidFollows(name.clone(), bin.follows))
181-
.unwrap_or_else(|e| panic!("{}", e));
182-
paths.insert(name, other.clone());
180+
if !res.paths.contains_key(&bin.follows) {
181+
panic!("{}", BinaryError::InvalidFollows(name, bin.follows));
182+
};
183+
match name.strip_suffix("*") {
184+
Some(wildcard) => res.wildcards.insert(wildcard.into(), bin.follows),
185+
None => res.follows.insert(name, bin.follows),
186+
};
183187
}
184188

185-
Self(paths)
189+
res
186190
}
187191
}
188192

189193
impl Paths {
190-
pub fn get(&self, key: &str) -> Result<&Vec<PathBuf>, Error> {
191-
self.0.get(key).ok_or(Error::PackageNotFound(key.into()))
192-
}
194+
/// Returns the list of paths for a certain package. Matches wildcards but they never have
195+
/// priority over explicit urls or follows, even if they are defined higher in the hierarchy.
196+
pub fn get(&self, key: &str) -> Option<&Vec<PathBuf>> {
197+
if let Some(paths) = self.paths.get(key) {
198+
return Some(paths);
199+
};
193200

194-
pub fn build(self, path: impl AsRef<Path>) -> Result<(), io::Error> {
195-
let mut f = fs::File::create(path.as_ref())?;
196-
writeln!(f, "/// List of pkg_config paths provided by packages")?;
197-
writeln!(f, "pub fn get_path(_name: &str) -> &[&'static str] {{")?;
198-
199-
if self.0.is_empty() {
200-
writeln!(f, "&[]")?;
201-
} else {
202-
writeln!(f, "match _name {{")?;
203-
for (name, list) in self.0 {
204-
writeln!(f, r#""{}" => &{:?},"#, name, list)?;
205-
}
206-
writeln!(f, "_ => &[]\n}}")?;
201+
if let Some(follows) = self.follows.get(key) {
202+
return self.paths.get(follows);
207203
};
208204

209-
write!(f, "}}")?;
210-
Ok(())
205+
self.wildcards.iter().find_map(|(k, v)| {
206+
key.starts_with(k)
207+
.then_some(v)
208+
.and_then(|v| self.paths.get(v))
209+
})
210+
}
211+
212+
/// Serializes the path list.
213+
pub fn to_string(&self) -> Result<String, Error> {
214+
Ok(toml::to_string(self)?)
211215
}
212216
}
213217

@@ -238,6 +242,7 @@ fn check_valid_dir(dst: &Path, checksum: Option<&str>) -> Result<bool, BinaryErr
238242
/// Retrieve a binary archive from the specified `url` and decompress it in the target directory.
239243
/// "Download" is used as an umbrella term, since this can also be a local file.
240244
fn make_available(url: String, checksum: Option<String>, dst: &Path) -> Result<(), BinaryError> {
245+
// TODO: Find a way of printing download/decompress progress
241246
static LOCK: OnceLock<Mutex<()>> = OnceLock::new();
242247

243248
// Check whether the file is local or not
@@ -250,6 +255,9 @@ fn make_available(url: String, checksum: Option<String>, dst: &Path) -> Result<(
250255

251256
// Check if it is a folder and it can be symlinked
252257
if matches!(ext, Extension::Folder) {
258+
if !local {
259+
return Err(BinaryError::UnsupportedExtension("<folder>".into()));
260+
}
253261
let _l = LOCK.get_or_init(|| Mutex::new(())).lock();
254262
if !dst.read_link().is_ok_and(|l| l == Path::new(url)) {
255263
if dst.is_symlink() {
@@ -267,7 +275,8 @@ fn make_available(url: String, checksum: Option<String>, dst: &Path) -> Result<(
267275
let file = if local {
268276
fs::read(url).map_err(BinaryError::LocalFileError)?
269277
} else {
270-
attohttpc::get(url).send()?.bytes()?
278+
let res = attohttpc::get(url).send()?;
279+
res.error_for_status()?.bytes()?
271280
};
272281

273282
// Verify the checksum

meta/src/error.rs

-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ pub enum Error {
1010
CfgNotObject(String),
1111
/// Error while deserializing metadata.
1212
DeserializeError(toml::de::Error),
13-
// TODO: Add details
1413
/// Merging two incompatible branches.
1514
IncompatibleMerge,
1615
/// Error while parsing the cfg() expression.

meta/src/lib.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
1+
//#![warn(missing_docs)]
2+
13
pub mod error;
24
pub mod parse;
35
pub mod utils;
46

57
#[cfg(feature = "binary")]
68
pub mod binary;
79

8-
#[cfg(test)]
9-
mod test;
10+
#[cfg(any(test, feature = "test"))]
11+
pub mod test;
1012

1113
/// Path to the top level Cargo.toml.
1214
pub const BUILD_MANIFEST: &str = env!("BUILD_MANIFEST");

0 commit comments

Comments
 (0)