From e79adc0ba1384a7a06bd79dcbc295ef6a8561fff Mon Sep 17 00:00:00 2001 From: Delyan Angelov Date: Tue, 26 May 2020 13:34:01 +0300 Subject: [PATCH] v symlink: use a .symlink/v.bat launcher to avoid global PATH polution --- .gitignore | 1 + cmd/tools/vsymlink.v | 71 ++++++++++++++++++++++++++++++++++++++------ 2 files changed, 63 insertions(+), 9 deletions(-) diff --git a/.gitignore b/.gitignore index 79125ef272..5abc519ab1 100644 --- a/.gitignore +++ b/.gitignore @@ -66,3 +66,4 @@ cachegrind.out.* .DS_Store ._* thumbs.db +/.symlink/* diff --git a/cmd/tools/vsymlink.v b/cmd/tools/vsymlink.v index 2350e53c91..63d06b24c3 100644 --- a/cmd/tools/vsymlink.v +++ b/cmd/tools/vsymlink.v @@ -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) + } +}