@@ -2,14 +2,13 @@ use std::{
2
2
collections:: HashMap ,
3
3
convert:: { TryFrom , TryInto } ,
4
4
fs,
5
- io:: { self , Write } ,
6
5
iter:: FromIterator ,
7
6
path:: { Path , PathBuf } ,
8
7
sync:: { Mutex , OnceLock } ,
9
8
thread,
10
9
} ;
11
10
12
- use serde:: Deserialize ;
11
+ use serde:: { Deserialize , Serialize } ;
13
12
use toml:: { Table , Value } ;
14
13
15
14
use crate :: {
@@ -47,9 +46,8 @@ impl TryFrom<&Path> for Extension {
47
46
return Ok ( Self :: Folder ) ;
48
47
} ;
49
48
let Some ( ext) = path. extension ( ) else {
50
- return Err ( BinaryError :: UnsupportedExtension ( "" . into ( ) ) ) ;
49
+ return Err ( BinaryError :: UnsupportedExtension ( "<error> " . into ( ) ) ) ;
51
50
} ;
52
-
53
51
match ext {
54
52
#[ cfg( feature = "gz" ) ]
55
53
e if e == "gz" || e == "tgz" => Ok ( Extension :: TarGz ) ,
@@ -123,8 +121,12 @@ pub struct UrlBinary {
123
121
paths : Option < Vec < String > > ,
124
122
}
125
123
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
+ }
128
130
129
131
impl < T > FromIterator < ( String , T ) > for Paths
130
132
where
@@ -137,7 +139,7 @@ where
137
139
/// decompressing errors. While it would possible to pass these values to the caller, in this
138
140
/// particular instance it would be hard to use this trait and it complicates error management.
139
141
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 ( ) ;
141
143
142
144
let ( url_binaries, follow_binaries) : ( Vec < _ > , Vec < _ > ) = binaries
143
145
. into_iter ( )
@@ -152,7 +154,7 @@ where
152
154
} ;
153
155
154
156
let dst = Path :: new ( & crate :: BUILD_TARGET_DIR ) . join ( & name) ;
155
- paths. insert (
157
+ res . paths . insert (
156
158
name,
157
159
bin. paths . iter ( ) . flatten ( ) . map ( |p| dst. join ( p) ) . collect ( ) ,
158
160
) ;
@@ -175,39 +177,41 @@ where
175
177
let Binary :: Follow ( bin) = bin else {
176
178
unreachable ! ( ) ;
177
179
} ;
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
+ } ;
183
187
}
184
188
185
- Self ( paths )
189
+ res
186
190
}
187
191
}
188
192
189
193
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
+ } ;
193
200
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) ;
207
203
} ;
208
204
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 ) ?)
211
215
}
212
216
}
213
217
@@ -238,6 +242,7 @@ fn check_valid_dir(dst: &Path, checksum: Option<&str>) -> Result<bool, BinaryErr
238
242
/// Retrieve a binary archive from the specified `url` and decompress it in the target directory.
239
243
/// "Download" is used as an umbrella term, since this can also be a local file.
240
244
fn make_available ( url : String , checksum : Option < String > , dst : & Path ) -> Result < ( ) , BinaryError > {
245
+ // TODO: Find a way of printing download/decompress progress
241
246
static LOCK : OnceLock < Mutex < ( ) > > = OnceLock :: new ( ) ;
242
247
243
248
// Check whether the file is local or not
@@ -250,6 +255,9 @@ fn make_available(url: String, checksum: Option<String>, dst: &Path) -> Result<(
250
255
251
256
// Check if it is a folder and it can be symlinked
252
257
if matches ! ( ext, Extension :: Folder ) {
258
+ if !local {
259
+ return Err ( BinaryError :: UnsupportedExtension ( "<folder>" . into ( ) ) ) ;
260
+ }
253
261
let _l = LOCK . get_or_init ( || Mutex :: new ( ( ) ) ) . lock ( ) ;
254
262
if !dst. read_link ( ) . is_ok_and ( |l| l == Path :: new ( url) ) {
255
263
if dst. is_symlink ( ) {
@@ -267,7 +275,8 @@ fn make_available(url: String, checksum: Option<String>, dst: &Path) -> Result<(
267
275
let file = if local {
268
276
fs:: read ( url) . map_err ( BinaryError :: LocalFileError ) ?
269
277
} else {
270
- attohttpc:: get ( url) . send ( ) ?. bytes ( ) ?
278
+ let res = attohttpc:: get ( url) . send ( ) ?;
279
+ res. error_for_status ( ) ?. bytes ( ) ?
271
280
} ;
272
281
273
282
// Verify the checksum
0 commit comments