From b11d285680038bfb3bc638292c87aedfd3f5e817 Mon Sep 17 00:00:00 2001 From: Delyan Angelov Date: Mon, 30 Nov 2020 19:31:37 +0200 Subject: [PATCH] v: support multiple paths in VMODULES env variable (#7048) --- cmd/tools/vdoc.v | 21 ++++++------ vlib/os/os.v | 18 ++++++++-- vlib/v/doc/module.v | 14 +++++--- vlib/v/pref/default.v | 16 +++++++-- .../tests/multiple_paths_in_vmodules/main.vv | 9 +++++ .../path1/.gitignore | 4 +++ .../multiple_paths_in_vmodules/path1/xxx/m.v | 4 +++ .../multiple_paths_in_vmodules/path2/yyy/m.v | 4 +++ .../multiple_paths_in_vmodules/path3/zzz/m.v | 4 +++ .../vmodules_overrides_test.v | 34 +++++++++++++++++++ 10 files changed, 109 insertions(+), 19 deletions(-) create mode 100644 vlib/v/tests/multiple_paths_in_vmodules/main.vv create mode 100644 vlib/v/tests/multiple_paths_in_vmodules/path1/.gitignore create mode 100644 vlib/v/tests/multiple_paths_in_vmodules/path1/xxx/m.v create mode 100644 vlib/v/tests/multiple_paths_in_vmodules/path2/yyy/m.v create mode 100644 vlib/v/tests/multiple_paths_in_vmodules/path3/zzz/m.v create mode 100644 vlib/v/tests/multiple_paths_in_vmodules/vmodules_overrides_test.v diff --git a/cmd/tools/vdoc.v b/cmd/tools/vdoc.v index 204e22e60c..4cf5d7e3c5 100644 --- a/cmd/tools/vdoc.v +++ b/cmd/tools/vdoc.v @@ -37,10 +37,9 @@ enum HighlightTokenTyp { const ( css_js_assets = ['doc.css', 'normalize.css', 'doc.js'] allowed_formats = ['md', 'markdown', 'json', 'text', 'stdout', 'html', 'htm'] - exe_path = os.executable() - exe_dir = os.dir(exe_path) - res_path = os.join_path(exe_dir, 'vdoc-resources') - vexe_path = os.dir(@VEXE) + res_path = os.resource_abs_path('vdoc-resources') + vexe = pref.vexe_path() + vroot = os.dir(vexe) html_content = ' @@ -192,7 +191,9 @@ struct VdocHttpServerContext { } fn handle_http_connection(mut con net.TcpConn, ctx &VdocHttpServerContext) { - mut reader := io.new_buffered_reader(reader: io.make_reader(con)) + mut reader := io.new_buffered_reader({ + reader: io.make_reader(con) + }) first_line := reader.read_line() or { send_http_response(mut con, 501, ctx.content_type, 'bad request') return @@ -715,7 +716,7 @@ fn (mut cfg DocConfig) generate_docs_from_file() { exit(1) } dir_path := if cfg.is_vlib { - vexe_path + vroot } else if os.is_dir(cfg.input_path) { cfg.input_path } else { @@ -935,11 +936,11 @@ fn (cfg DocConfig) get_resource(name string, minify bool) string { } fn main() { - args := os.args[2..].clone() - if args.len == 0 || args[0] in ['help', '-h', '--help'] { - os.system('${@VEXE} help doc') + if os.args.len < 2 || '-h' in os.args || '--help' in os.args || os.args[1..] == ['doc', 'help'] { + os.system('$vexe help doc') exit(0) } + args := os.args[2..].clone() mut cfg := DocConfig{ manifest: vmod.Manifest{ repo_url: '' @@ -1050,7 +1051,7 @@ fn main() { if cfg.input_path.trim_right('/') == 'vlib' { cfg.is_vlib = true cfg.is_multi = true - cfg.input_path = os.join_path(vexe_path, 'vlib') + cfg.input_path = os.join_path(vroot, 'vlib') } else if !is_path { cfg.vprintln('Input "$cfg.input_path" is not a valid path. Looking for modules named "$cfg.input_path"...') mod_path := doc.lookup_module(cfg.input_path) or { diff --git a/vlib/os/os.v b/vlib/os/os.v index e39c0f6f73..37b7bc90b1 100644 --- a/vlib/os/os.v +++ b/vlib/os/os.v @@ -1354,13 +1354,27 @@ pub fn temp_dir() string { return path } +fn default_vmodules_path() string { + return os.join_path(os.home_dir(), '.vmodules') +} // vmodules_dir returns the path to a folder, where v stores its global modules. pub fn vmodules_dir() string { + paths := vmodules_paths() + if paths.len > 0 { + return paths[0] + } + return os.default_vmodules_path() +} + +// vmodules_paths returns a list of paths, where v looks up for modules. +// You can customize it through setting the environment variable VMODULES +pub fn vmodules_paths() []string { mut path := os.getenv('VMODULES') if path == '' { - path = os.join_path(os.home_dir(), '.vmodules') + path = os.default_vmodules_path() } - return path + list := path.split(os.path_delimiter).map(it.trim_right(os.path_separator)) + return list } // chmod change file access attributes of `path` to `mode`. diff --git a/vlib/v/doc/module.v b/vlib/v/doc/module.v index 8373c38888..474dd431c8 100644 --- a/vlib/v/doc/module.v +++ b/vlib/v/doc/module.v @@ -1,9 +1,10 @@ module doc +import os import v.table import v.parser import v.ast -import os +import v.pref // get_parent_mod - return the parent mod name, in dot format. // It works by climbing up the folder hierarchy, until a folder, @@ -61,12 +62,17 @@ fn get_parent_mod(input_dir string) ?string { } pub fn lookup_module_with_path(mod string, base_path string) ?string { + vexe := pref.vexe_path() + vroot := os.dir(vexe) mod_path := mod.replace('.', os.path_separator) compile_dir := os.real_path(base_path) modules_dir := os.join_path(compile_dir, 'modules', mod_path) - vlib_path := os.join_path(os.dir(@VEXE), 'vlib', mod_path) - vmodules_path := os.join_path(os.vmodules_dir(), mod_path) - paths := [modules_dir, vlib_path, vmodules_path] + vlib_path := os.join_path(vroot, 'vlib', mod_path) + mut paths := [modules_dir, vlib_path] + vmodules_paths := os.vmodules_paths() + for vmpath in vmodules_paths { + paths << os.join_path(vmpath, mod_path) + } for path in paths { if !os.exists(path) || os.is_dir_empty(path) { continue diff --git a/vlib/v/pref/default.v b/vlib/v/pref/default.v index 5fcccf7314..2b7637c995 100644 --- a/vlib/v/pref/default.v +++ b/vlib/v/pref/default.v @@ -16,7 +16,7 @@ pub fn new_preferences() Preferences { return p } -pub fn (mut p Preferences) fill_with_defaults() { +fn (mut p Preferences) expand_lookup_paths() { if p.vroot == '' { // Location of all vlib files p.vroot = os.dir(vexe_path()) @@ -25,9 +25,19 @@ pub fn (mut p Preferences) fill_with_defaults() { if p.lookup_path.len == 0 { p.lookup_path = ['@vlib', '@vmodules'] } - for i, path in p.lookup_path { - p.lookup_path[i] = path.replace('@vlib', vlib_path).replace('@vmodules', default_module_path) + mut expanded_paths := []string{} + for path in p.lookup_path { + match path { + '@vlib' { expanded_paths << vlib_path } + '@vmodules' { expanded_paths << os.vmodules_paths() } + else { expanded_paths << path } + } } + p.lookup_path = expanded_paths +} + +pub fn (mut p Preferences) fill_with_defaults() { + p.expand_lookup_paths() rpath := os.real_path(p.path) if p.out_name == '' { filename := os.file_name(rpath).trim_space() diff --git a/vlib/v/tests/multiple_paths_in_vmodules/main.vv b/vlib/v/tests/multiple_paths_in_vmodules/main.vv new file mode 100644 index 0000000000..2fae430d1a --- /dev/null +++ b/vlib/v/tests/multiple_paths_in_vmodules/main.vv @@ -0,0 +1,9 @@ +import yyy +import xxx +import zzz + +fn main() { + all := [xxx.f(), yyy.f(), zzz.f()] + println(all) + assert all == ['x','y','z'] +} diff --git a/vlib/v/tests/multiple_paths_in_vmodules/path1/.gitignore b/vlib/v/tests/multiple_paths_in_vmodules/path1/.gitignore new file mode 100644 index 0000000000..38977ffd21 --- /dev/null +++ b/vlib/v/tests/multiple_paths_in_vmodules/path1/.gitignore @@ -0,0 +1,4 @@ +## this folder is the first one that will be put in vmodules. +## V uses that to put there its cache too. +## Just ignore it for now. +cache/ diff --git a/vlib/v/tests/multiple_paths_in_vmodules/path1/xxx/m.v b/vlib/v/tests/multiple_paths_in_vmodules/path1/xxx/m.v new file mode 100644 index 0000000000..0ff85a26d8 --- /dev/null +++ b/vlib/v/tests/multiple_paths_in_vmodules/path1/xxx/m.v @@ -0,0 +1,4 @@ +module xxx +pub fn f() string { + return 'x' +} diff --git a/vlib/v/tests/multiple_paths_in_vmodules/path2/yyy/m.v b/vlib/v/tests/multiple_paths_in_vmodules/path2/yyy/m.v new file mode 100644 index 0000000000..f596280bd6 --- /dev/null +++ b/vlib/v/tests/multiple_paths_in_vmodules/path2/yyy/m.v @@ -0,0 +1,4 @@ +module yyy +pub fn f() string { + return 'y' +} diff --git a/vlib/v/tests/multiple_paths_in_vmodules/path3/zzz/m.v b/vlib/v/tests/multiple_paths_in_vmodules/path3/zzz/m.v new file mode 100644 index 0000000000..975dd4bdc8 --- /dev/null +++ b/vlib/v/tests/multiple_paths_in_vmodules/path3/zzz/m.v @@ -0,0 +1,4 @@ +module zzz +pub fn f() string { + return 'z' +} diff --git a/vlib/v/tests/multiple_paths_in_vmodules/vmodules_overrides_test.v b/vlib/v/tests/multiple_paths_in_vmodules/vmodules_overrides_test.v new file mode 100644 index 0000000000..e5c528b49f --- /dev/null +++ b/vlib/v/tests/multiple_paths_in_vmodules/vmodules_overrides_test.v @@ -0,0 +1,34 @@ +import os + +const ( + vexe = os.getenv('VEXE') + vroot = os.dir(vexe) + basepath = os.real_path(os.join_path(vroot, 'vlib', 'v', 'tests', 'multiple_paths_in_vmodules')) + mainvv = os.join_path(basepath, 'main.vv') +) + +fn test_vexe_is_set() { + assert vexe != '' + println('vexe: $vexe') +} + +fn test_compiling_without_vmodules_fails() { + os.chdir(vroot) + os.setenv('VMODULES', '', true) + res := os.exec('"$vexe" run "$mainvv"') or { + panic(err) + } + assert res.exit_code == 1 + assert res.output.trim_space() == 'builder error: cannot import module "yyy" (not found)' +} + +fn test_compiling_with_vmodules_works() { + os.chdir(vroot) + vmpaths := ['path1', 'path2', 'path3'].map(os.join_path(basepath, it)) + os.setenv('VMODULES', vmpaths.join(os.path_delimiter), true) + res := os.exec('"$vexe" run "$mainvv"') or { + panic(err) + } + assert res.exit_code == 0 + assert res.output.trim_space() == "['x', 'y', 'z']" +}