From 5518bfc7d5534e061bef8fdb3fef4e0280bae558 Mon Sep 17 00:00:00 2001 From: Alexander Medvednikov Date: Wed, 22 Apr 2026 13:58:49 +0300 Subject: [PATCH] all: remove src/ virtual dirs (replaced with v.mod subdirs) --- vlib/v/builder/builder.v | 85 ++++++++++++------- vlib/v/builder/builder_test.v | 54 +----------- vlib/v/builder/compile.v | 21 +---- vlib/v/gen/c/cgen.v | 10 ++- .../tests/projects_that_should_compile_test.v | 20 ++--- .../module_named_cache/src/cache/my_cache.v | 3 - .../testdata/module_named_cache/src/main.v | 8 -- .../v/tests/testdata/module_named_cache/v.mod | 7 -- .../modules/somemoduletwo/somemoduletwo.v | 7 -- .../tests/testdata/modules_in_src/src/main.v | 8 -- .../src/modules/somemodule/somemodule.v | 7 -- vlib/v/tests/testdata/modules_in_src/v.mod | 7 -- .../testdata/sibling_modules_in_src/src/a/a.v | 5 -- .../testdata/sibling_modules_in_src/src/b/b.v | 7 -- .../sibling_modules_in_src/src/main.v | 7 -- .../testdata/sibling_modules_in_src/v.mod | 3 - vlib/v/util/module.v | 63 ++++---------- vlib/v/vmod/vmod.v | 5 +- 18 files changed, 94 insertions(+), 233 deletions(-) delete mode 100644 vlib/v/tests/testdata/module_named_cache/src/cache/my_cache.v delete mode 100644 vlib/v/tests/testdata/module_named_cache/src/main.v delete mode 100644 vlib/v/tests/testdata/module_named_cache/v.mod delete mode 100644 vlib/v/tests/testdata/modules_in_src/modules/somemoduletwo/somemoduletwo.v delete mode 100644 vlib/v/tests/testdata/modules_in_src/src/main.v delete mode 100644 vlib/v/tests/testdata/modules_in_src/src/modules/somemodule/somemodule.v delete mode 100644 vlib/v/tests/testdata/modules_in_src/v.mod delete mode 100644 vlib/v/tests/testdata/sibling_modules_in_src/src/a/a.v delete mode 100644 vlib/v/tests/testdata/sibling_modules_in_src/src/b/b.v delete mode 100644 vlib/v/tests/testdata/sibling_modules_in_src/src/main.v delete mode 100644 vlib/v/tests/testdata/sibling_modules_in_src/v.mod diff --git a/vlib/v/builder/builder.v b/vlib/v/builder/builder.v index 962a70244..04e6fdc97 100644 --- a/vlib/v/builder/builder.v +++ b/vlib/v/builder/builder.v @@ -574,20 +574,46 @@ pub fn (b &Builder) v_files_from_dir(dir string) []string { } mut res := b.pref.should_compile_filtered_files(dir, files) if res.len == 0 { - // Perhaps the .v files are stored in a custom source root? - source_root := source_root_from_vmod_root(dir) or { os.join_path(dir, 'src') } - if source_root != dir && os.is_dir(source_root) { - if b.pref.is_verbose { - println('v_files_from_dir ("${source_root}") (v.mod source root)') + // An explicit `base_url` in v.mod still re-homes the source folder. + if source_root := source_root_from_vmod_root(dir) { + if source_root != dir && os.is_dir(source_root) { + if b.pref.is_verbose { + println('v_files_from_dir ("${source_root}") (v.mod base_url)') + } + files = os.ls(source_root) or { panic(err) } + source_dir = os.real_path(source_root) + res = b.pref.should_compile_filtered_files(source_root, files) } - files = os.ls(source_root) or { panic(err) } - source_dir = os.real_path(source_root) - res = b.pref.should_compile_filtered_files(source_root, files) + } + if res.len == 0 { + report_removed_src_layout_if_any(dir) } } return b.with_same_module_subdir_files(source_dir, res) } +// report_removed_src_layout_if_any prints a clear error if `dir` still relies on +// the removed virtual `src/` module layout (sources under `dir/src/` instead of +// at the module root). The explicit `base_url` opt-in in v.mod is unaffected. +fn report_removed_src_layout_if_any(dir string) { + src_dir := os.join_path(dir, 'src') + if !os.is_dir(src_dir) { + return + } + src_files := os.ls(src_dir) or { return } + mut has_v_files := false + for f in src_files { + if f.ends_with('.v') { + has_v_files = true + break + } + } + if !has_v_files { + return + } + verror('the virtual `src/` module directory is no longer supported.\nV found .v source files under ${src_dir}, but will not treat `src/` as a virtual module root anymore.\nPlease move the sources up from `src/` into ${dir}:\n\tmv ${src_dir}/*.v ${dir}/\n\trmdir ${src_dir}\n\nIf you really want the sources to live in a subfolder, set `base_url` in v.mod to point at it.') +} + fn (b &Builder) with_same_module_subdir_files(source_dir string, v_files []string) []string { mut mcache := vmod.get_cache() vmod_file_location := mcache.get_by_folder(source_dir) @@ -609,9 +635,7 @@ fn (b &Builder) with_same_module_subdir_files(source_dir string, v_files []strin seen[os.real_path(file)] = true } for subdir in subdirs { - normalized_subdir := normalize_same_module_subdir(subdir, module_source_root) or { - continue - } + normalized_subdir := normalize_same_module_subdir(subdir, manifest.base_url) or { continue } subdir_path := os.join_path(module_source_root, normalized_subdir) b.collect_same_module_v_files(vmod_file_location.vmod_folder, subdir_path, mut seen, mut res) @@ -621,29 +645,30 @@ fn (b &Builder) with_same_module_subdir_files(source_dir string, v_files []strin fn (b &Builder) module_source_root(module_root string) string { real_module_root := os.real_path(module_root) - files := os.ls(real_module_root) or { return real_module_root } - if b.pref.should_compile_filtered_files(real_module_root, files).len == 0 { - src_path := os.join_path(real_module_root, 'src') - if os.is_dir(src_path) { - return os.real_path(src_path) + if source_root := source_root_from_vmod_root(real_module_root) { + if source_root != real_module_root && os.is_dir(source_root) { + return os.real_path(source_root) } } return real_module_root } -fn normalize_same_module_subdir(subdir string, module_source_root string) !string { +fn normalize_same_module_subdir(subdir string, base_url string) !string { mut normalized := os.norm_path(subdir.trim_space().replace('\\', os.path_separator).replace('/', os.path_separator)) if normalized == '' || normalized == '.' || os.is_abs_path(normalized) { return error('invalid subdir') } - if os.base(module_source_root) == 'src' { - src_prefix := 'src' + os.path_separator - if normalized == 'src' { - return error('invalid subdir') - } - if normalized.starts_with(src_prefix) { - normalized = normalized.all_after(src_prefix) + if base_url != '' { + base := os.norm_path(base_url).trim_left(os.path_separator).trim_right(os.path_separator) + if base != '' { + base_prefix := base + os.path_separator + if normalized == base { + return error('invalid subdir') + } + if normalized.starts_with(base_prefix) { + normalized = normalized.all_after(base_prefix) + } } } normalized = normalized.trim_left(os.path_separator).trim_right(os.path_separator) @@ -710,15 +735,17 @@ fn manifest_from_vmod_root(vmod_root string) !vmod.Manifest { fn source_root_from_vmod_root(vmod_root string) !string { manifest := manifest_from_vmod_root(vmod_root)! + if manifest.base_url == '' { + return error('module not found') + } return manifest.source_root(vmod_root) } -fn lookup_source_root_from_vmod_root(vmod_root string) string { - return source_root_from_vmod_root(vmod_root) or { os.join_path(vmod_root, 'src') } -} - fn find_module_path_from_vmod_root(vmod_root string, mod string) !string { manifest := manifest_from_vmod_root(vmod_root)! + if manifest.base_url == '' { + return error('module not found') + } tail_path := mod_tail_after_vmod_name(mod, manifest.name) or { return error('module not found') } @@ -747,8 +774,8 @@ fn find_module_path_from_search_root(search_path string, mod string) !string { if !os.is_file(os.join_path(candidate_root, 'v.mod')) { continue } + source_root := source_root_from_vmod_root(candidate_root) or { continue } submodule_path := mod_parts[i..].join(os.path_separator) - source_root := lookup_source_root_from_vmod_root(candidate_root) src_try_path := os.join_path(source_root, submodule_path) if os.is_dir(src_try_path) { return src_try_path diff --git a/vlib/v/builder/builder_test.v b/vlib/v/builder/builder_test.v index 008985212..a814ba4f8 100644 --- a/vlib/v/builder/builder_test.v +++ b/vlib/v/builder/builder_test.v @@ -25,8 +25,7 @@ fn run_v_ok(command string) string { fn test_conditional_executable_removal() { os.chdir(test_path)! - os.mkdir_all('src')! - os.write_file('src/main.v', 'fn main(){\n\tprintln("Hello World!")\n}\n')! + os.write_file('main.v', 'fn main(){\n\tprintln("Hello World!")\n}\n')! mut executable := 'run_check' $if windows { @@ -93,57 +92,6 @@ pub struct BS{} assert os.execute('./${executable}').output.trim_space() == 'AS{}=>BS{}' } -fn test_run_explicit_src_directory_uses_project_root_lookup() { - os.chdir(test_path)! - project_dir := os.join_path(test_path, 'run_src_project') - defer { - os.chdir(test_path) or {} - } - os.mkdir_all(os.join_path(project_dir, 'src'))! - os.mkdir_all(os.join_path(project_dir, 'modules', 'somemoduletwo'))! - os.write_file(os.join_path(project_dir, 'src', 'main.v'), 'module main -import somemoduletwo - -fn main() { - println(somemoduletwo.name()) -} -')! - os.write_file(os.join_path(project_dir, 'modules', 'somemoduletwo', 'somemoduletwo.v'), 'module somemoduletwo - -pub fn name() string { - return "somemoduletwo" -} -')! - os.chdir(project_dir)! - assert run_v_ok('${os.quoted_path(vexe)} run src').trim_space() == 'somemoduletwo' - assert run_v_ok('${os.quoted_path(vexe)} run ./src').trim_space() == 'somemoduletwo' -} - -fn test_run_explicit_main_file_inside_src_resolves_nested_module_imports() { - os.chdir(test_path)! - project_dir := os.join_path(test_path, 'run_src_main_file_project') - os.mkdir_all(os.join_path(project_dir, 'src', 'infrastructure', 'database'))! - os.write_file(os.join_path(project_dir, 'src', 'infrastructure', 'database', 'database.v'), 'module database - -pub fn name() string { - return "database" -} -')! - os.write_file(os.join_path(project_dir, 'src', 'infrastructure', 'infrastructure.v'), 'module infrastructure -')! - os.write_file(os.join_path(project_dir, 'src', 'main.v'), 'module main - -import infrastructure.database - -fn main() { - println(database.name()) -} -')! - - main_file := os.join_path('run_src_main_file_project', 'src', 'main.v') - assert run_v_ok('${os.quoted_path(vexe)} run ${os.quoted_path(main_file)}').trim_space() == 'database' -} - fn test_run_custom_base_url_uses_project_root_lookup() { os.chdir(test_path)! project_dir := os.join_path(test_path, 'run_base_url_project') diff --git a/vlib/v/builder/compile.v b/vlib/v/builder/compile.v index 3fda0a6e5..8e587187c 100644 --- a/vlib/v/builder/compile.v +++ b/vlib/v/builder/compile.v @@ -246,9 +246,6 @@ pub fn (mut v Builder) set_module_lookup_paths() { println('x: "${x}"') } - if os.exists(os.join_path(lookup_root, 'src/modules')) { - v.module_search_paths << os.join_path(lookup_root, 'src/modules') - } if source_root := source_root_from_vmod_root(lookup_root) { source_modules := os.join_path(source_root, 'modules') if source_modules !in v.module_search_paths && os.exists(source_modules) { @@ -267,6 +264,8 @@ pub fn (mut v Builder) set_module_lookup_paths() { } fn (v &Builder) module_lookup_root() string { + // If `compiled_dir` is the base_url-configured source folder, treat the + // enclosing module folder as the lookup root so sibling `modules/` resolves. mut mcache := vmod.get_cache() vmod_file_location := mcache.get_by_folder(v.compiled_dir) if vmod_file_location.vmod_file != '' && vmod_file_location.vmod_folder != v.compiled_dir { @@ -276,22 +275,6 @@ fn (v &Builder) module_lookup_root() string { } } } - if os.file_name(v.compiled_dir) != 'src' { - return v.compiled_dir - } - project_dir := os.dir(v.compiled_dir) - if project_dir == v.compiled_dir { - return v.compiled_dir - } - if vmod_file_location.vmod_folder == project_dir { - return project_dir - } - if os.real_path(os.getwd()) == project_dir { - return project_dir - } - if os.is_dir(os.join_path(project_dir, 'modules')) { - return project_dir - } return v.compiled_dir } diff --git a/vlib/v/gen/c/cgen.v b/vlib/v/gen/c/cgen.v index cbd509b40..31e6624f6 100644 --- a/vlib/v/gen/c/cgen.v +++ b/vlib/v/gen/c/cgen.v @@ -6583,8 +6583,14 @@ fn (mut g Gen) selector_expr(node ast.SelectorExpr) { if field_sym.kind == .interface && cast_sym.kind == .interface && !is_option_unwrap { ptr := '*'.repeat(field.typ.nr_muls()) - dot := if node.expr_type.is_ptr() { '->' } else { '.' } - g.write('I_${field_sym.cname}_as_I_${cast_sym.cname}(${ptr}${node.expr}${dot}${node.field_name}))') + // Emit the receiver via g.expr() so smartcasts on the + // receiver (e.g. `mut child is SubWindow` → `(child._SubWindow)`) + // are preserved. Use lhs_expr_type for the dot since it + // reflects the smartcast'd type, not the original interface. + g.write('I_${field_sym.cname}_as_I_${cast_sym.cname}(${ptr}') + g.expr(node.expr) + dot := if lhs_expr_type.is_ptr() { '->' } else { '.' } + g.write('${dot}${node.field_name}))') return } else if !is_option_unwrap { if i != 0 { diff --git a/vlib/v/tests/projects_that_should_compile_test.v b/vlib/v/tests/projects_that_should_compile_test.v index 4b2a00555..1f920cc23 100644 --- a/vlib/v/tests/projects_that_should_compile_test.v +++ b/vlib/v/tests/projects_that_should_compile_test.v @@ -32,16 +32,16 @@ fn setup_module_resolution_workdir_fixture() string { 'v_module_resolution_independent_of_workdir_${os.getpid()}') interp := r'${' os.rmdir_all(workspace) or {} - os.mkdir_all(os.join_path(workspace, 'app', 'src')) or { panic(err) } - os.mkdir_all(os.join_path(workspace, 'lib', 'src')) or { panic(err) } + os.mkdir_all(os.join_path(workspace, 'app')) or { panic(err) } + os.mkdir_all(os.join_path(workspace, 'lib')) or { panic(err) } write_file(os.join_path(workspace, '.v.mod.stop'), '') write_file(os.join_path(workspace, 'app', 'v.mod'), "Module {\n\tname: 'app'\n\tdescription: ''\n\tversion: ''\n\tlicense: ''\n\tdependencies: []\n}\n") - write_file(os.join_path(workspace, 'app', 'src', 'main.v'), + write_file(os.join_path(workspace, 'app', 'main.v'), "module main\n\nimport lib\n\nfn main() {\n\tprintln('Hello ${interp}lib.square(4)}!')\n}\n") write_file(os.join_path(workspace, 'lib', 'v.mod'), "Module {\n\tname: 'lib'\n\tdescription: ''\n\tversion: ''\n\tlicense: ''\n\tdependencies: []\n}\n") - write_file(os.join_path(workspace, 'lib', 'src', 'lib.v'), + write_file(os.join_path(workspace, 'lib', 'lib.v'), 'module lib\n\npub fn square(x int) int {\n\treturn x * x\n}\n') return workspace } @@ -63,12 +63,6 @@ fn test_projects_should_run() { } res := vrun_ok('run', vroot_path('vlib/v/tests/testdata/enum_in_builtin') + os.path_separator) assert res.trim_space() == 'v0' - - res2 := vrun_ok('run', vroot_path('vlib/v/tests/testdata/modules_in_src/')) - assert res2.trim_space() == 'somemodule somemoduletwo' - - res3 := vrun_ok('run', vroot_path('vlib/v/tests/testdata/module_named_cache/')) - assert res3.trim_space().ends_with('cache.a: 123') } fn test_running_subdir_project_with_parent_vmod_works() { @@ -99,14 +93,14 @@ fn test_running_module_with_same_module_subdirs_setting_works() { defer { os.rmdir_all(root) or {} } - os.mkdir_all(os.join_path(root, 'app', 'foo', 'src', 'internal', 'nested'))! + os.mkdir_all(os.join_path(root, 'app', 'foo', 'internal', 'nested'))! os.write_file(os.join_path(root, 'app', 'main.v'), 'module main\n\nimport foo\n\nfn main() {\n\tprintln(foo.answer())\n}\n')! os.write_file(os.join_path(root, 'app', 'foo', 'v.mod'), "Module {\n\tname: 'foo'\n\tsubdirs: ['internal']\n}\n")! - os.write_file(os.join_path(root, 'app', 'foo', 'src', 'foo.v'), + os.write_file(os.join_path(root, 'app', 'foo', 'foo.v'), 'module foo\n\npub fn answer() int {\n\treturn secret()\n}\n')! - os.write_file(os.join_path(root, 'app', 'foo', 'src', 'internal', 'nested', 'secret.v'), + os.write_file(os.join_path(root, 'app', 'foo', 'internal', 'nested', 'secret.v'), 'module foo\n\nfn secret() int {\n\treturn 42\n}\n')! old_dir := os.getwd() defer { diff --git a/vlib/v/tests/testdata/module_named_cache/src/cache/my_cache.v b/vlib/v/tests/testdata/module_named_cache/src/cache/my_cache.v deleted file mode 100644 index ff345da98..000000000 --- a/vlib/v/tests/testdata/module_named_cache/src/cache/my_cache.v +++ /dev/null @@ -1,3 +0,0 @@ -module cache - -pub const a = 123 diff --git a/vlib/v/tests/testdata/module_named_cache/src/main.v b/vlib/v/tests/testdata/module_named_cache/src/main.v deleted file mode 100644 index 2c476aa1e..000000000 --- a/vlib/v/tests/testdata/module_named_cache/src/main.v +++ /dev/null @@ -1,8 +0,0 @@ -module main - -import cache - -fn main() { - println('Hello World!') - dump(cache.a) -} diff --git a/vlib/v/tests/testdata/module_named_cache/v.mod b/vlib/v/tests/testdata/module_named_cache/v.mod deleted file mode 100644 index 7dd2a885c..000000000 --- a/vlib/v/tests/testdata/module_named_cache/v.mod +++ /dev/null @@ -1,7 +0,0 @@ -Module { - name: 'aa' - description: 'AA' - version: '0.0.0' - license: 'MIT' - dependencies: [] -} diff --git a/vlib/v/tests/testdata/modules_in_src/modules/somemoduletwo/somemoduletwo.v b/vlib/v/tests/testdata/modules_in_src/modules/somemoduletwo/somemoduletwo.v deleted file mode 100644 index 457675ebc..000000000 --- a/vlib/v/tests/testdata/modules_in_src/modules/somemoduletwo/somemoduletwo.v +++ /dev/null @@ -1,7 +0,0 @@ -module somemoduletwo - -const name = 'somemoduletwo' - -pub fn name() string { - return name -} diff --git a/vlib/v/tests/testdata/modules_in_src/src/main.v b/vlib/v/tests/testdata/modules_in_src/src/main.v deleted file mode 100644 index 0c246529a..000000000 --- a/vlib/v/tests/testdata/modules_in_src/src/main.v +++ /dev/null @@ -1,8 +0,0 @@ -module main - -import somemodule -import somemoduletwo - -fn main() { - println('${somemodule.name()} ${somemoduletwo.name()}') -} diff --git a/vlib/v/tests/testdata/modules_in_src/src/modules/somemodule/somemodule.v b/vlib/v/tests/testdata/modules_in_src/src/modules/somemodule/somemodule.v deleted file mode 100644 index e4c843856..000000000 --- a/vlib/v/tests/testdata/modules_in_src/src/modules/somemodule/somemodule.v +++ /dev/null @@ -1,7 +0,0 @@ -module somemodule - -const name = 'somemodule' - -pub fn name() string { - return name -} diff --git a/vlib/v/tests/testdata/modules_in_src/v.mod b/vlib/v/tests/testdata/modules_in_src/v.mod deleted file mode 100644 index dc334bd0e..000000000 --- a/vlib/v/tests/testdata/modules_in_src/v.mod +++ /dev/null @@ -1,7 +0,0 @@ -Module { - name: 'somemodule' - description: '' - version: '' - license: '' - dependencies: [] -} diff --git a/vlib/v/tests/testdata/sibling_modules_in_src/src/a/a.v b/vlib/v/tests/testdata/sibling_modules_in_src/src/a/a.v deleted file mode 100644 index 7ebff18c4..000000000 --- a/vlib/v/tests/testdata/sibling_modules_in_src/src/a/a.v +++ /dev/null @@ -1,5 +0,0 @@ -module a - -pub fn say_a() string { - return 'Hello from a!' -} diff --git a/vlib/v/tests/testdata/sibling_modules_in_src/src/b/b.v b/vlib/v/tests/testdata/sibling_modules_in_src/src/b/b.v deleted file mode 100644 index 6a6363328..000000000 --- a/vlib/v/tests/testdata/sibling_modules_in_src/src/b/b.v +++ /dev/null @@ -1,7 +0,0 @@ -module b - -import a - -pub fn say_b() string { - return 'b says ${a.say_a()}' -} diff --git a/vlib/v/tests/testdata/sibling_modules_in_src/src/main.v b/vlib/v/tests/testdata/sibling_modules_in_src/src/main.v deleted file mode 100644 index 69c8f8bc1..000000000 --- a/vlib/v/tests/testdata/sibling_modules_in_src/src/main.v +++ /dev/null @@ -1,7 +0,0 @@ -module main - -import b - -fn main() { - println(b.say_b()) -} diff --git a/vlib/v/tests/testdata/sibling_modules_in_src/v.mod b/vlib/v/tests/testdata/sibling_modules_in_src/v.mod deleted file mode 100644 index 2e5c78260..000000000 --- a/vlib/v/tests/testdata/sibling_modules_in_src/v.mod +++ /dev/null @@ -1,3 +0,0 @@ -Module { - name: 'sibling_modules_in_src' -} diff --git a/vlib/v/util/module.v b/vlib/v/util/module.v index c28cb7b84..188b5dc71 100644 --- a/vlib/v/util/module.v +++ b/vlib/v/util/module.v @@ -147,7 +147,7 @@ fn mod_path_to_full_name(pref_ &pref.Preferences, mod string, path string) !stri path_part := path_parts[j] // we reached a vmod folder if path_part in vmod_folders { - mod_full_name := normalize_src_based_mod_name(try_path.split(os.path_separator)[ + mod_full_name := normalize_base_url_mod_name(try_path.split(os.path_separator)[ j + 1..].join('.'), try_path) return mod_full_name } @@ -172,7 +172,7 @@ fn mod_path_to_full_name(pref_ &pref.Preferences, mod string, path string) !stri break } if last_v_mod > -1 { - mod_full_name := normalize_src_based_mod_name(try_path_parts[last_v_mod..].join('.'), + mod_full_name := normalize_base_url_mod_name(try_path_parts[last_v_mod..].join('.'), try_path) return if mod_full_name.len < mod.len { mod } else { mod_full_name } } @@ -188,46 +188,17 @@ fn mod_path_to_full_name(pref_ &pref.Preferences, mod string, path string) !stri rel_mod_path := path.replace(abs_pref_path.all_before_last(os.path_separator) + os.path_separator, '') if rel_mod_path != path { - full_mod_name := - normalize_src_based_mod_name(rel_mod_path.replace(os.path_separator, '.'), path) - return full_mod_name + return normalize_base_url_mod_name(rel_mod_path.replace(os.path_separator, '.'), path) } } return error('module not found') } -fn pref_path_to_source_root(pref_ &pref.Preferences) string { - pref_path_dir := if os.is_dir(pref_.path) { pref_.path } else { os.dir(pref_.path) } - real_pref_path_dir := os.real_path(pref_path_dir) - files := os.ls(real_pref_path_dir) or { return real_pref_path_dir } - if pref_.should_compile_filtered_files(real_pref_path_dir, files).len == 0 { - source_root := source_root_from_vmod_root(real_pref_path_dir) or { - os.join_path(real_pref_path_dir, 'src') - } - if source_root != real_pref_path_dir && os.is_dir(source_root) { - return source_root - } - } - return real_pref_path_dir -} - -fn source_root_from_vmod_root(vmod_root string) !string { - vmod_path := os.join_path(vmod_root, 'v.mod') - if !os.is_file(vmod_path) { - return error('module not found') - } - manifest := vmod.from_file(vmod_path) or { return error('module not found') } - return manifest.source_root(vmod_root) -} - -fn configured_base_parts(manifest vmod.Manifest) []string { - if manifest.base_url == '' { - return []string{} - } - return os.norm_path(manifest.base_url).split(os.path_separator).filter(it.len > 0 && it != '.') -} - -fn normalize_src_based_mod_name(mod_full_name string, path string) string { +// normalize_base_url_mod_name strips the `base_url` prefix from `mod_full_name` +// when the module lives in a folder configured via v.mod's `base_url`. Without +// this, a module rooted at `/source/feature` would be named `pkg.source.feature` +// instead of `pkg.feature`. The implicit `src/` fallback is intentionally gone. +fn normalize_base_url_mod_name(mod_full_name string, path string) string { real_path := os.real_path(path) mut mcache := vmod.get_cache() vmod_file_location := mcache.get_by_folder(real_path) @@ -238,17 +209,17 @@ fn normalize_src_based_mod_name(mod_full_name string, path string) string { if !real_path.starts_with(vmod_prefix) { return mod_full_name } - rel_path := real_path.all_after(vmod_prefix) - rel_parts := rel_path.split(os.path_separator) - mut base_parts := []string{} - manifest := vmod.from_file(vmod_file_location.vmod_file) or { vmod.Manifest{} } - base_parts = configured_base_parts(manifest) + manifest := vmod.from_file(vmod_file_location.vmod_file) or { return mod_full_name } + if manifest.base_url == '' { + return mod_full_name + } + base_parts := os.norm_path(manifest.base_url).split(os.path_separator).filter(it.len > 0 + && it != '.') if base_parts.len == 0 { - if rel_parts.len == 0 || rel_parts[0] != 'src' { - return mod_full_name - } - base_parts = ['src'] + return mod_full_name } + rel_path := real_path.all_after(vmod_prefix) + rel_parts := rel_path.split(os.path_separator) if rel_parts.len < base_parts.len || rel_parts[..base_parts.len] != base_parts { return mod_full_name } diff --git a/vlib/v/vmod/vmod.v b/vlib/v/vmod/vmod.v index 670dbd348..328cdd678 100644 --- a/vlib/v/vmod/vmod.v +++ b/vlib/v/vmod/vmod.v @@ -21,13 +21,14 @@ pub fn (manifest Manifest) resolved_base_url(vmod_root string) string { } // source_root returns the folder where sources are looked up under a `v.mod`. -// When `base_url` is missing, it preserves the existing `src/` fallback. +// When `base_url` is set, it points at that folder; otherwise it falls back to +// the folder containing `v.mod`. The previous implicit `src/` fallback is gone. pub fn (manifest Manifest) source_root(vmod_root string) string { base_url := manifest.resolved_base_url(vmod_root) if base_url != '' { return base_url } - return os.norm_path(os.join_path(vmod_root, 'src')) + return os.norm_path(vmod_root) } // This file provides a caching mechanism for seeking quickly whether a -- 2.39.5