@@ -146,19 +146,33 @@ fn url_to_file_path_wasm(url: &Url) -> Result<PathBuf, ()> {
146146/// <https://github.com/rust-lang/cargo/blob/af307a38c20a753ec60f0ad18be5abed3db3c9ac/src/cargo/util/paths.rs#L60-L85>
147147#[ inline]
148148pub fn normalize_path ( path : Cow < Path > ) -> Cow < Path > {
149- fn should_normalize ( path : & Path ) -> bool {
149+ enum ShouldNormalize {
150+ Yes ,
151+ No ,
152+ EnsureNoTrailingSlash ,
153+ }
154+
155+ fn should_normalize ( path : & Path ) -> ShouldNormalize {
156+ let mut had_normal = false ;
150157 for component in path. components ( ) {
151158 match component {
152159 Component :: CurDir | Component :: ParentDir => {
153- return true ;
160+ return ShouldNormalize :: Yes ;
154161 }
155- Component :: Prefix ( ..) | Component :: RootDir | Component :: Normal ( _ ) => {
162+ Component :: Prefix ( ..) | Component :: RootDir => {
156163 // ok
157164 }
165+ Component :: Normal ( _) => had_normal = true ,
158166 }
159167 }
160168
161- path_has_cur_dir_separator ( path)
169+ if path_has_cur_dir_separator ( path) {
170+ ShouldNormalize :: Yes
171+ } else if had_normal {
172+ ShouldNormalize :: EnsureNoTrailingSlash
173+ } else {
174+ ShouldNormalize :: No
175+ }
162176 }
163177
164178 // Rust normalizes away `Component::CurDir` most of the time
@@ -191,6 +205,29 @@ pub fn normalize_path(path: Cow<Path>) -> Cow<Path> {
191205 false
192206 }
193207
208+ // Warning: this makes some assumptions like not handling a
209+ // path like `/path/../` because it's assumed paths like that
210+ // won't be passed here because they'd be normalized by looping
211+ // over the components instead.
212+ fn ensure_no_trailing_slash ( path : Cow < Path > ) -> Cow < Path > {
213+ let is_windows = sys_traits:: impls:: is_windows ( ) ;
214+ let mut bytes = path. as_os_str ( ) . as_encoded_bytes ( ) ;
215+ let start_len = bytes. len ( ) ;
216+ while bytes. len ( ) > 1
217+ && ( is_windows && bytes. ends_with ( b"\\ " ) || bytes. ends_with ( b"/" ) )
218+ {
219+ bytes = & bytes[ ..bytes. len ( ) - 1 ] ;
220+ }
221+
222+ if bytes. len ( ) == start_len {
223+ return path;
224+ }
225+
226+ let new_len = bytes. len ( ) ;
227+ let os_string = path. into_owned ( ) . into_os_string ( ) ;
228+ Cow :: Owned ( PathBuf :: from ( truncate_os_string ( os_string, new_len) ) )
229+ }
230+
194231 fn inner ( path : & Path ) -> PathBuf {
195232 let mut components = path. components ( ) . peekable ( ) ;
196233 let mut ret =
@@ -219,35 +256,13 @@ pub fn normalize_path(path: Cow<Path>) -> Cow<Path> {
219256 ret
220257 }
221258
222- if should_normalize ( & path) {
223- Cow :: Owned ( inner ( & path) )
224- } else {
225- ensure_no_trailing_slash ( path)
259+ match should_normalize ( & path) {
260+ ShouldNormalize :: Yes => Cow :: Owned ( inner ( & path) ) ,
261+ ShouldNormalize :: No => path ,
262+ ShouldNormalize :: EnsureNoTrailingSlash => ensure_no_trailing_slash ( path) ,
226263 }
227264}
228265
229- fn ensure_no_trailing_slash ( path : Cow < Path > ) -> Cow < Path > {
230- let is_windows = sys_traits:: impls:: is_windows ( ) ;
231- let mut bytes = path. as_os_str ( ) . as_encoded_bytes ( ) ;
232- let start_len = bytes. len ( ) ;
233- while bytes. len ( ) > 1
234- && ( is_windows && bytes. ends_with ( b"\\ " ) || bytes. ends_with ( b"/" ) )
235- {
236- bytes = & bytes[ ..bytes. len ( ) - 1 ] ;
237- }
238-
239- if bytes. len ( ) == start_len
240- || bytes. ends_with ( b"." )
241- || is_windows && bytes. ends_with ( b":" )
242- {
243- return path;
244- }
245-
246- let new_len = bytes. len ( ) ;
247- let os_string = path. into_owned ( ) . into_os_string ( ) ;
248- Cow :: Owned ( PathBuf :: from ( truncate_os_string ( os_string, new_len) ) )
249- }
250-
251266#[ cfg( unix) ]
252267fn truncate_os_string ( mut os : OsString , n : usize ) -> OsString {
253268 use std:: os:: unix:: ffi:: OsStringExt ;
0 commit comments