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() {
vexe := pref.vexe_path()
vexe := os.real_path(pref.vexe_path())
$if windows {
setup_symlink_windows(vexe)
} $else {
@ -36,10 +36,10 @@ fn setup_symlink(vexe string) {
if ret.exit_code == 0 {
println('Symlink "$link_path" has been created')
} else {
println('Failed to create symlink "$link_path". Try again with sudo.')
eprintln('Failed to create symlink "$link_path". Try again with sudo.')
}
} 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 {
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 {
// typically only fails if you're on a network drive (VirtualBox)
// 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...')
vsymlink = os.join_path(vsymlinkdir, 'v.bat')
if os.exists(vsymlink) {
os.rm(vsymlink)
}
os.write_file(vsymlink, '@echo off\n$vexe %*')
eprintln('$vsymlink file written.')
}
if !os.exists(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 {
warn_and_exit(err)
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'))
mut new_paths := [vsymlinkdir]
for p in current_sys_paths {
if p == '' {
continue
}
if p !in new_paths {
new_paths << p
}
}
new_sys_env_path := new_paths.join(';')
if new_sys_env_path == sys_env_path {
println('configured.')
println('System %PATH% was already configured.')
} 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 {
warn_and_exit(err)
C.RegCloseKey(reg_sys_env_handle)
@ -103,15 +109,16 @@ fn setup_symlink_windows(vexe string) {
}
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 {
eprintln('\n' + err)
eprintln(err)
warn_and_exit('You might need to run this again to have the `v` command in your %PATH%')
C.RegCloseKey(reg_sys_env_handle)
return
}
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!')
}
}

View File

@ -1141,9 +1141,27 @@ pub fn real_path(fpath string) string {
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.
pub fn is_abs_path(path string) bool {
$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
pub fn symlink(origin string, target string) ?bool {
flags := if is_dir(origin) { 1 } else { 0 }
if C.CreateSymbolicLinkW(origin.to_wide(), target.to_wide(), u32(flags)) != 0 {
return true
pub fn symlink(symlink_path string, target_path string) ?bool {
mut flags := 0
if is_dir(symlink_path) {
flags |= 1
}
return error(get_error_msg(int(C.GetLastError())))
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())))
}
if !exists(symlink_path) {
return error('C.CreateSymbolicLinkW reported success, but symlink still does not exist')
}
return true
}
pub fn (mut f File) close() {