os: add existing_path function (#14536)
parent
928dafeb6d
commit
4ffdcf8058
|
@ -123,6 +123,52 @@ pub fn norm_path(path string) string {
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// existing_path returns the existing part of the given `path`.
|
||||||
|
// An error is returned if there is no existing part of the given `path`.
|
||||||
|
pub fn existing_path(path string) ?string {
|
||||||
|
err := error('path does not exist')
|
||||||
|
if path.len == 0 {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if exists(path) {
|
||||||
|
return path
|
||||||
|
}
|
||||||
|
mut volume_len := 0
|
||||||
|
$if windows {
|
||||||
|
volume_len = win_volume_len(path)
|
||||||
|
}
|
||||||
|
if volume_len > 0 && is_slash(path[volume_len - 1]) {
|
||||||
|
volume_len++
|
||||||
|
}
|
||||||
|
mut sc := textscanner.new(path[volume_len..])
|
||||||
|
mut recent_path := path[..volume_len]
|
||||||
|
for sc.next() != -1 {
|
||||||
|
curr := u8(sc.current())
|
||||||
|
peek := sc.peek()
|
||||||
|
back := sc.peek_back()
|
||||||
|
if is_curr_dir_ref(back, curr, peek) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
range := sc.ilen - sc.remaining() + volume_len
|
||||||
|
if is_slash(curr) && !is_slash(u8(peek)) {
|
||||||
|
recent_path = path[..range]
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if !is_slash(curr) && (peek == -1 || is_slash(u8(peek))) {
|
||||||
|
curr_path := path[..range]
|
||||||
|
if exists(curr_path) {
|
||||||
|
recent_path = curr_path
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if recent_path.len == 0 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
return recent_path
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
// clean_path returns the "cleaned" version of the given `path`
|
// clean_path returns the "cleaned" version of the given `path`
|
||||||
// by turning forward slashes into back slashes
|
// by turning forward slashes into back slashes
|
||||||
// on a Windows system and eliminating:
|
// on a Windows system and eliminating:
|
||||||
|
@ -144,8 +190,7 @@ fn clean_path(path string) string {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
// skip reference to current dir (.)
|
// skip reference to current dir (.)
|
||||||
if (back == -1 || is_slash(u8(back))) && curr == os.dot
|
if is_curr_dir_ref(back, curr, peek) {
|
||||||
&& (peek == -1 || is_slash(u8(peek))) {
|
|
||||||
// skip if the next byte is a path separator
|
// skip if the next byte is a path separator
|
||||||
if peek != -1 && is_slash(u8(peek)) {
|
if peek != -1 && is_slash(u8(peek)) {
|
||||||
sc.skip_n(1)
|
sc.skip_n(1)
|
||||||
|
@ -246,3 +291,13 @@ fn is_normal_path(path string) bool {
|
||||||
return (plen == 1 && is_slash(path[0])) || (plen >= 2 && is_slash(path[0])
|
return (plen == 1 && is_slash(path[0])) || (plen >= 2 && is_slash(path[0])
|
||||||
&& !is_slash(path[1]))
|
&& !is_slash(path[1]))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// is_curr_dir_ref returns `true` if the 3 given integer construct
|
||||||
|
// a reference to a current directory (.).
|
||||||
|
// NOTE: a negative integer means that no byte is present
|
||||||
|
fn is_curr_dir_ref(byte_one int, byte_two int, byte_three int) bool {
|
||||||
|
if u8(byte_two) != os.dot {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return (byte_one < 0 || is_slash(u8(byte_one))) && (byte_three < 0 || is_slash(u8(byte_three)))
|
||||||
|
}
|
||||||
|
|
|
@ -36,11 +36,13 @@ fn test_clean_path() {
|
||||||
assert clean_path(r'\./path/dir\\file.exe') == r'\path\dir\file.exe'
|
assert clean_path(r'\./path/dir\\file.exe') == r'\path\dir\file.exe'
|
||||||
assert clean_path(r'.') == ''
|
assert clean_path(r'.') == ''
|
||||||
assert clean_path(r'./') == ''
|
assert clean_path(r'./') == ''
|
||||||
|
assert clean_path('') == ''
|
||||||
assert clean_path(r'\./') == '\\'
|
assert clean_path(r'\./') == '\\'
|
||||||
assert clean_path(r'//\/\/////') == '\\'
|
assert clean_path(r'//\/\/////') == '\\'
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
assert clean_path('./../.././././//') == '../..'
|
assert clean_path('./../.././././//') == '../..'
|
||||||
|
assert clean_path('') == ''
|
||||||
assert clean_path('.') == ''
|
assert clean_path('.') == ''
|
||||||
assert clean_path('./path/to/file.v//./') == 'path/to/file.v'
|
assert clean_path('./path/to/file.v//./') == 'path/to/file.v'
|
||||||
assert clean_path('./') == ''
|
assert clean_path('./') == ''
|
||||||
|
@ -127,3 +129,26 @@ fn test_abs_path() {
|
||||||
assert abs_path('path/../file.v/..') == wd
|
assert abs_path('path/../file.v/..') == wd
|
||||||
assert abs_path('///') == '/'
|
assert abs_path('///') == '/'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn test_existing_path() {
|
||||||
|
wd := getwd()
|
||||||
|
$if windows {
|
||||||
|
assert existing_path('') or { '' } == ''
|
||||||
|
assert existing_path('..') or { '' } == '..'
|
||||||
|
assert existing_path('.') or { '' } == '.'
|
||||||
|
assert existing_path(wd) or { '' } == wd
|
||||||
|
assert existing_path('\\') or { '' } == '\\'
|
||||||
|
assert existing_path('$wd\\.\\\\does/not/exist\\.\\') or { '' } == '$wd\\.\\\\'
|
||||||
|
assert existing_path('$wd\\\\/\\.\\.\\/.') or { '' } == '$wd\\\\/\\.\\.\\/.'
|
||||||
|
assert existing_path('$wd\\././/\\/oh') or { '' } == '$wd\\././/\\/'
|
||||||
|
return
|
||||||
|
}
|
||||||
|
assert existing_path('') or { '' } == ''
|
||||||
|
assert existing_path('..') or { '' } == '..'
|
||||||
|
assert existing_path('.') or { '' } == '.'
|
||||||
|
assert existing_path(wd) or { '' } == wd
|
||||||
|
assert existing_path('/') or { '' } == '/'
|
||||||
|
assert existing_path('$wd/does/.///not/exist///.//') or { '' } == '$wd/'
|
||||||
|
assert existing_path('$wd//././/.//') or { '' } == '$wd//././/.//'
|
||||||
|
assert existing_path('$wd//././/.//oh') or { '' } == '$wd//././/.//'
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue