Skip to content

Commit 78d51d3

Browse files
committed
vpm: warn when a module name is normalized into a different import path
1 parent 9142d68 commit 78d51d3

4 files changed

Lines changed: 52 additions & 5 deletions

File tree

cmd/tools/vpm/common.v

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,16 @@ fn normalize_mod_path(path string) string {
230230
return path.replace('-', '_').to_lower()
231231
}
232232

233+
// Derive the import path of an installed module from its location relative to
234+
// `vmodules`. E.g. `<vmodules>/spytheman/vtray` -> `spytheman.vtray`.
235+
// Normalize both sides via `real_path` so macOS's `/tmp` -> `/private/tmp`
236+
// resolution doesn't leave the prefix unstripped.
237+
fn import_path_of(install_path string) string {
238+
vmodules_real := os.real_path(settings.vmodules_path)
239+
rel_install_path := install_path.trim_string_left(vmodules_real).trim_left(os.path_separator)
240+
return rel_install_path.replace(os.path_separator, '.')
241+
}
242+
233243
fn get_all_modules_for_search() []string {
234244
working_server_url := get_working_server_url()
235245
verbose_println_more(@FILE_LINE, @FN, 'working_server_url: ${working_server_url}')

cmd/tools/vpm/install.v

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,12 +94,26 @@ fn install_modules(modules []Module, selected_server_url string) {
9494
}
9595
}
9696
println('Installed `${m.name}` in ${m.install_path_fmted} .')
97+
m.warn_on_normalized_name()
9798
}
9899
if errors > 0 {
99100
exit(1)
100101
}
101102
}
102103

104+
// Module names may contain characters that are not valid in V import paths, e.g. `-`.
105+
// Those are normalized away when the module is placed into `vmodules`, so point out
106+
// the resulting import path instead of leaving the mismatch for the compiler to report.
107+
fn (m Module) warn_on_normalized_name() {
108+
import_path := import_path_of(m.install_path)
109+
if import_path == m.name {
110+
return
111+
}
112+
vpm_warn('`${m.name}` is not a valid V import path, it was installed as `${import_path}`.',
113+
details: 'Use `import ${import_path}` to import it.\nConsider renaming the `name` field in the `v.mod` of the module.'
114+
)
115+
}
116+
103117
fn (m Module) install() InstallResult {
104118
defer {
105119
os.rmdir_all(m.tmp_path) or {}

cmd/tools/vpm/install_local_test.v

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,33 @@ fn test_update_and_remove_with_capitalized_ident() {
114114
assert !os.exists(publisher_dir)
115115
}
116116

117+
// A module named e.g. `my-mod` is installed as `my_mod`, since `-` is not valid
118+
// in a V import path. Make sure the mismatch is reported with the resulting
119+
// import path, instead of leaving users to guess it.
120+
fn test_install_warns_about_normalized_module_name() {
121+
vmodules_path := os.join_path(test_path, 'vmodules_normalized_name')
122+
test_utils.set_test_env(vmodules_path)
123+
repo_path := os.join_path(test_path, 'hyphenated_repo')
124+
create_local_git_module(repo_path, 'my-mod')
125+
126+
res := cmd_ok(@LOCATION, '${vexe} install ${os.quoted_path(repo_path)}')
127+
assert res.output.contains('`my-mod` is not a valid V import path, it was installed as `my_mod`.'), res.output
128+
assert res.output.contains('Use `import my_mod` to import it.'), res.output
129+
assert os.exists(os.join_path(vmodules_path, 'my_mod', 'v.mod'))
130+
}
131+
132+
// Counterpart of the test above: a module name that is already a valid import
133+
// path must not trigger the warning.
134+
fn test_install_does_not_warn_about_valid_module_name() {
135+
vmodules_path := os.join_path(test_path, 'vmodules_valid_name')
136+
test_utils.set_test_env(vmodules_path)
137+
repo_path := os.join_path(test_path, 'valid_name_repo')
138+
create_local_git_module(repo_path, 'my_mod')
139+
140+
res := cmd_ok(@LOCATION, '${vexe} install ${os.quoted_path(repo_path)}')
141+
assert !res.output.contains('is not a valid V import path'), res.output
142+
}
143+
117144
fn create_local_git_module(repo_path string, module_name string) {
118145
os.mkdir_all(repo_path) or { panic(err) }
119146
os.write_file(os.join_path(repo_path, 'v.mod'),

cmd/tools/vpm/update.v

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -44,11 +44,7 @@ fn update_module(mut pp pool.PoolProcessor, idx int, _wid int) &UpdateResult {
4444
// Derive the canonical module name from the install path so URL-based
4545
// updates report the registered name (e.g. `spytheman.vtray` for
4646
// `<vmodules>/spytheman/vtray`) instead of the bare URL-derived `vtray`.
47-
// Normalize both sides via real_path so macOS's `/tmp` -> `/private/tmp`
48-
// resolution doesn't leave the prefix unstripped.
49-
vmodules_real := os.real_path(settings.vmodules_path)
50-
rel_install_path := install_path.trim_string_left(vmodules_real).trim_left(os.path_separator)
51-
name := rel_install_path.replace(os.path_separator, '.')
47+
name := import_path_of(install_path)
5248
vcs := vcs_used_in_dir(install_path) or {
5349
vpm_error('failed to find version control system for `${name}`.', verbose: true)
5450
return &UpdateResult{}

0 commit comments

Comments
 (0)