mirror of
https://github.com/vlang/v.git
synced 2025-09-17 11:26:17 -04:00
tools.vpm: extend recursive dependency fix for module installation (#20015)
This commit is contained in:
parent
920be09c7e
commit
50f3ac4968
@ -1,6 +1,7 @@
|
||||
// vtest retry: 3
|
||||
import os
|
||||
import v.vmod
|
||||
import time
|
||||
|
||||
const v = os.quoted_path(@VEXE)
|
||||
const test_path = os.join_path(os.vtmp_dir(), 'vpm_dependency_test')
|
||||
@ -72,3 +73,11 @@ fn test_resolve_external_dependencies_during_module_install() {
|
||||
assert get_mod_name(os.join_path(test_path, 'webview', 'v.mod')) == 'webview'
|
||||
assert get_mod_name(os.join_path(test_path, 'miniaudio', 'v.mod')) == 'miniaudio'
|
||||
}
|
||||
|
||||
fn test_install_with_recursive_dependencies() {
|
||||
spawn fn () {
|
||||
time.sleep(2 * time.minute)
|
||||
exit(1)
|
||||
}()
|
||||
os.execute_or_exit('${v} install https://gitlab.com/tobealive/a')
|
||||
}
|
||||
|
@ -18,134 +18,138 @@ mut:
|
||||
manifest vmod.Manifest
|
||||
}
|
||||
|
||||
struct Parser {
|
||||
mut:
|
||||
modules map[string]Module
|
||||
checked_settings_vcs bool
|
||||
is_git_setting bool
|
||||
errors int
|
||||
}
|
||||
|
||||
fn parse_query(query []string) []Module {
|
||||
mut modules := []Module{}
|
||||
mut dependencies := map[string]bool{}
|
||||
mut checked_settings_vcs := false
|
||||
mut errors := 0
|
||||
is_git_setting := settings.vcs.cmd == 'git'
|
||||
for m in query {
|
||||
ident, version := m.rsplit_once('@') or { m, '' }
|
||||
println('Scanning `${ident}`...')
|
||||
is_http := if ident.starts_with('http://') {
|
||||
vpm_warn('installing `${ident}` via http.',
|
||||
details: 'Support for `http` is deprecated, use `https` to ensure future compatibility.'
|
||||
)
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
mut mod := if is_http || ident.starts_with('https://') {
|
||||
// External module. The idenifier is an URL.
|
||||
publisher, name := get_ident_from_url(ident) or {
|
||||
vpm_error(err.msg())
|
||||
errors++
|
||||
continue
|
||||
}
|
||||
// Verify VCS. Only needed once for external modules.
|
||||
if !checked_settings_vcs {
|
||||
checked_settings_vcs = true
|
||||
settings.vcs.is_executable() or {
|
||||
vpm_error(err.msg())
|
||||
exit(1)
|
||||
}
|
||||
}
|
||||
// Fetch manifest.
|
||||
manifest := fetch_manifest(name, ident, version, is_git_setting) or {
|
||||
vpm_error('failed to find `v.mod` for `${ident}${at_version(version)}`.',
|
||||
details: err.msg()
|
||||
)
|
||||
errors++
|
||||
continue
|
||||
}
|
||||
// Resolve path.
|
||||
mod_path := normalize_mod_path(os.join_path(if is_http { publisher } else { '' },
|
||||
manifest.name))
|
||||
Module{
|
||||
name: manifest.name
|
||||
url: ident
|
||||
install_path: os.real_path(os.join_path(settings.vmodules_path, mod_path))
|
||||
is_external: true
|
||||
manifest: manifest
|
||||
}
|
||||
} else {
|
||||
// VPM registered module.
|
||||
info := get_mod_vpm_info(ident) or {
|
||||
vpm_error('failed to retrieve metadata for `${ident}`.', details: err.msg())
|
||||
errors++
|
||||
continue
|
||||
}
|
||||
// Verify VCS.
|
||||
mut is_git_module := true
|
||||
vcs := if info.vcs != '' {
|
||||
info_vcs := supported_vcs[info.vcs] or {
|
||||
vpm_error('skipping `${info.name}`, since it uses an unsupported version control system `${info.vcs}`.')
|
||||
errors++
|
||||
continue
|
||||
}
|
||||
is_git_module = info.vcs == 'git'
|
||||
if !is_git_module && version != '' {
|
||||
vpm_error('skipping `${info.name}`, version installs are currently only supported for projects using `git`.')
|
||||
errors++
|
||||
continue
|
||||
}
|
||||
info_vcs
|
||||
} else {
|
||||
supported_vcs['git']
|
||||
}
|
||||
vcs.is_executable() or {
|
||||
vpm_error(err.msg())
|
||||
errors++
|
||||
continue
|
||||
}
|
||||
// Fetch manifest.
|
||||
manifest := fetch_manifest(info.name, info.url, version, is_git_module) or {
|
||||
// Add link with issue template requesting to add a manifest.
|
||||
mut details := ''
|
||||
if resp := http.head('${info.url}/issues/new') {
|
||||
if resp.status_code == 200 {
|
||||
issue_tmpl_url := '${info.url}/issues/new?title=Missing%20Manifest&body=${info.name}%20is%20missing%20a%20manifest,%20please%20consider%20adding%20a%20v.mod%20file%20with%20the%20modules%20metadata.'
|
||||
details = 'Help to ensure future-compatibility by adding a `v.mod` file or opening an issue at:\n`${issue_tmpl_url}`'
|
||||
}
|
||||
}
|
||||
vpm_warn('`${info.name}` is missing a manifest file.', details: details)
|
||||
vpm_log(@FILE_LINE, @FN, 'vpm manifest detection error: ${err}')
|
||||
vmod.Manifest{}
|
||||
}
|
||||
// Resolve path.
|
||||
mod_path := normalize_mod_path(info.name.replace('.', os.path_separator))
|
||||
Module{
|
||||
name: info.name
|
||||
url: info.url
|
||||
vcs: vcs
|
||||
install_path: os.real_path(os.join_path(settings.vmodules_path, mod_path))
|
||||
manifest: manifest
|
||||
}
|
||||
}
|
||||
mod.install_path_fmted = fmt_mod_path(mod.install_path)
|
||||
mod.version = version
|
||||
mod.get_installed()
|
||||
modules << mod
|
||||
if mod.manifest.dependencies.len > 0 {
|
||||
verbose_println('Found ${mod.manifest.dependencies.len} dependencies for `${mod.name}`: ${mod.manifest.dependencies}.')
|
||||
for d in mod.manifest.dependencies {
|
||||
if !dependencies[d] {
|
||||
dependencies[d] = true
|
||||
}
|
||||
}
|
||||
}
|
||||
mut p := Parser{
|
||||
is_git_setting: settings.vcs.cmd == 'git'
|
||||
}
|
||||
if errors > 0 && errors == query.len {
|
||||
for m in query {
|
||||
p.parse_module(m)
|
||||
}
|
||||
if p.errors > 0 && p.errors == query.len {
|
||||
exit(1)
|
||||
}
|
||||
if dependencies.len > 0 {
|
||||
vpm_log(@FILE_LINE, @FN, 'dependencies: ${dependencies}')
|
||||
deps := dependencies.keys().filter(it !in query)
|
||||
vpm_log(@FILE_LINE, @FN, 'dependencies filtered: ${deps}')
|
||||
println('Scanning dependencies...')
|
||||
modules << parse_query(deps)
|
||||
return p.modules.values()
|
||||
}
|
||||
|
||||
fn (mut p Parser) parse_module(m string) {
|
||||
if m in p.modules {
|
||||
return
|
||||
}
|
||||
ident, version := m.rsplit_once('@') or { m, '' }
|
||||
println('Scanning `${ident}`...')
|
||||
is_http := if ident.starts_with('http://') {
|
||||
vpm_warn('installing `${ident}` via http.',
|
||||
details: 'Support for `http` is deprecated, use `https` to ensure future compatibility.'
|
||||
)
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
mut mod := if is_http || ident.starts_with('https://') {
|
||||
// External module. The idenifier is an URL.
|
||||
publisher, name := get_ident_from_url(ident) or {
|
||||
vpm_error(err.msg())
|
||||
p.errors++
|
||||
return
|
||||
}
|
||||
// Verify VCS. Only needed once for external modules.
|
||||
if !p.checked_settings_vcs {
|
||||
p.checked_settings_vcs = true
|
||||
settings.vcs.is_executable() or {
|
||||
vpm_error(err.msg())
|
||||
exit(1)
|
||||
}
|
||||
}
|
||||
// Fetch manifest.
|
||||
manifest := fetch_manifest(name, ident, version, p.is_git_setting) or {
|
||||
vpm_error('failed to find `v.mod` for `${ident}${at_version(version)}`.',
|
||||
details: err.msg()
|
||||
)
|
||||
p.errors++
|
||||
return
|
||||
}
|
||||
// Resolve path.
|
||||
mod_path := normalize_mod_path(os.join_path(if is_http { publisher } else { '' },
|
||||
manifest.name))
|
||||
Module{
|
||||
name: manifest.name
|
||||
url: ident
|
||||
install_path: os.real_path(os.join_path(settings.vmodules_path, mod_path))
|
||||
is_external: true
|
||||
manifest: manifest
|
||||
}
|
||||
} else {
|
||||
// VPM registered module.
|
||||
info := get_mod_vpm_info(ident) or {
|
||||
vpm_error('failed to retrieve metadata for `${ident}`.', details: err.msg())
|
||||
p.errors++
|
||||
return
|
||||
}
|
||||
// Verify VCS.
|
||||
mut is_git_module := true
|
||||
vcs := if info.vcs != '' {
|
||||
info_vcs := supported_vcs[info.vcs] or {
|
||||
vpm_error('skipping `${info.name}`, since it uses an unsupported version control system `${info.vcs}`.')
|
||||
p.errors++
|
||||
return
|
||||
}
|
||||
is_git_module = info.vcs == 'git'
|
||||
if !is_git_module && version != '' {
|
||||
vpm_error('skipping `${info.name}`, version installs are currently only supported for projects using `git`.')
|
||||
p.errors++
|
||||
return
|
||||
}
|
||||
info_vcs
|
||||
} else {
|
||||
supported_vcs['git']
|
||||
}
|
||||
vcs.is_executable() or {
|
||||
vpm_error(err.msg())
|
||||
p.errors++
|
||||
return
|
||||
}
|
||||
// Fetch manifest.
|
||||
manifest := fetch_manifest(info.name, info.url, version, is_git_module) or {
|
||||
// Add link with issue template requesting to add a manifest.
|
||||
mut details := ''
|
||||
if resp := http.head('${info.url}/issues/new') {
|
||||
if resp.status_code == 200 {
|
||||
issue_tmpl_url := '${info.url}/issues/new?title=Missing%20Manifest&body=${info.name}%20is%20missing%20a%20manifest,%20please%20consider%20adding%20a%20v.mod%20file%20with%20the%20modules%20metadata.'
|
||||
details = 'Help to ensure future-compatibility by adding a `v.mod` file or opening an issue at:\n`${issue_tmpl_url}`'
|
||||
}
|
||||
}
|
||||
vpm_warn('`${info.name}` is missing a manifest file.', details: details)
|
||||
vpm_log(@FILE_LINE, @FN, 'vpm manifest detection error: ${err}')
|
||||
vmod.Manifest{}
|
||||
}
|
||||
// Resolve path.
|
||||
mod_path := normalize_mod_path(info.name.replace('.', os.path_separator))
|
||||
Module{
|
||||
name: info.name
|
||||
url: info.url
|
||||
vcs: vcs
|
||||
install_path: os.real_path(os.join_path(settings.vmodules_path, mod_path))
|
||||
manifest: manifest
|
||||
}
|
||||
}
|
||||
mod.install_path_fmted = fmt_mod_path(mod.install_path)
|
||||
mod.version = version
|
||||
mod.get_installed()
|
||||
p.modules[m] = mod
|
||||
if mod.manifest.dependencies.len > 0 {
|
||||
verbose_println('Found ${mod.manifest.dependencies.len} dependencies for `${mod.name}`: ${mod.manifest.dependencies}.')
|
||||
for d in mod.manifest.dependencies {
|
||||
p.parse_module(d)
|
||||
}
|
||||
}
|
||||
return modules
|
||||
}
|
||||
|
||||
// TODO: add unit test
|
||||
|
Loading…
x
Reference in New Issue
Block a user