v symlink: use a .symlink/v.bat launcher to avoid global PATH polution

pull/5045/head
Delyan Angelov 2020-05-26 13:34:01 +03:00
parent 7585483c69
commit e79adc0ba1
2 changed files with 63 additions and 9 deletions

1
.gitignore vendored
View File

@ -66,3 +66,4 @@ cachegrind.out.*
.DS_Store
._*
thumbs.db
/.symlink/*

View File

@ -2,17 +2,15 @@ import os
import v.pref
fn main(){
vexe := pref.vexe_path()
$if windows {
vdir := os.real_path(os.dir(vexe))
res := os.system('setx /M PATH "$vdir;%PATH%"')
if res == 0 {
println('v has been prepended to the path')
exit(0)
}
exit(1)
setup_symlink_on_windows()
} $else {
setup_symlink_on_unix()
}
//
}
fn setup_symlink_on_unix(){
vexe := pref.vexe_path()
mut link_path := '/usr/local/bin/v'
mut ret := os.exec('ln -sf $vexe $link_path') or {
panic(err)
@ -34,3 +32,58 @@ fn main(){
println('Failed to create symlink "$link_path". Try again with sudo.')
}
}
fn setup_symlink_on_windows(){
vexe := pref.vexe_path()
// NB: Putting $vdir directly into PATH will also result in
// make.bat being global, which is NOT what we want.
//
// Instead, we create a small launcher v.bat, in a new local
// folder .symlink/ . That .symlink/ folder can then be put
// in PATH without poluting it with anything else - just a
// `v` command will be available, simillar to unix.
//
// Creating a real NTFS symlink to the real executable was also
// tried, but then os.real_path( os.executable() ) returns the
// path to the symlink, unfortunately, unlike on posix systems
// ¯\_(ツ)_/¯
vdir := os.real_path(os.dir(vexe))
vsymlinkdir := os.join_path(vdir, '.symlink')
vsymlinkbat := os.join_path(vsymlinkdir, 'v.bat')
os.rmdir_all(vsymlinkdir)
os.mkdir_all(vsymlinkdir)
os.write_file(vsymlinkbat, '$vexe %*')
if !os.exists( vsymlinkbat ) {
eprintln('Could not create $vsymlinkbat')
exit(1)
}
println('Created $vsymlinkbat .')
current_paths := os.getenv('PATH').split(';').map(it.trim('/\\'))
if vsymlinkdir in current_paths {
println('$vsymlinkdir is already on your PATH')
println('Try running `v version`')
exit(0)
}
// put vsymlinkdir first, prevent duplicates:
mut new_paths := [ vsymlinkdir ]
for p in current_paths {
if p !in new_paths {
new_paths << p
}
}
//
change_path_cmd := 'setx /M PATH "' + new_paths.join(';') +'"'
println('Changing global PATH with:')
println(change_path_cmd)
res := os.system(change_path_cmd)
if res == 0 {
println('')
println('$vsymlinkdir has been prepended to PATH.')
println('Try running `v version`.')
exit(0)
} else {
println('Could not run `setx`, probably you are not an administrator.')
println('`v symlink` should be launched with admin privileges.')
exit(1)
}
}