22// SPDX-License-Identifier: Apache-2.0
33// SPDX-License-Identifier: MIT
44
5- use std:: path:: { Component , Path , PathBuf } ;
5+ use std:: {
6+ collections:: HashMap ,
7+ path:: { Component , Path , PathBuf } ,
8+ } ;
69
710/// Given a path (absolute or relative) to a resource file, returns the
811/// relative path from the bundle resources directory where that resource
@@ -39,40 +42,116 @@ pub fn external_binaries(external_binaries: &[String], target_triple: &str) -> V
3942 paths
4043}
4144
45+ enum PatternIter < ' a > {
46+ Slice ( std:: slice:: Iter < ' a , String > ) ,
47+ Map ( std:: collections:: hash_map:: Iter < ' a , String , String > ) ,
48+ }
49+
4250/// A helper to iterate through resources.
4351pub struct ResourcePaths < ' a > {
52+ iter : ResourcePathsIter < ' a > ,
53+ }
54+
55+ impl < ' a > ResourcePaths < ' a > {
56+ /// Creates a new ResourcePaths from a slice of patterns to iterate
57+ pub fn new ( patterns : & ' a [ String ] , allow_walk : bool ) -> ResourcePaths < ' a > {
58+ ResourcePaths {
59+ iter : ResourcePathsIter {
60+ pattern_iter : PatternIter :: Slice ( patterns. iter ( ) ) ,
61+ glob_iter : None ,
62+ walk_iter : None ,
63+ allow_walk,
64+ current_pattern : None ,
65+ current_pattern_is_valid : false ,
66+ current_dest : None ,
67+ } ,
68+ }
69+ }
70+
71+ /// Creates a new ResourcePaths from a slice of patterns to iterate
72+ pub fn from_map ( patterns : & ' a HashMap < String , String > , allow_walk : bool ) -> ResourcePaths < ' a > {
73+ ResourcePaths {
74+ iter : ResourcePathsIter {
75+ pattern_iter : PatternIter :: Map ( patterns. iter ( ) ) ,
76+ glob_iter : None ,
77+ walk_iter : None ,
78+ allow_walk,
79+ current_pattern : None ,
80+ current_pattern_is_valid : false ,
81+ current_dest : None ,
82+ } ,
83+ }
84+ }
85+
86+ /// Returns the resource iterator that yields the source and target paths.
87+ /// Needed when using [`Self::from_map`].
88+ pub fn iter ( self ) -> ResourcePathsIter < ' a > {
89+ self . iter
90+ }
91+ }
92+
93+ /// Iterator of a [`ResourcePaths`].
94+ pub struct ResourcePathsIter < ' a > {
4495 /// the patterns to iterate.
45- pattern_iter : std :: slice :: Iter < ' a , String > ,
96+ pattern_iter : PatternIter < ' a > ,
4697 /// the glob iterator if the path from the current iteration is a glob pattern.
4798 glob_iter : Option < glob:: Paths > ,
4899 /// the walkdir iterator if the path from the current iteration is a directory.
49100 walk_iter : Option < walkdir:: IntoIter > ,
50101 /// whether the resource paths allows directories or not.
51102 allow_walk : bool ,
52103 /// the pattern of the current iteration.
53- current_pattern : Option < String > ,
104+ current_pattern : Option < ( String , PathBuf ) > ,
54105 /// whether the current pattern is valid or not.
55106 current_pattern_is_valid : bool ,
107+ /// Current destination path. Only set when the iterator comes from a Map.
108+ current_dest : Option < PathBuf > ,
56109}
57110
58- impl < ' a > ResourcePaths < ' a > {
59- /// Creates a new ResourcePaths from a slice of patterns to iterate
60- pub fn new ( patterns : & ' a [ String ] , allow_walk : bool ) -> ResourcePaths < ' a > {
61- ResourcePaths {
62- pattern_iter : patterns. iter ( ) ,
63- glob_iter : None ,
64- walk_iter : None ,
65- allow_walk,
66- current_pattern : None ,
67- current_pattern_is_valid : false ,
68- }
111+ /// Information for a resource.
112+ pub struct Resource {
113+ path : PathBuf ,
114+ target : PathBuf ,
115+ }
116+
117+ impl Resource {
118+ /// The path of the resource.
119+ pub fn path ( & self ) -> & Path {
120+ & self . path
121+ }
122+
123+ /// The target location of the resource.
124+ pub fn target ( & self ) -> & Path {
125+ & self . target
69126 }
70127}
71128
72129impl < ' a > Iterator for ResourcePaths < ' a > {
73130 type Item = crate :: Result < PathBuf > ;
74131
75132 fn next ( & mut self ) -> Option < crate :: Result < PathBuf > > {
133+ self . iter . next ( ) . map ( |r| r. map ( |res| res. path ) )
134+ }
135+ }
136+
137+ fn normalize ( path : & Path ) -> PathBuf {
138+ let mut dest = PathBuf :: new ( ) ;
139+ for component in path. components ( ) {
140+ match component {
141+ Component :: Prefix ( _) => { }
142+ Component :: RootDir => dest. push ( "/" ) ,
143+ Component :: CurDir => { }
144+ Component :: ParentDir => dest. push ( ".." ) ,
145+ Component :: Normal ( string) => dest. push ( string) ,
146+ }
147+ }
148+ dest
149+ }
150+
151+ impl < ' a > Iterator for ResourcePathsIter < ' a > {
152+ type Item = crate :: Result < Resource > ;
153+
154+ fn next ( & mut self ) -> Option < crate :: Result < Resource > > {
76155 loop {
77156 if let Some ( ref mut walk_entries) = self . walk_iter {
78157 if let Some ( entry) = walk_entries. next ( ) {
@@ -85,7 +164,20 @@ impl<'a> Iterator for ResourcePaths<'a> {
85164 continue ;
86165 }
87166 self . current_pattern_is_valid = true ;
88- return Some ( Ok ( path. to_path_buf ( ) ) ) ;
167+ return Some ( Ok ( Resource {
168+ target : if let ( Some ( current_dest) , Some ( current_pattern) ) =
169+ ( & self . current_dest , & self . current_pattern )
170+ {
171+ if current_pattern. 0 . contains ( '*' ) {
172+ current_dest. join ( path. file_name ( ) . unwrap ( ) )
173+ } else {
174+ current_dest. join ( path. strip_prefix ( & current_pattern. 1 ) . unwrap ( ) )
175+ }
176+ } else {
177+ resource_relpath ( path)
178+ } ,
179+ path : path. to_path_buf ( ) ,
180+ } ) ) ;
89181 }
90182 }
91183 self . walk_iter = None ;
@@ -105,24 +197,51 @@ impl<'a> Iterator for ResourcePaths<'a> {
105197 }
106198 }
107199 self . current_pattern_is_valid = true ;
108- return Some ( Ok ( path) ) ;
200+ return Some ( Ok ( Resource {
201+ target : if let Some ( current_dest) = & self . current_dest {
202+ current_dest. join ( path. file_name ( ) . unwrap ( ) )
203+ } else {
204+ resource_relpath ( & path)
205+ } ,
206+ path,
207+ } ) ) ;
109208 } else if let Some ( current_path) = & self . current_pattern {
110209 if !self . current_pattern_is_valid {
111210 self . glob_iter = None ;
112- return Some ( Err ( crate :: Error :: GlobPathNotFound ( current_path. clone ( ) ) ) ) ;
211+ return Some ( Err ( crate :: Error :: GlobPathNotFound ( current_path. 0 . clone ( ) ) ) ) ;
113212 }
114213 }
115214 }
116215 self . glob_iter = None ;
117- if let Some ( pattern) = self . pattern_iter . next ( ) {
118- self . current_pattern = Some ( pattern. to_string ( ) ) ;
119- self . current_pattern_is_valid = false ;
120- let glob = match glob:: glob ( pattern) {
121- Ok ( glob) => glob,
122- Err ( error) => return Some ( Err ( error. into ( ) ) ) ,
123- } ;
124- self . glob_iter = Some ( glob) ;
125- continue ;
216+ self . current_dest = None ;
217+ match & mut self . pattern_iter {
218+ PatternIter :: Slice ( iter) => {
219+ if let Some ( pattern) = iter. next ( ) {
220+ self . current_pattern = Some ( ( pattern. to_string ( ) , normalize ( Path :: new ( pattern) ) ) ) ;
221+ self . current_pattern_is_valid = false ;
222+ let glob = match glob:: glob ( pattern) {
223+ Ok ( glob) => glob,
224+ Err ( error) => return Some ( Err ( error. into ( ) ) ) ,
225+ } ;
226+ self . glob_iter = Some ( glob) ;
227+ continue ;
228+ }
229+ }
230+ PatternIter :: Map ( iter) => {
231+ if let Some ( ( pattern, dest) ) = iter. next ( ) {
232+ self . current_pattern = Some ( ( pattern. to_string ( ) , normalize ( Path :: new ( pattern) ) ) ) ;
233+ self . current_pattern_is_valid = false ;
234+ let glob = match glob:: glob ( pattern) {
235+ Ok ( glob) => glob,
236+ Err ( error) => return Some ( Err ( error. into ( ) ) ) ,
237+ } ;
238+ self
239+ . current_dest
240+ . replace ( resource_relpath ( & PathBuf :: from ( dest) ) ) ;
241+ self . glob_iter = Some ( glob) ;
242+ continue ;
243+ }
244+ }
126245 }
127246 return None ;
128247 }
0 commit comments