v / vlib / v2 / pref / module.v
117 lines · 110 sloc · 3.26 KB · b831b0eec9b5b2756784b5dabf3808d47d6a39ae
Raw
1// Copyright (c) 2020-2024 Joe Conigliaro. All rights reserved.
2// Use of this source code is governed by an MIT license
3// that can be found in the LICENSE file.
4module pref
5
6import os
7
8fn (p &Preferences) effective_vroot() string {
9 if p.vroot.len > 0 {
10 return p.vroot
11 }
12 return os.getwd()
13}
14
15pub fn (p &Preferences) get_vlib_module_path(mod string) string {
16 mod_path := mod.replace('.', os.path_separator)
17 return module_path_join(module_path_join(p.effective_vroot(), 'vlib'), mod_path)
18}
19
20fn module_path_join(base string, name string) string {
21 if base.len == 0 {
22 return name
23 }
24 if name.len == 0 {
25 return base
26 }
27 last := base[base.len - 1]
28 if last == `/` || last == `\\` {
29 return base + name
30 }
31 return base + os.path_separator + name
32}
33
34fn module_root_for_file(path string) string {
35 mut dir := os.dir(path)
36 for dir.len > 0 {
37 if os.exists(module_path_join(dir, 'v.mod')) {
38 return dir
39 }
40 parent := os.dir(dir)
41 if parent == dir {
42 break
43 }
44 dir = parent
45 }
46 return ''
47}
48
49fn find_module_path_in_parent_dirs(mod_path string, importing_file_path string) ?string {
50 mut dir := os.dir(importing_file_path)
51 for dir.len > 0 {
52 parent_relative_path := module_path_join(dir, mod_path)
53 if dir_exists(parent_relative_path) {
54 return parent_relative_path
55 }
56 parent := os.dir(dir)
57 if parent == dir {
58 break
59 }
60 dir = parent
61 }
62 return none
63}
64
65// check for relative and then vlib
66pub fn (p &Preferences) get_module_path(mod string, importing_file_path string) string {
67 mod_path := mod.replace('.', os.path_separator)
68 vroot := p.effective_vroot()
69 // relative to file importing it
70 relative_path := module_path_join(os.dir(importing_file_path), mod_path)
71 if dir_exists(relative_path) {
72 return relative_path
73 }
74 module_root := module_root_for_file(importing_file_path)
75 if module_root != '' {
76 root_relative_path := module_path_join(module_root, mod_path)
77 if dir_exists(root_relative_path) {
78 return root_relative_path
79 }
80 }
81 if parent_relative_path := find_module_path_in_parent_dirs(mod_path, importing_file_path) {
82 return parent_relative_path
83 }
84 cwd_relative_path := module_path_join(os.getwd(), mod_path)
85 if dir_exists(cwd_relative_path) {
86 return cwd_relative_path
87 }
88 // TODO: is this the best order?
89 // vlib
90 vlib_path := module_path_join(module_path_join(vroot, 'vlib'), mod_path)
91 if dir_exists(vlib_path) {
92 return vlib_path
93 }
94 // V1 compiler modules under vlib/v use legacy bare sibling imports
95 // (`import token` from vlib/v/checker, with sources in vlib/v/token).
96 vlib_v_path := module_path_join(module_path_join(vroot, 'vlib'), 'v')
97 normalized_importer := importing_file_path.replace('\\', '/')
98 normalized_vlib_v := vlib_v_path.replace('\\', '/')
99 if normalized_importer.starts_with(normalized_vlib_v + '/')
100 || normalized_importer.starts_with('vlib/v/') {
101 legacy_v_path := module_path_join(vlib_v_path, mod_path)
102 if dir_exists(legacy_v_path) {
103 return legacy_v_path
104 }
105 }
106 // ~/.vmodules
107 vmodules_path := module_path_join(p.vmodules_path, mod_path)
108 if dir_exists(vmodules_path) {
109 // V convention: if a module dir has a src/ subdirectory, use that
110 src_path := module_path_join(vmodules_path, 'src')
111 if dir_exists(src_path) {
112 return src_path
113 }
114 return vmodules_path
115 }
116 panic('Preferences.get_module_path: cannot find module path for `${mod}`')
117}
118