Skip to content

Commit 10160c0

Browse files
authored
tools: add parse_query to vpm (#19814)
1 parent 2b21dea commit 10160c0

File tree

5 files changed

+209
-189
lines changed

5 files changed

+209
-189
lines changed

cmd/tools/vpm/common.v

Lines changed: 93 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -9,40 +9,95 @@ import net.urllib
99
import term
1010
import log
1111

12-
struct Mod {
13-
id int
12+
struct Module {
13+
mut:
14+
// Fields that can be populated via VPM API.
15+
name string
16+
url string
17+
vcs string
18+
// Fields based on input / environment.
19+
version string // specifies the requested version.
20+
install_path string
21+
is_installed bool
22+
installed_version string
23+
}
24+
25+
struct ModuleVpmInfo {
26+
// id int
1427
name string
1528
url string
16-
nr_downloads int
1729
vcs string
30+
nr_downloads int
1831
}
1932

20-
pub struct ModDateInfo {
33+
pub struct ModuleDateInfo {
2134
name string
2235
mut:
2336
outdated bool
2437
exec_err bool
2538
}
2639

27-
struct ModNameInfo {
28-
mut:
29-
mname string // The-user.The-mod , *never* The-user.The-mod.git
30-
mname_normalised string // the_user.the_mod
31-
mname_as_path string // the_user/the_mod
32-
final_module_path string // ~/.vmodules/the_user/the_mod
33-
}
34-
3540
[params]
3641
struct ErrorOptions {
3742
details string
3843
verbose bool // is used to only output the error message if the verbose setting is enabled.
3944
}
4045

41-
fn get_mod_date_info(mut pp pool.PoolProcessor, idx int, wid int) &ModDateInfo {
42-
mut result := &ModDateInfo{
46+
fn parse_query(query []string) ([]Module, []Module) {
47+
mut vpm_modules, mut extended_modules := []Module{}, []Module{}
48+
mut errors := 0
49+
for m in query {
50+
ident, version := m.rsplit_once('@') or { m, '' }
51+
mut is_external := false
52+
mut mod := if ident.starts_with('https://') {
53+
is_external = true
54+
name := get_name_from_url(ident) or {
55+
vpm_error(err.msg())
56+
errors++
57+
continue
58+
}
59+
Module{
60+
name: name
61+
url: ident
62+
install_path: os.real_path(os.join_path(settings.vmodules_path, name))
63+
}
64+
} else {
65+
info := get_mod_vpm_info(ident) or {
66+
vpm_error('failed to retrieve metadata for `${ident}`.', details: err.msg())
67+
errors++
68+
continue
69+
}
70+
name_normalized := info.name.replace('-', '_').to_lower()
71+
name_as_path := name_normalized.replace('.', os.path_separator)
72+
Module{
73+
name: info.name
74+
url: info.url
75+
vcs: info.vcs
76+
install_path: os.real_path(os.join_path(settings.vmodules_path, name_as_path))
77+
}
78+
}
79+
mod.version = version
80+
if v := os.execute_opt('git ls-remote --tags ${mod.install_path}') {
81+
mod.is_installed = true
82+
mod.installed_version = v.output.all_after_last('/').trim_space()
83+
}
84+
if is_external {
85+
extended_modules << mod
86+
} else {
87+
vpm_modules << mod
88+
}
89+
}
90+
if errors > 0 && errors == query.len {
91+
exit(1)
92+
}
93+
return vpm_modules, extended_modules
94+
}
95+
96+
fn get_mod_date_info(mut pp pool.PoolProcessor, idx int, wid int) &ModuleDateInfo {
97+
mut result := &ModuleDateInfo{
4398
name: pp.get_item[string](idx)
4499
}
45-
final_module_path := valid_final_path_of_existing_module(result.name) or { return result }
100+
final_module_path := get_path_of_existing_module(result.name) or { return result }
46101
vcs := vcs_used_in_dir(final_module_path) or { return result }
47102
is_hg := vcs.cmd == 'hg'
48103
mut outputs := []string{}
@@ -68,26 +123,14 @@ fn get_mod_date_info(mut pp pool.PoolProcessor, idx int, wid int) &ModDateInfo {
68123
return result
69124
}
70125

71-
fn get_mod_name_info(mod_name string) ModNameInfo {
72-
mut info := ModNameInfo{}
73-
info.mname = if mod_name.ends_with('.git') { mod_name.replace('.git', '') } else { mod_name }
74-
info.mname_normalised = info.mname.replace('-', '_').to_lower()
75-
info.mname_as_path = info.mname_normalised.replace('.', os.path_separator)
76-
info.final_module_path = os.real_path(os.join_path(settings.vmodules_path, info.mname_as_path))
77-
return info
78-
}
79-
80-
fn get_module_meta_info(name string) !Mod {
81-
if mod := get_mod_by_url(name) {
82-
return mod
83-
}
126+
fn get_mod_vpm_info(name string) !ModuleVpmInfo {
84127
if name.len < 2 || (!name[0].is_digit() && !name[0].is_letter()) {
85128
return error('invalid module name `${name}`.')
86129
}
87130
mut errors := []string{}
88131
for server_url in vpm_server_urls {
89132
modurl := server_url + '/api/packages/${name}'
90-
verbose_println('Retrieving module metadata from `${modurl}` ...')
133+
verbose_println('Retrieving metadata for `${name}` from `${modurl}`...')
91134
r := http.get(modurl) or {
92135
errors << 'Http server did not respond to our request for `${modurl}`.'
93136
errors << 'Error details: ${err}'
@@ -104,41 +147,39 @@ fn get_module_meta_info(name string) !Mod {
104147
s := r.body
105148
if s.len > 0 && s[0] != `{` {
106149
errors << 'Invalid json data'
107-
errors << s.trim_space().limit(100) + ' ...'
150+
errors << s.trim_space().limit(100) + '...'
108151
continue
109152
}
110-
mod := json.decode(Mod, s) or {
153+
mod := json.decode(ModuleVpmInfo, s) or {
111154
errors << 'Skipping module `${name}`, since its information is not in json format.'
112155
continue
113156
}
114157
if '' == mod.url || '' == mod.name {
115158
errors << 'Skipping module `${name}`, since it is missing name or url information.'
116159
continue
117160
}
161+
vpm_log(@FILE_LINE, @FN, 'name: ${name}; mod: ${mod}')
118162
return mod
119163
}
120164
return error(errors.join_lines())
121165
}
122166

123-
fn get_mod_by_url(name string) !Mod {
124-
if purl := urllib.parse(name) {
125-
verbose_println('purl: ${purl}')
126-
mod := Mod{
127-
name: purl.path.trim_left('/').trim_right('/').replace('/', '.')
128-
url: name
129-
}
130-
verbose_println(mod.str())
131-
return mod
167+
fn get_name_from_url(raw_url string) !string {
168+
url := urllib.parse(raw_url) or { return error('failed to parse module URL `${raw_url}`.') }
169+
owner, mut name := url.path.trim_left('/').rsplit_once('/') or {
170+
return error('failed to retrieve module name for `${url}`.')
132171
}
133-
return error('invalid url: ${name}')
172+
vpm_log(@FILE_LINE, @FN, 'raw_url: ${raw_url}; owner: ${owner}; name: ${name}')
173+
name = if name.ends_with('.git') { name.replace('.git', '') } else { name }
174+
return name.replace('-', '_').to_lower()
134175
}
135176

136177
fn get_outdated() ![]string {
137178
module_names := get_installed_modules()
138179
mut outdated := []string{}
139180
mut pp := pool.new_pool_processor(callback: get_mod_date_info)
140181
pp.work_on_items(module_names)
141-
for res in pp.get_results[ModDateInfo]() {
182+
for res in pp.get_results[ModuleDateInfo]() {
142183
if res.exec_err {
143184
return error('failed to check the latest commits for `${res.name}`.')
144185
}
@@ -297,14 +338,6 @@ fn resolve_dependencies(name string, module_path string, module_names []string)
297338
}
298339
}
299340

300-
fn url_to_module_name(modulename string) string {
301-
mut res := if mod := get_mod_by_url(modulename) { mod.name } else { modulename }
302-
if res.ends_with('.git') {
303-
res = res.replace('.git', '')
304-
}
305-
return res
306-
}
307-
308341
fn vcs_used_in_dir(dir string) ?VCS {
309342
for vcs in supported_vcs.values() {
310343
if os.is_dir(os.real_path(os.join_path(dir, vcs.dir))) {
@@ -314,22 +347,22 @@ fn vcs_used_in_dir(dir string) ?VCS {
314347
return none
315348
}
316349

317-
fn valid_final_path_of_existing_module(modulename string) ?string {
318-
name := if mod := get_mod_by_url(modulename) { mod.name } else { modulename }
319-
minfo := get_mod_name_info(name)
320-
if !os.exists(minfo.final_module_path) {
321-
vpm_error('failed to find a module with name `${minfo.mname_normalised}` at `${minfo.final_module_path}`')
350+
fn get_path_of_existing_module(mod_name string) ?string {
351+
name := get_name_from_url(mod_name) or { mod_name.replace('-', '_').to_lower() }
352+
path := os.real_path(os.join_path(settings.vmodules_path, name.replace('.', os.path_separator)))
353+
if !os.exists(path) {
354+
vpm_error('failed to find `${name}` at `${path}`.')
322355
return none
323356
}
324-
if !os.is_dir(minfo.final_module_path) {
325-
vpm_error('skipping `${minfo.final_module_path}`, since it is not a directory.')
357+
if !os.is_dir(path) {
358+
vpm_error('skipping `${path}`, since it is not a directory.')
326359
return none
327360
}
328-
vcs_used_in_dir(minfo.final_module_path) or {
329-
vpm_error('skipping `${minfo.final_module_path}`, since it uses an unsupported version control system.')
361+
vcs_used_in_dir(path) or {
362+
vpm_error('skipping `${path}`, since it uses an unsupported version control system.')
330363
return none
331364
}
332-
return minfo.final_module_path
365+
return path
333366
}
334367

335368
fn verbose_println(s string) {

0 commit comments

Comments
 (0)