v symlink: fix windows PATH setting (cmd.exe needs C: not c:)

pull/6672/head
Delyan Angelov 2020-10-22 17:28:58 +03:00
parent 66b8462d7a
commit f7698ea160
3 changed files with 51 additions and 17 deletions

View File

@ -8,7 +8,7 @@ $if windows {
} }
} }
fn main() { fn main() {
vexe := pref.vexe_path() vexe := os.real_path(pref.vexe_path())
$if windows { $if windows {
setup_symlink_windows(vexe) setup_symlink_windows(vexe)
} $else { } $else {
@ -36,10 +36,10 @@ fn setup_symlink(vexe string) {
if ret.exit_code == 0 { if ret.exit_code == 0 {
println('Symlink "$link_path" has been created') println('Symlink "$link_path" has been created')
} else { } else {
println('Failed to create symlink "$link_path". Try again with sudo.') eprintln('Failed to create symlink "$link_path". Try again with sudo.')
} }
} else { } else {
println('Failed to create symlink "$link_path". Try again with sudo.') eprintln('Failed to create symlink "$link_path". Try again with sudo.')
} }
} }
@ -56,22 +56,24 @@ fn setup_symlink_windows(vexe string) {
} else { } else {
os.rm(vsymlink) os.rm(vsymlink)
} }
// try to create a native symlink at .\.bin\v.exe // First, try to create a native symlink at .\.bin\v.exe
os.symlink(vsymlink, vexe) or { os.symlink(vsymlink, vexe) or {
// typically only fails if you're on a network drive (VirtualBox) // typically only fails if you're on a network drive (VirtualBox)
// do batch file creation instead // do batch file creation instead
eprint('NOTE: Could not create a native symlink: $err') eprintln('Could not create a native symlink: $err')
eprintln('Creating a batch file instead...') eprintln('Creating a batch file instead...')
vsymlink = os.join_path(vsymlinkdir, 'v.bat') vsymlink = os.join_path(vsymlinkdir, 'v.bat')
if os.exists(vsymlink) { if os.exists(vsymlink) {
os.rm(vsymlink) os.rm(vsymlink)
} }
os.write_file(vsymlink, '@echo off\n$vexe %*') os.write_file(vsymlink, '@echo off\n$vexe %*')
eprintln('$vsymlink file written.')
} }
if !os.exists(vsymlink) { if !os.exists(vsymlink) {
warn_and_exit('Could not create $vsymlink') warn_and_exit('Could not create $vsymlink')
} }
print('Symlink $vsymlink to $vexe created.\n\nChecking system %PATH%...') println('Symlink $vsymlink to $vexe created.')
println('Checking system %PATH%...')
reg_sys_env_handle := get_reg_sys_env_handle() or { reg_sys_env_handle := get_reg_sys_env_handle() or {
warn_and_exit(err) warn_and_exit(err)
return return
@ -87,15 +89,19 @@ fn setup_symlink_windows(vexe string) {
current_sys_paths := sys_env_path.split(os.path_delimiter).map(it.trim('/$os.path_separator')) current_sys_paths := sys_env_path.split(os.path_delimiter).map(it.trim('/$os.path_separator'))
mut new_paths := [vsymlinkdir] mut new_paths := [vsymlinkdir]
for p in current_sys_paths { for p in current_sys_paths {
if p == '' {
continue
}
if p !in new_paths { if p !in new_paths {
new_paths << p new_paths << p
} }
} }
new_sys_env_path := new_paths.join(';') new_sys_env_path := new_paths.join(';')
if new_sys_env_path == sys_env_path { if new_sys_env_path == sys_env_path {
println('configured.') println('System %PATH% was already configured.')
} else { } else {
print('not configured.\nAdding symlink directory to system %PATH%...') println('System %PATH% was not configured.')
println('Adding symlink directory to system %PATH%...')
set_reg_value(reg_sys_env_handle, 'Path', new_sys_env_path) or { set_reg_value(reg_sys_env_handle, 'Path', new_sys_env_path) or {
warn_and_exit(err) warn_and_exit(err)
C.RegCloseKey(reg_sys_env_handle) C.RegCloseKey(reg_sys_env_handle)
@ -103,15 +109,16 @@ fn setup_symlink_windows(vexe string) {
} }
println('done.') println('done.')
} }
print('Letting running process know to update their Environment...') println('Notifying running processes to update their Environment...')
send_setting_change_msg('Environment') or { send_setting_change_msg('Environment') or {
eprintln('\n' + err) eprintln(err)
warn_and_exit('You might need to run this again to have the `v` command in your %PATH%') warn_and_exit('You might need to run this again to have the `v` command in your %PATH%')
C.RegCloseKey(reg_sys_env_handle) C.RegCloseKey(reg_sys_env_handle)
return return
} }
C.RegCloseKey(reg_sys_env_handle) C.RegCloseKey(reg_sys_env_handle)
println('finished.\n\nNote: restart your shell/IDE to load the new %PATH%.') println('')
println('Note: restart your shell/IDE to load the new %PATH%.')
println('After restarting your shell/IDE, give `v version` a try in another dir!') println('After restarting your shell/IDE, give `v version` a try in another dir!')
} }
} }

View File

@ -1141,9 +1141,27 @@ pub fn real_path(fpath string) string {
return fpath return fpath
} }
} }
return unsafe { fullpath.vstring() } res := unsafe { fullpath.vstring() }
return normalize_drive_letter(res)
} }
fn normalize_drive_letter(path string) string {
// normalize_drive_letter is needed, because a path like c:\nv\.bin (note the small `c`)
// in %PATH is NOT recognized by cmd.exe (and probably other programs too)...
// Capital drive letters do work fine.
$if !windows {
return path
}
if path.len > 2 && path[0] >= `a` && path[0] <= `z` && path[1] == `:` && path[2] == os.path_separator[0] {
unsafe {
x := &path.str[0]
(*x) = *x - 32
}
}
return path
}
// is_abs_path returns `true` if `path` is absolute. // is_abs_path returns `true` if `path` is absolute.
pub fn is_abs_path(path string) bool { pub fn is_abs_path(path string) bool {
$if windows { $if windows {

View File

@ -294,14 +294,23 @@ pub fn exec(cmd string) ?Result {
} }
} }
// See https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-createsymboliclinkw
fn C.CreateSymbolicLinkW(&u16, &u16, u32) int fn C.CreateSymbolicLinkW(&u16, &u16, u32) int
pub fn symlink(origin string, target string) ?bool { pub fn symlink(symlink_path string, target_path string) ?bool {
flags := if is_dir(origin) { 1 } else { 0 } mut flags := 0
if C.CreateSymbolicLinkW(origin.to_wide(), target.to_wide(), u32(flags)) != 0 { if is_dir(symlink_path) {
return true flags |= 1
} }
flags |= 2 // SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE
res := C.CreateSymbolicLinkW(symlink_path.to_wide(), target_path.to_wide(), flags)
if res == 0 {
return error(get_error_msg(int(C.GetLastError()))) return error(get_error_msg(int(C.GetLastError())))
}
if !exists(symlink_path) {
return error('C.CreateSymbolicLinkW reported success, but symlink still does not exist')
}
return true
} }
pub fn (mut f File) close() { pub fn (mut f File) close() {