@@ -44,44 +44,92 @@ struct LocationCache {
4444pub ( crate ) fn load_manifests ( load_from : & Path ) -> Result < ( Vec < MirrorFile > , Vec < String > ) , Error > {
4545 let mut result = Vec :: new ( ) ;
4646 let mut cache = LocationCache :: default ( ) ;
47+ let mut errors = Vec :: new ( ) ;
4748
4849 fn load_inner (
4950 load_from : & Path ,
5051 result : & mut Vec < MirrorFile > ,
5152 cache : & mut LocationCache ,
53+ errors : & mut Vec < String > ,
5254 ) -> anyhow:: Result < ( ) > {
5355 for entry in load_from. read_dir ( ) ? {
5456 let path = entry?. path ( ) ;
5557 if path. is_file ( ) && path. extension ( ) . and_then ( |s| s. to_str ( ) ) == Some ( "toml" ) {
56- let manifest = std:: fs:: read_to_string ( & path)
58+ let file_source = std:: fs:: read_to_string ( & path)
59+ . map_err ( Error :: from)
60+ . with_context ( || format ! ( "failed to read {}" , path. display( ) ) ) ?;
61+ let manifest = toml:: from_str :: < Manifest > ( & file_source)
5762 . map_err ( Error :: from)
58- . and_then ( |raw| toml:: from_str :: < Manifest > ( & raw ) . map_err ( Error :: from) )
5963 . with_context ( || format ! ( "failed to read {}" , path. display( ) ) ) ?;
6064 record_locations ( & path, & manifest, cache) ;
6165
6266 for file in manifest. files {
63- result . push ( match file. into_inner ( ) {
67+ let mirror_file = match file. into_inner ( ) {
6468 ManifestFile :: Legacy ( legacy) => MirrorFile {
6569 name : legacy. name ,
6670 sha256 : legacy. sha256 ,
6771 source : Source :: Legacy ,
72+ rename_from : None ,
6873 } ,
6974 ManifestFile :: Managed ( managed) => MirrorFile {
7075 name : managed. name ,
7176 sha256 : managed. sha256 ,
7277 source : Source :: Url ( managed. source ) ,
78+ rename_from : managed. rename_from ,
7379 } ,
74- } ) ;
80+ } ;
81+ if let Source :: Url ( ref source) = mirror_file. source {
82+ if let Some ( file_name) = source. path ( ) . split ( '/' ) . last ( )
83+ && let Some ( path_name) = mirror_file. name . split ( '/' ) . last ( )
84+ && path_name != file_name
85+ {
86+ match mirror_file. rename_from {
87+ Some ( ref rename_from) => {
88+ if rename_from != file_name {
89+ let location = cache
90+ . seen_paths
91+ . get ( & mirror_file. name )
92+ . unwrap ( )
93+ . first ( )
94+ . unwrap ( ) ;
95+ let ( src_line, snippet) = span_info ( & file_source, location) ;
96+ errors. push ( format ! (
97+ "`rename-from` field value doesn't match name from the URL `{source}` (`{file_name}` != `{rename_from}`):\n \
98+ # {} (line {src_line})\n {snippet}\n ",
99+ location. file. display( )
100+ ) ) ;
101+ }
102+ }
103+ None => {
104+ let location = cache
105+ . seen_paths
106+ . get ( & mirror_file. name )
107+ . unwrap ( )
108+ . first ( )
109+ . unwrap ( ) ;
110+ let ( src_line, snippet) = span_info ( & file_source, location) ;
111+ errors. push ( format ! (
112+ "The name from the URL `{source}` doesn't match the `name` field (`{file_name}` != `{path_name}`). \
113+ Add `rename-from = {file_name:?}` to fix this error:\n \
114+ # {} (line {src_line})\n {snippet}\n ",
115+ location. file. display( )
116+ ) ) ;
117+ }
118+ }
119+ }
120+ }
121+ result. push ( mirror_file) ;
75122 }
76123 } else if path. is_dir ( ) {
77- load_inner ( & path, result, cache) ?;
124+ load_inner ( & path, result, cache, errors ) ?;
78125 }
79126 }
80127 Ok ( ( ) )
81128 }
82129
83- load_inner ( load_from, & mut result, & mut cache) ?;
84- Ok ( ( result, find_errors ( cache) ) )
130+ load_inner ( load_from, & mut result, & mut cache, & mut errors) ?;
131+ find_errors ( cache, & mut errors) ;
132+ Ok ( ( result, errors) )
85133}
86134
87135fn record_locations ( toml_path : & Path , manifest : & Manifest , cache : & mut LocationCache ) {
@@ -114,12 +162,32 @@ fn record_locations(toml_path: &Path, manifest: &Manifest, cache: &mut LocationC
114162 . or_default ( )
115163 . insert ( location. clone ( ) ) ;
116164 if let Some ( url) = url {
117- cache. seen_urls . entry ( url) . or_default ( ) . insert ( location) ;
165+ cache
166+ . seen_urls
167+ . entry ( url)
168+ . or_default ( )
169+ . insert ( location. clone ( ) ) ;
170+ }
171+ }
172+ }
173+
174+ fn span_info < ' a > ( content : & ' a str , location : & Location ) -> ( usize , & ' a str ) {
175+ // Find the corresponding line number
176+ let mut accumulated_chars = 0 ;
177+ let mut src_line = 0 ;
178+ for ( index, line) in content. lines ( ) . enumerate ( ) {
179+ accumulated_chars += line. len ( ) + 1 ; // +1 for newline
180+ if accumulated_chars > location. span . 0 . start {
181+ src_line = index + 1 ;
182+ break ;
118183 }
119184 }
185+
186+ let snippet = & content[ location. span . 0 . start ..location. span . 0 . end ] ;
187+ ( src_line, snippet)
120188}
121189
122- fn find_errors ( cache : LocationCache ) -> Vec < String > {
190+ fn find_errors ( cache : LocationCache , errors : & mut Vec < String > ) {
123191 let mut file_cache: HashMap < PathBuf , String > = HashMap :: new ( ) ;
124192
125193 fn format_locations (
@@ -136,18 +204,7 @@ fn find_errors(cache: LocationCache) -> Vec<String> {
136204 } )
137205 } ) ;
138206
139- // Find the corresponding line number
140- let mut accumulated_chars = 0 ;
141- let mut src_line = 0 ;
142- for ( index, line) in content. lines ( ) . enumerate ( ) {
143- accumulated_chars += line. len ( ) + 1 ; // +1 for newline
144- if accumulated_chars > location. span . 0 . start {
145- src_line = index + 1 ;
146- break ;
147- }
148- }
149-
150- let snippet = & content[ location. span . 0 . start ..location. span . 0 . end ] ;
207+ let ( src_line, snippet) = span_info ( & content, location) ;
151208 writeln ! (
152209 output,
153210 "# {} (line {src_line})\n {snippet}\n " ,
@@ -159,7 +216,6 @@ fn find_errors(cache: LocationCache) -> Vec<String> {
159216 output
160217 }
161218
162- let mut errors = Vec :: new ( ) ;
163219 for ( path, locations) in cache. seen_paths {
164220 if locations. len ( ) > 1 {
165221 errors. push ( format ! (
@@ -184,13 +240,13 @@ fn find_errors(cache: LocationCache) -> Vec<String> {
184240 ) ) ;
185241 }
186242 }
187- errors
188243}
189244
190245pub ( crate ) struct MirrorFile {
191246 pub ( crate ) name : String ,
192247 pub ( crate ) sha256 : String ,
193248 pub ( crate ) source : Source ,
249+ pub ( crate ) rename_from : Option < String > ,
194250}
195251
196252pub ( crate ) enum Source {
@@ -233,15 +289,24 @@ pub struct ManifestFileManaged {
233289 // This field is not considered at all by the automation, we just enforce its presence so that
234290 // people adding new entries think about the licensing implications.
235291 license : String ,
292+ #[ serde( default , rename = "rename-from" ) ]
293+ rename_from : Option < String > ,
236294}
237295
238296impl ManifestFileManaged {
239- pub fn new ( name : String , sha256 : String , source : Url , license : String ) -> Self {
297+ pub fn new (
298+ name : String ,
299+ sha256 : String ,
300+ source : Url ,
301+ license : String ,
302+ rename_from : Option < String > ,
303+ ) -> Self {
240304 Self {
241305 name,
242306 sha256,
243307 source,
244308 license,
309+ rename_from,
245310 }
246311 }
247312}
0 commit comments