2023-03-28 23:55:57 +03:00
|
|
|
|
// Copyright (c) 2019-2023 Alexander Medvednikov. All rights reserved.
|
2020-09-15 19:35:00 +03:00
|
|
|
|
// Use of this source code is governed by an MIT license
|
|
|
|
|
// that can be found in the LICENSE file.
|
tools/vget => tools/v , search, install, etc
* compiler: rename vget to tools/vpm, implement draft support for v vpm search, v vpm update, v vpm install, v vpm remove, v vpm help .
* compiler: use "v pm" instead of "v vpm" to reduce the redundancy of typing, as suggested by slapden
* Use 'v install modulename', 'v search keywords', 'v update modulename', 'v remove modulename' instead of the longer 'v pm install modulename' etc.
2019-11-01 15:19:04 +03:00
|
|
|
|
module main
|
|
|
|
|
|
2020-04-26 09:32:05 +03:00
|
|
|
|
import os
|
2022-06-21 12:58:22 +03:00
|
|
|
|
import rand
|
2020-04-26 09:32:05 +03:00
|
|
|
|
import os.cmdline
|
|
|
|
|
import net.http
|
2022-01-15 15:35:37 +03:00
|
|
|
|
import net.urllib
|
2020-04-26 09:32:05 +03:00
|
|
|
|
import json
|
2023-02-01 12:18:23 +03:00
|
|
|
|
import v.help
|
2020-05-24 15:25:29 +03:00
|
|
|
|
import v.vmod
|
tools/vget => tools/v , search, install, etc
* compiler: rename vget to tools/vpm, implement draft support for v vpm search, v vpm update, v vpm install, v vpm remove, v vpm help .
* compiler: use "v pm" instead of "v vpm" to reduce the redundancy of typing, as suggested by slapden
* Use 'v install modulename', 'v search keywords', 'v update modulename', 'v remove modulename' instead of the longer 'v pm install modulename' etc.
2019-11-01 15:19:04 +03:00
|
|
|
|
|
|
|
|
|
const (
|
2022-06-21 12:27:27 +03:00
|
|
|
|
default_vpm_server_urls = ['https://vpm.vlang.io', 'https://vpm.url4e.com']
|
2022-06-21 12:58:22 +03:00
|
|
|
|
vpm_server_urls = rand.shuffle_clone(default_vpm_server_urls) or { [] } // ensure that all queries are distributed fairly
|
2021-04-29 02:17:37 +03:00
|
|
|
|
valid_vpm_commands = ['help', 'search', 'install', 'update', 'upgrade', 'outdated',
|
2021-05-24 15:17:57 +03:00
|
|
|
|
'list', 'remove', 'show']
|
2021-04-29 02:17:37 +03:00
|
|
|
|
excluded_dirs = ['cache', 'vlib']
|
|
|
|
|
supported_vcs_systems = ['git', 'hg']
|
|
|
|
|
supported_vcs_folders = ['.git', '.hg']
|
2021-08-04 12:44:41 +03:00
|
|
|
|
supported_vcs_update_cmds = {
|
2022-08-22 11:23:32 +03:00
|
|
|
|
'git': 'git pull --recurse-submodules' // pulling with `--depth=1` leads to conflicts, when the upstream is more than 1 commit newer
|
2021-01-26 17:43:10 +03:00
|
|
|
|
'hg': 'hg pull --update'
|
2020-01-04 00:07:58 +03:00
|
|
|
|
}
|
2021-08-04 12:44:41 +03:00
|
|
|
|
supported_vcs_install_cmds = {
|
2022-08-22 11:23:32 +03:00
|
|
|
|
'git': 'git clone --depth=1 --recursive --shallow-submodules'
|
2021-01-26 17:43:10 +03:00
|
|
|
|
'hg': 'hg clone'
|
2020-01-04 00:07:58 +03:00
|
|
|
|
}
|
2021-08-04 12:44:41 +03:00
|
|
|
|
supported_vcs_outdated_steps = {
|
2022-11-10 15:05:34 +03:00
|
|
|
|
'git': ['git fetch', 'git rev-parse @', 'git rev-parse @{u}']
|
2021-01-26 17:43:10 +03:00
|
|
|
|
'hg': ['hg incoming']
|
2020-07-15 22:55:07 +03:00
|
|
|
|
}
|
2022-01-01 16:40:19 +03:00
|
|
|
|
supported_vcs_version_cmds = {
|
|
|
|
|
'git': 'git version'
|
|
|
|
|
'hg': 'hg version'
|
|
|
|
|
}
|
tools/vget => tools/v , search, install, etc
* compiler: rename vget to tools/vpm, implement draft support for v vpm search, v vpm update, v vpm install, v vpm remove, v vpm help .
* compiler: use "v pm" instead of "v vpm" to reduce the redundancy of typing, as suggested by slapden
* Use 'v install modulename', 'v search keywords', 'v update modulename', 'v remove modulename' instead of the longer 'v pm install modulename' etc.
2019-11-01 15:19:04 +03:00
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
struct Mod {
|
2019-12-23 13:02:50 +03:00
|
|
|
|
id int
|
2021-08-18 18:58:04 +03:00
|
|
|
|
name string
|
2019-12-23 13:02:50 +03:00
|
|
|
|
url string
|
tools/vget => tools/v , search, install, etc
* compiler: rename vget to tools/vpm, implement draft support for v vpm search, v vpm update, v vpm install, v vpm remove, v vpm help .
* compiler: use "v pm" instead of "v vpm" to reduce the redundancy of typing, as suggested by slapden
* Use 'v install modulename', 'v search keywords', 'v update modulename', 'v remove modulename' instead of the longer 'v pm install modulename' etc.
2019-11-01 15:19:04 +03:00
|
|
|
|
nr_downloads int
|
2020-01-04 00:07:58 +03:00
|
|
|
|
vcs string
|
2019-12-30 07:22:28 +03:00
|
|
|
|
}
|
|
|
|
|
|
2021-08-18 18:58:04 +03:00
|
|
|
|
struct Vmod {
|
|
|
|
|
mut:
|
|
|
|
|
name string
|
|
|
|
|
version string
|
|
|
|
|
deps []string
|
2021-08-18 14:05:10 +03:00
|
|
|
|
}
|
|
|
|
|
|
2021-08-18 18:58:04 +03:00
|
|
|
|
enum Source {
|
|
|
|
|
git
|
|
|
|
|
hg
|
|
|
|
|
vpm
|
2021-08-13 12:28:30 +03:00
|
|
|
|
}
|
|
|
|
|
|
tools/vget => tools/v , search, install, etc
* compiler: rename vget to tools/vpm, implement draft support for v vpm search, v vpm update, v vpm install, v vpm remove, v vpm help .
* compiler: use "v pm" instead of "v vpm" to reduce the redundancy of typing, as suggested by slapden
* Use 'v install modulename', 'v search keywords', 'v update modulename', 'v remove modulename' instead of the longer 'v pm install modulename' etc.
2019-11-01 15:19:04 +03:00
|
|
|
|
fn main() {
|
2020-01-04 00:07:58 +03:00
|
|
|
|
init_settings()
|
tools/vget => tools/v , search, install, etc
* compiler: rename vget to tools/vpm, implement draft support for v vpm search, v vpm update, v vpm install, v vpm remove, v vpm help .
* compiler: use "v pm" instead of "v vpm" to reduce the redundancy of typing, as suggested by slapden
* Use 'v install modulename', 'v search keywords', 'v update modulename', 'v remove modulename' instead of the longer 'v pm install modulename' etc.
2019-11-01 15:19:04 +03:00
|
|
|
|
// This tool is intended to be launched by the v frontend,
|
2019-12-23 13:02:50 +03:00
|
|
|
|
// which provides the path to V inside os.getenv('VEXE')
|
2020-12-20 18:08:56 +03:00
|
|
|
|
// args are: vpm [options] SUBCOMMAND module names
|
|
|
|
|
params := cmdline.only_non_options(os.args[1..])
|
2021-08-18 18:58:04 +03:00
|
|
|
|
options := cmdline.only_options(os.args[1..])
|
2022-11-15 16:53:13 +03:00
|
|
|
|
verbose_println('cli params: ${params}')
|
2020-01-04 00:07:58 +03:00
|
|
|
|
if params.len < 1 {
|
2020-03-13 22:52:49 +03:00
|
|
|
|
vpm_help()
|
tools/vget => tools/v , search, install, etc
* compiler: rename vget to tools/vpm, implement draft support for v vpm search, v vpm update, v vpm install, v vpm remove, v vpm help .
* compiler: use "v pm" instead of "v vpm" to reduce the redundancy of typing, as suggested by slapden
* Use 'v install modulename', 'v search keywords', 'v update modulename', 'v remove modulename' instead of the longer 'v pm install modulename' etc.
2019-11-01 15:19:04 +03:00
|
|
|
|
exit(5)
|
|
|
|
|
}
|
2020-01-04 00:07:58 +03:00
|
|
|
|
vpm_command := params[0]
|
2020-05-24 15:25:29 +03:00
|
|
|
|
mut module_names := params[1..]
|
2020-01-04 00:07:58 +03:00
|
|
|
|
ensure_vmodules_dir_exist()
|
2021-08-18 18:58:04 +03:00
|
|
|
|
// println('module names: ') println(module_names)
|
tools/vget => tools/v , search, install, etc
* compiler: rename vget to tools/vpm, implement draft support for v vpm search, v vpm update, v vpm install, v vpm remove, v vpm help .
* compiler: use "v pm" instead of "v vpm" to reduce the redundancy of typing, as suggested by slapden
* Use 'v install modulename', 'v search keywords', 'v update modulename', 'v remove modulename' instead of the longer 'v pm install modulename' etc.
2019-11-01 15:19:04 +03:00
|
|
|
|
match vpm_command {
|
2019-12-23 13:02:50 +03:00
|
|
|
|
'help' {
|
2020-03-13 22:52:49 +03:00
|
|
|
|
vpm_help()
|
2019-12-23 13:02:50 +03:00
|
|
|
|
}
|
|
|
|
|
'search' {
|
|
|
|
|
vpm_search(module_names)
|
|
|
|
|
}
|
|
|
|
|
'install' {
|
2021-08-18 18:58:04 +03:00
|
|
|
|
if module_names.len == 0 && os.exists('./v.mod') {
|
2021-08-18 14:05:10 +03:00
|
|
|
|
println('Detected v.mod file inside the project directory. Using it...')
|
2021-08-18 18:58:04 +03:00
|
|
|
|
manifest := vmod.from_file('./v.mod') or { panic(err) }
|
2022-08-25 08:52:13 +03:00
|
|
|
|
module_names = manifest.dependencies.clone()
|
2021-08-13 12:28:30 +03:00
|
|
|
|
}
|
2023-06-25 22:31:39 +03:00
|
|
|
|
|
2022-04-09 14:29:41 +03:00
|
|
|
|
if '--once' in options {
|
|
|
|
|
module_names = vpm_once_filter(module_names)
|
2023-06-25 22:31:39 +03:00
|
|
|
|
|
2022-04-09 14:29:41 +03:00
|
|
|
|
if module_names.len == 0 {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
}
|
2023-06-25 22:31:39 +03:00
|
|
|
|
|
|
|
|
|
external_module_names := module_names.filter(it.starts_with('https://'))
|
|
|
|
|
vpm_module_names := module_names.filter(it !in external_module_names)
|
|
|
|
|
|
|
|
|
|
if vpm_module_names.len > 0 {
|
|
|
|
|
vpm_install(vpm_module_names, Source.vpm)
|
2021-08-18 14:05:10 +03:00
|
|
|
|
}
|
|
|
|
|
|
2023-06-25 22:31:39 +03:00
|
|
|
|
if external_module_names.len > 0 {
|
|
|
|
|
mut external_source := Source.git
|
|
|
|
|
|
|
|
|
|
if '--hg' in options {
|
|
|
|
|
external_source = Source.hg
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
vpm_install(external_module_names, external_source)
|
|
|
|
|
}
|
2021-08-18 18:58:04 +03:00
|
|
|
|
}
|
|
|
|
|
'update' {
|
|
|
|
|
vpm_update(module_names)
|
2019-12-23 13:02:50 +03:00
|
|
|
|
}
|
2020-08-18 03:44:18 +03:00
|
|
|
|
'upgrade' {
|
|
|
|
|
vpm_upgrade()
|
|
|
|
|
}
|
2020-07-15 22:55:07 +03:00
|
|
|
|
'outdated' {
|
|
|
|
|
vpm_outdated()
|
|
|
|
|
}
|
2020-07-20 17:39:37 +03:00
|
|
|
|
'list' {
|
|
|
|
|
vpm_list()
|
|
|
|
|
}
|
2019-12-23 13:02:50 +03:00
|
|
|
|
'remove' {
|
|
|
|
|
vpm_remove(module_names)
|
|
|
|
|
}
|
2021-05-24 15:17:57 +03:00
|
|
|
|
'show' {
|
|
|
|
|
vpm_show(module_names)
|
|
|
|
|
}
|
tools/vget => tools/v , search, install, etc
* compiler: rename vget to tools/vpm, implement draft support for v vpm search, v vpm update, v vpm install, v vpm remove, v vpm help .
* compiler: use "v pm" instead of "v vpm" to reduce the redundancy of typing, as suggested by slapden
* Use 'v install modulename', 'v search keywords', 'v update modulename', 'v remove modulename' instead of the longer 'v pm install modulename' etc.
2019-11-01 15:19:04 +03:00
|
|
|
|
else {
|
2022-11-15 16:53:13 +03:00
|
|
|
|
eprintln('Error: you tried to run "v ${vpm_command}"')
|
2022-10-08 11:32:31 +03:00
|
|
|
|
eprintln('... but the v package management tool vpm only knows about these commands:')
|
tools/vget => tools/v , search, install, etc
* compiler: rename vget to tools/vpm, implement draft support for v vpm search, v vpm update, v vpm install, v vpm remove, v vpm help .
* compiler: use "v pm" instead of "v vpm" to reduce the redundancy of typing, as suggested by slapden
* Use 'v install modulename', 'v search keywords', 'v update modulename', 'v remove modulename' instead of the longer 'v pm install modulename' etc.
2019-11-01 15:19:04 +03:00
|
|
|
|
for validcmd in valid_vpm_commands {
|
2022-11-15 16:53:13 +03:00
|
|
|
|
eprintln(' v ${validcmd}')
|
tools/vget => tools/v , search, install, etc
* compiler: rename vget to tools/vpm, implement draft support for v vpm search, v vpm update, v vpm install, v vpm remove, v vpm help .
* compiler: use "v pm" instead of "v vpm" to reduce the redundancy of typing, as suggested by slapden
* Use 'v install modulename', 'v search keywords', 'v update modulename', 'v remove modulename' instead of the longer 'v pm install modulename' etc.
2019-11-01 15:19:04 +03:00
|
|
|
|
}
|
|
|
|
|
exit(3)
|
2019-12-30 07:22:28 +03:00
|
|
|
|
}
|
|
|
|
|
}
|
tools/vget => tools/v , search, install, etc
* compiler: rename vget to tools/vpm, implement draft support for v vpm search, v vpm update, v vpm install, v vpm remove, v vpm help .
* compiler: use "v pm" instead of "v vpm" to reduce the redundancy of typing, as suggested by slapden
* Use 'v install modulename', 'v search keywords', 'v update modulename', 'v remove modulename' instead of the longer 'v pm install modulename' etc.
2019-11-01 15:19:04 +03:00
|
|
|
|
}
|
|
|
|
|
|
2019-12-30 07:22:28 +03:00
|
|
|
|
fn vpm_search(keywords []string) {
|
2020-07-02 19:20:42 +03:00
|
|
|
|
search_keys := keywords.map(it.replace('_', '-'))
|
2021-08-18 18:58:04 +03:00
|
|
|
|
if settings.is_help {
|
2023-02-01 12:18:23 +03:00
|
|
|
|
help.print_and_exit('search')
|
2021-08-18 18:58:04 +03:00
|
|
|
|
exit(0)
|
|
|
|
|
}
|
2020-07-02 19:20:42 +03:00
|
|
|
|
if search_keys.len == 0 {
|
2022-10-08 11:32:31 +03:00
|
|
|
|
eprintln('´v search´ requires *at least one* keyword.')
|
tools/vget => tools/v , search, install, etc
* compiler: rename vget to tools/vpm, implement draft support for v vpm search, v vpm update, v vpm install, v vpm remove, v vpm help .
* compiler: use "v pm" instead of "v vpm" to reduce the redundancy of typing, as suggested by slapden
* Use 'v install modulename', 'v search keywords', 'v update modulename', 'v remove modulename' instead of the longer 'v pm install modulename' etc.
2019-11-01 15:19:04 +03:00
|
|
|
|
exit(2)
|
|
|
|
|
}
|
2019-12-30 07:22:28 +03:00
|
|
|
|
modules := get_all_modules()
|
2020-10-21 00:02:17 +03:00
|
|
|
|
installed_modules := get_installed_modules()
|
2020-07-02 19:20:42 +03:00
|
|
|
|
joined := search_keys.join(', ')
|
2019-12-30 07:22:28 +03:00
|
|
|
|
mut index := 0
|
2021-08-18 18:58:04 +03:00
|
|
|
|
for mod in modules {
|
2020-07-02 19:20:42 +03:00
|
|
|
|
for k in search_keys {
|
2021-08-18 18:58:04 +03:00
|
|
|
|
if !mod.contains(k) {
|
2019-12-30 07:22:28 +03:00
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
if index == 0 {
|
2022-11-15 16:53:13 +03:00
|
|
|
|
println('Search results for "${joined}":\n')
|
2019-12-30 07:22:28 +03:00
|
|
|
|
}
|
|
|
|
|
index++
|
2021-08-18 18:58:04 +03:00
|
|
|
|
mut parts := mod.split('.')
|
2019-12-30 07:22:28 +03:00
|
|
|
|
// in case the author isn't present
|
|
|
|
|
if parts.len == 1 {
|
|
|
|
|
parts << parts[0]
|
2020-10-21 00:02:17 +03:00
|
|
|
|
parts[0] = ' '
|
|
|
|
|
} else {
|
|
|
|
|
parts[0] = ' by ${parts[0]} '
|
2019-12-30 07:22:28 +03:00
|
|
|
|
}
|
2021-08-18 18:58:04 +03:00
|
|
|
|
installed := if mod in installed_modules { ' (installed)' } else { '' }
|
2022-11-15 16:53:13 +03:00
|
|
|
|
println('${index}. ${parts[1]}${parts[0]}[${mod}]${installed}')
|
2019-12-30 07:22:28 +03:00
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if index == 0 {
|
2020-11-07 19:02:16 +03:00
|
|
|
|
vexe := os.getenv('VEXE')
|
|
|
|
|
vroot := os.real_path(os.dir(vexe))
|
2022-11-15 16:53:13 +03:00
|
|
|
|
mut messages := ['No module(s) found for `${joined}` .']
|
2020-11-07 19:02:16 +03:00
|
|
|
|
for vlibmod in search_keys {
|
|
|
|
|
if os.is_dir(os.join_path(vroot, 'vlib', vlibmod)) {
|
2022-11-15 16:53:13 +03:00
|
|
|
|
messages << 'There is already an existing "${vlibmod}" module in vlib, so you can just `import ${vlibmod}` .'
|
2020-11-07 19:02:16 +03:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
for m in messages {
|
|
|
|
|
println(m)
|
|
|
|
|
}
|
2020-07-02 19:20:42 +03:00
|
|
|
|
} else {
|
2022-10-08 11:32:31 +03:00
|
|
|
|
eprintln('\nUse "v install author_name.module_name" to install the module.')
|
2019-12-30 07:22:28 +03:00
|
|
|
|
}
|
tools/vget => tools/v , search, install, etc
* compiler: rename vget to tools/vpm, implement draft support for v vpm search, v vpm update, v vpm install, v vpm remove, v vpm help .
* compiler: use "v pm" instead of "v vpm" to reduce the redundancy of typing, as suggested by slapden
* Use 'v install modulename', 'v search keywords', 'v update modulename', 'v remove modulename' instead of the longer 'v pm install modulename' etc.
2019-11-01 15:19:04 +03:00
|
|
|
|
}
|
|
|
|
|
|
2021-08-18 18:58:04 +03:00
|
|
|
|
fn vpm_install_from_vpm(module_names []string) {
|
tools/vget => tools/v , search, install, etc
* compiler: rename vget to tools/vpm, implement draft support for v vpm search, v vpm update, v vpm install, v vpm remove, v vpm help .
* compiler: use "v pm" instead of "v vpm" to reduce the redundancy of typing, as suggested by slapden
* Use 'v install modulename', 'v search keywords', 'v update modulename', 'v remove modulename' instead of the longer 'v pm install modulename' etc.
2019-11-01 15:19:04 +03:00
|
|
|
|
mut errors := 0
|
2021-08-18 18:58:04 +03:00
|
|
|
|
for n in module_names {
|
|
|
|
|
name := n.trim_space().replace('_', '-')
|
|
|
|
|
mod := get_module_meta_info(name) or {
|
|
|
|
|
errors++
|
2022-11-15 16:53:13 +03:00
|
|
|
|
eprintln('Errors while retrieving meta data for module ${name}:')
|
2022-10-08 11:32:31 +03:00
|
|
|
|
eprintln(err)
|
tools/vget => tools/v , search, install, etc
* compiler: rename vget to tools/vpm, implement draft support for v vpm search, v vpm update, v vpm install, v vpm remove, v vpm help .
* compiler: use "v pm" instead of "v vpm" to reduce the redundancy of typing, as suggested by slapden
* Use 'v install modulename', 'v search keywords', 'v update modulename', 'v remove modulename' instead of the longer 'v pm install modulename' etc.
2019-11-01 15:19:04 +03:00
|
|
|
|
continue
|
|
|
|
|
}
|
2020-01-04 00:07:58 +03:00
|
|
|
|
mut vcs := mod.vcs
|
|
|
|
|
if vcs == '' {
|
|
|
|
|
vcs = supported_vcs_systems[0]
|
|
|
|
|
}
|
2020-04-13 20:59:57 +03:00
|
|
|
|
if vcs !in supported_vcs_systems {
|
2020-01-04 00:07:58 +03:00
|
|
|
|
errors++
|
2022-11-15 16:53:13 +03:00
|
|
|
|
eprintln('Skipping module "${name}", since it uses an unsupported VCS {${vcs}} .')
|
2020-01-04 00:07:58 +03:00
|
|
|
|
continue
|
|
|
|
|
}
|
2022-01-01 16:40:19 +03:00
|
|
|
|
if !ensure_vcs_is_installed(vcs) {
|
|
|
|
|
errors++
|
2022-11-15 16:53:13 +03:00
|
|
|
|
eprintln('VPM needs `${vcs}` to be installed.')
|
2022-01-01 16:40:19 +03:00
|
|
|
|
continue
|
|
|
|
|
}
|
2022-05-27 15:19:35 +03:00
|
|
|
|
//
|
|
|
|
|
minfo := mod_name_info(mod.name)
|
|
|
|
|
if os.exists(minfo.final_module_path) {
|
2021-08-18 18:58:04 +03:00
|
|
|
|
vpm_update([name])
|
2019-12-30 07:22:28 +03:00
|
|
|
|
continue
|
|
|
|
|
}
|
2022-11-15 16:53:13 +03:00
|
|
|
|
println('Installing module "${name}" from "${mod.url}" to "${minfo.final_module_path}" ...')
|
2023-05-25 03:47:58 +03:00
|
|
|
|
increment_module_download_count(name) or {
|
|
|
|
|
errors++
|
|
|
|
|
eprintln('Errors while incrementing the download count for ${name}:')
|
|
|
|
|
}
|
2020-01-04 00:07:58 +03:00
|
|
|
|
vcs_install_cmd := supported_vcs_install_cmds[vcs]
|
2022-11-15 16:53:13 +03:00
|
|
|
|
cmd := '${vcs_install_cmd} "${mod.url}" "${minfo.final_module_path}"'
|
|
|
|
|
verbose_println(' command: ${cmd}')
|
2021-03-08 21:52:13 +03:00
|
|
|
|
cmdres := os.execute(cmd)
|
2020-01-04 00:07:58 +03:00
|
|
|
|
if cmdres.exit_code != 0 {
|
|
|
|
|
errors++
|
2022-11-15 16:53:13 +03:00
|
|
|
|
eprintln('Failed installing module "${name}" to "${minfo.final_module_path}" .')
|
2022-01-01 16:40:19 +03:00
|
|
|
|
print_failed_cmd(cmd, cmdres)
|
2021-08-18 18:58:04 +03:00
|
|
|
|
continue
|
|
|
|
|
}
|
2022-05-27 15:19:35 +03:00
|
|
|
|
resolve_dependencies(name, minfo.final_module_path, module_names)
|
2021-08-18 18:58:04 +03:00
|
|
|
|
}
|
|
|
|
|
if errors > 0 {
|
|
|
|
|
exit(1)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-01-01 16:40:19 +03:00
|
|
|
|
fn print_failed_cmd(cmd string, cmdres os.Result) {
|
2022-11-15 16:53:13 +03:00
|
|
|
|
verbose_println('Failed command: ${cmd}')
|
|
|
|
|
verbose_println('Failed command output:\n${cmdres.output}')
|
2022-01-01 16:40:19 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn ensure_vcs_is_installed(vcs string) bool {
|
|
|
|
|
mut res := true
|
|
|
|
|
cmd := supported_vcs_version_cmds[vcs]
|
|
|
|
|
cmdres := os.execute(cmd)
|
|
|
|
|
if cmdres.exit_code != 0 {
|
|
|
|
|
print_failed_cmd(cmd, cmdres)
|
|
|
|
|
res = false
|
|
|
|
|
}
|
|
|
|
|
return res
|
|
|
|
|
}
|
|
|
|
|
|
2021-08-18 18:58:04 +03:00
|
|
|
|
fn vpm_install_from_vcs(module_names []string, vcs_key string) {
|
|
|
|
|
mut errors := 0
|
|
|
|
|
for n in module_names {
|
|
|
|
|
url := n.trim_space()
|
|
|
|
|
|
|
|
|
|
first_cut_pos := url.last_index('/') or {
|
|
|
|
|
errors++
|
2022-11-15 16:53:13 +03:00
|
|
|
|
eprintln('Errors while retrieving name for module "${url}" :')
|
2022-10-08 11:32:31 +03:00
|
|
|
|
eprintln(err)
|
2021-08-18 18:58:04 +03:00
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
mod_name := url.substr(first_cut_pos + 1, url.len)
|
|
|
|
|
|
|
|
|
|
second_cut_pos := url.substr(0, first_cut_pos).last_index('/') or {
|
|
|
|
|
errors++
|
2022-11-15 16:53:13 +03:00
|
|
|
|
eprintln('Errors while retrieving name for module "${url}" :')
|
2022-10-08 11:32:31 +03:00
|
|
|
|
eprintln(err)
|
2021-08-18 18:58:04 +03:00
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
repo_name := url.substr(second_cut_pos + 1, first_cut_pos)
|
2022-05-27 15:19:35 +03:00
|
|
|
|
mut name := os.join_path(repo_name, mod_name)
|
2021-08-18 18:58:04 +03:00
|
|
|
|
mod_name_as_path := name.replace('-', '_').to_lower()
|
|
|
|
|
mut final_module_path := os.real_path(os.join_path(settings.vmodules_path, mod_name_as_path))
|
|
|
|
|
if os.exists(final_module_path) {
|
|
|
|
|
vpm_update([name.replace('-', '_')])
|
|
|
|
|
continue
|
|
|
|
|
}
|
2022-01-01 16:40:19 +03:00
|
|
|
|
if !ensure_vcs_is_installed(vcs_key) {
|
|
|
|
|
errors++
|
2022-11-15 16:53:13 +03:00
|
|
|
|
eprintln('VPM needs `${vcs_key}` to be installed.')
|
2022-01-01 16:40:19 +03:00
|
|
|
|
continue
|
|
|
|
|
}
|
2022-11-15 16:53:13 +03:00
|
|
|
|
println('Installing module "${name}" from "${url}" to "${final_module_path}" ...')
|
2021-08-18 18:58:04 +03:00
|
|
|
|
vcs_install_cmd := supported_vcs_install_cmds[vcs_key]
|
2022-11-15 16:53:13 +03:00
|
|
|
|
cmd := '${vcs_install_cmd} "${url}" "${final_module_path}"'
|
|
|
|
|
verbose_println(' command: ${cmd}')
|
2021-08-18 18:58:04 +03:00
|
|
|
|
cmdres := os.execute(cmd)
|
|
|
|
|
if cmdres.exit_code != 0 {
|
|
|
|
|
errors++
|
2022-11-15 16:53:13 +03:00
|
|
|
|
eprintln('Failed installing module "${name}" to "${final_module_path}" .')
|
2022-01-01 16:40:19 +03:00
|
|
|
|
print_failed_cmd(cmd, cmdres)
|
2021-08-13 12:28:30 +03:00
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
vmod_path := os.join_path(final_module_path, 'v.mod')
|
|
|
|
|
if os.exists(vmod_path) {
|
2021-08-18 18:58:04 +03:00
|
|
|
|
data := os.read_file(vmod_path) or { return }
|
2023-02-08 21:37:04 +03:00
|
|
|
|
vmod_ := parse_vmod(data) or {
|
2022-10-08 11:33:49 +03:00
|
|
|
|
eprintln(err)
|
|
|
|
|
return
|
|
|
|
|
}
|
2023-02-08 21:37:04 +03:00
|
|
|
|
minfo := mod_name_info(vmod_.name)
|
2022-12-20 18:38:08 +03:00
|
|
|
|
if final_module_path != minfo.final_module_path {
|
2023-02-08 21:37:04 +03:00
|
|
|
|
println('Relocating module from "${name}" to "${vmod_.name}" ( "${minfo.final_module_path}" ) ...')
|
2022-12-20 18:38:08 +03:00
|
|
|
|
if os.exists(minfo.final_module_path) {
|
|
|
|
|
eprintln('Warning module "${minfo.final_module_path}" already exsits!')
|
|
|
|
|
eprintln('Removing module "${minfo.final_module_path}" ...')
|
|
|
|
|
os.rmdir_all(minfo.final_module_path) or {
|
|
|
|
|
errors++
|
2023-08-08 08:59:16 +03:00
|
|
|
|
eprintln('Errors while removing "${minfo.final_module_path}" :')
|
|
|
|
|
eprintln(err)
|
2022-12-20 18:38:08 +03:00
|
|
|
|
continue
|
|
|
|
|
}
|
2021-08-13 12:28:30 +03:00
|
|
|
|
}
|
2022-12-20 18:38:08 +03:00
|
|
|
|
os.mv(final_module_path, minfo.final_module_path) or {
|
2021-08-18 18:58:04 +03:00
|
|
|
|
errors++
|
2022-12-20 18:38:08 +03:00
|
|
|
|
eprintln('Errors while relocating module "${name}" :')
|
2022-10-08 11:32:31 +03:00
|
|
|
|
eprintln(err)
|
2022-12-20 18:38:08 +03:00
|
|
|
|
os.rmdir_all(final_module_path) or {
|
|
|
|
|
errors++
|
|
|
|
|
eprintln('Errors while removing "${final_module_path}" :')
|
|
|
|
|
eprintln(err)
|
|
|
|
|
continue
|
|
|
|
|
}
|
2021-08-18 18:58:04 +03:00
|
|
|
|
continue
|
|
|
|
|
}
|
2023-02-08 21:37:04 +03:00
|
|
|
|
println('Module "${name}" relocated to "${vmod_.name}" successfully.')
|
2023-08-08 08:59:16 +03:00
|
|
|
|
publisher_dir := final_module_path.all_before_last(os.path_separator)
|
|
|
|
|
if os.is_dir_empty(publisher_dir) {
|
|
|
|
|
os.rmdir(publisher_dir) or {
|
|
|
|
|
errors++
|
|
|
|
|
eprintln('Errors while removing "${publisher_dir}" :')
|
|
|
|
|
eprintln(err)
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-12-20 18:38:08 +03:00
|
|
|
|
final_module_path = minfo.final_module_path
|
2021-08-13 12:28:30 +03:00
|
|
|
|
}
|
2023-02-08 21:37:04 +03:00
|
|
|
|
name = vmod_.name
|
2021-08-13 12:28:30 +03:00
|
|
|
|
}
|
2021-08-18 18:58:04 +03:00
|
|
|
|
resolve_dependencies(name, final_module_path, module_names)
|
2021-08-13 12:28:30 +03:00
|
|
|
|
}
|
|
|
|
|
if errors > 0 {
|
|
|
|
|
exit(1)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-04-09 14:29:41 +03:00
|
|
|
|
fn vpm_once_filter(module_names []string) []string {
|
|
|
|
|
installed_modules := get_installed_modules()
|
|
|
|
|
mut toinstall := []string{}
|
|
|
|
|
for mn in module_names {
|
|
|
|
|
if mn !in installed_modules {
|
|
|
|
|
toinstall << mn
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return toinstall
|
|
|
|
|
}
|
|
|
|
|
|
2021-08-18 18:58:04 +03:00
|
|
|
|
fn vpm_install(module_names []string, source Source) {
|
|
|
|
|
if settings.is_help {
|
2023-02-01 12:18:23 +03:00
|
|
|
|
help.print_and_exit('install')
|
2021-08-18 18:58:04 +03:00
|
|
|
|
exit(0)
|
|
|
|
|
}
|
|
|
|
|
if module_names.len == 0 {
|
2022-10-08 11:32:31 +03:00
|
|
|
|
eprintln('´v install´ requires *at least one* module name.')
|
2021-08-18 18:58:04 +03:00
|
|
|
|
exit(2)
|
|
|
|
|
}
|
2022-04-09 14:29:41 +03:00
|
|
|
|
match source {
|
|
|
|
|
.vpm {
|
|
|
|
|
vpm_install_from_vpm(module_names)
|
|
|
|
|
}
|
|
|
|
|
.git {
|
|
|
|
|
vpm_install_from_vcs(module_names, 'git')
|
|
|
|
|
}
|
|
|
|
|
.hg {
|
|
|
|
|
vpm_install_from_vcs(module_names, 'hg')
|
|
|
|
|
}
|
2021-08-18 18:58:04 +03:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn vpm_update(m []string) {
|
|
|
|
|
mut module_names := m.clone()
|
|
|
|
|
if settings.is_help {
|
2023-02-01 12:18:23 +03:00
|
|
|
|
help.print_and_exit('update')
|
2021-08-18 18:58:04 +03:00
|
|
|
|
exit(0)
|
|
|
|
|
}
|
|
|
|
|
if module_names.len == 0 {
|
|
|
|
|
module_names = get_installed_modules()
|
|
|
|
|
}
|
2019-12-30 07:22:28 +03:00
|
|
|
|
mut errors := 0
|
2022-01-15 17:37:54 +03:00
|
|
|
|
for modulename in module_names {
|
2022-05-27 15:22:47 +03:00
|
|
|
|
zname := url_to_module_name(modulename)
|
2022-01-15 17:37:54 +03:00
|
|
|
|
final_module_path := valid_final_path_of_existing_module(modulename) or { continue }
|
2021-08-28 12:44:03 +03:00
|
|
|
|
os.chdir(final_module_path) or {}
|
2022-11-15 16:53:13 +03:00
|
|
|
|
println('Updating module "${zname}" in "${final_module_path}" ...')
|
2021-08-18 18:58:04 +03:00
|
|
|
|
vcs := vcs_used_in_dir(final_module_path) or { continue }
|
2022-01-01 16:40:19 +03:00
|
|
|
|
if !ensure_vcs_is_installed(vcs[0]) {
|
|
|
|
|
errors++
|
2022-11-15 16:53:13 +03:00
|
|
|
|
println('VPM needs `${vcs}` to be installed.')
|
2022-01-01 16:40:19 +03:00
|
|
|
|
continue
|
|
|
|
|
}
|
2021-08-18 18:58:04 +03:00
|
|
|
|
vcs_cmd := supported_vcs_update_cmds[vcs[0]]
|
2022-11-15 16:53:13 +03:00
|
|
|
|
verbose_println(' command: ${vcs_cmd}')
|
|
|
|
|
vcs_res := os.execute('${vcs_cmd}')
|
2020-01-04 00:07:58 +03:00
|
|
|
|
if vcs_res.exit_code != 0 {
|
|
|
|
|
errors++
|
2022-11-15 16:53:13 +03:00
|
|
|
|
println('Failed updating module "${zname}" in "${final_module_path}" .')
|
2022-01-01 16:40:19 +03:00
|
|
|
|
print_failed_cmd(vcs_cmd, vcs_res)
|
2019-12-30 07:22:28 +03:00
|
|
|
|
continue
|
2020-08-07 18:33:13 +03:00
|
|
|
|
} else {
|
2022-11-15 16:53:13 +03:00
|
|
|
|
verbose_println(' ${vcs_res.output.trim_space()}')
|
2023-05-25 03:47:58 +03:00
|
|
|
|
increment_module_download_count(zname) or {
|
|
|
|
|
errors++
|
|
|
|
|
eprintln('Errors while incrementing the download count for ${zname}:')
|
|
|
|
|
}
|
2019-12-30 07:22:28 +03:00
|
|
|
|
}
|
2022-01-15 17:37:54 +03:00
|
|
|
|
resolve_dependencies(modulename, final_module_path, module_names)
|
2019-12-30 07:22:28 +03:00
|
|
|
|
}
|
|
|
|
|
if errors > 0 {
|
|
|
|
|
exit(1)
|
|
|
|
|
}
|
tools/vget => tools/v , search, install, etc
* compiler: rename vget to tools/vpm, implement draft support for v vpm search, v vpm update, v vpm install, v vpm remove, v vpm help .
* compiler: use "v pm" instead of "v vpm" to reduce the redundancy of typing, as suggested by slapden
* Use 'v install modulename', 'v search keywords', 'v update modulename', 'v remove modulename' instead of the longer 'v pm install modulename' etc.
2019-11-01 15:19:04 +03:00
|
|
|
|
}
|
|
|
|
|
|
2023-03-02 16:49:50 +03:00
|
|
|
|
fn get_outdated() ![]string {
|
2021-08-18 18:58:04 +03:00
|
|
|
|
module_names := get_installed_modules()
|
|
|
|
|
mut outdated := []string{}
|
|
|
|
|
for name in module_names {
|
|
|
|
|
final_module_path := valid_final_path_of_existing_module(name) or { continue }
|
2021-08-28 12:44:03 +03:00
|
|
|
|
os.chdir(final_module_path) or {}
|
2021-08-18 18:58:04 +03:00
|
|
|
|
vcs := vcs_used_in_dir(final_module_path) or { continue }
|
|
|
|
|
vcs_cmd_steps := supported_vcs_outdated_steps[vcs[0]]
|
2020-07-22 03:25:20 +03:00
|
|
|
|
mut outputs := []string{}
|
|
|
|
|
for step in vcs_cmd_steps {
|
2021-03-08 21:52:13 +03:00
|
|
|
|
res := os.execute(step)
|
|
|
|
|
if res.exit_code < 0 {
|
2022-11-15 16:53:13 +03:00
|
|
|
|
verbose_println('Error command: ${step}')
|
|
|
|
|
verbose_println('Error details:\n${res.output}')
|
|
|
|
|
return error('Error while checking latest commits for "${name}" .')
|
2020-07-22 03:25:20 +03:00
|
|
|
|
}
|
2021-08-18 18:58:04 +03:00
|
|
|
|
if vcs[0] == 'hg' {
|
2020-09-15 19:35:00 +03:00
|
|
|
|
if res.exit_code == 1 {
|
2021-08-18 18:58:04 +03:00
|
|
|
|
outdated << name
|
2020-09-15 19:35:00 +03:00
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
outputs << res.output
|
|
|
|
|
}
|
2020-07-15 22:55:07 +03:00
|
|
|
|
}
|
2021-08-18 18:58:04 +03:00
|
|
|
|
if vcs[0] == 'git' && outputs[1] != outputs[2] {
|
|
|
|
|
outdated << name
|
2020-07-15 22:55:07 +03:00
|
|
|
|
}
|
|
|
|
|
}
|
2020-08-18 03:44:18 +03:00
|
|
|
|
return outdated
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn vpm_upgrade() {
|
2021-08-18 18:58:04 +03:00
|
|
|
|
outdated := get_outdated() or { exit(1) }
|
2020-08-18 03:44:18 +03:00
|
|
|
|
if outdated.len > 0 {
|
2021-08-18 18:58:04 +03:00
|
|
|
|
vpm_update(outdated)
|
2020-08-18 03:44:18 +03:00
|
|
|
|
} else {
|
|
|
|
|
println('Modules are up to date.')
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn vpm_outdated() {
|
2021-08-18 18:58:04 +03:00
|
|
|
|
outdated := get_outdated() or { exit(1) }
|
2020-07-15 22:55:07 +03:00
|
|
|
|
if outdated.len > 0 {
|
2022-10-08 11:32:31 +03:00
|
|
|
|
eprintln('Outdated modules:')
|
2021-08-18 18:58:04 +03:00
|
|
|
|
for m in outdated {
|
2022-11-15 16:53:13 +03:00
|
|
|
|
eprintln(' ${m}')
|
2020-07-15 22:55:07 +03:00
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
println('Modules are up to date.')
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-07-20 17:39:37 +03:00
|
|
|
|
fn vpm_list() {
|
2021-08-18 18:58:04 +03:00
|
|
|
|
module_names := get_installed_modules()
|
|
|
|
|
if module_names.len == 0 {
|
2022-04-09 14:26:01 +03:00
|
|
|
|
eprintln('You have no modules installed.')
|
2020-07-20 17:39:37 +03:00
|
|
|
|
exit(0)
|
|
|
|
|
}
|
2021-08-18 18:58:04 +03:00
|
|
|
|
for mod in module_names {
|
2022-04-09 14:26:01 +03:00
|
|
|
|
println(mod)
|
2020-07-20 17:39:37 +03:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-12-23 13:02:50 +03:00
|
|
|
|
fn vpm_remove(module_names []string) {
|
2020-01-04 00:07:58 +03:00
|
|
|
|
if settings.is_help {
|
2023-02-01 12:18:23 +03:00
|
|
|
|
help.print_and_exit('remove')
|
tools/vget => tools/v , search, install, etc
* compiler: rename vget to tools/vpm, implement draft support for v vpm search, v vpm update, v vpm install, v vpm remove, v vpm help .
* compiler: use "v pm" instead of "v vpm" to reduce the redundancy of typing, as suggested by slapden
* Use 'v install modulename', 'v search keywords', 'v update modulename', 'v remove modulename' instead of the longer 'v pm install modulename' etc.
2019-11-01 15:19:04 +03:00
|
|
|
|
exit(0)
|
|
|
|
|
}
|
2019-12-30 07:22:28 +03:00
|
|
|
|
if module_names.len == 0 {
|
2022-10-08 11:32:31 +03:00
|
|
|
|
eprintln('´v remove´ requires *at least one* module name.')
|
2019-12-30 07:22:28 +03:00
|
|
|
|
exit(2)
|
|
|
|
|
}
|
|
|
|
|
for name in module_names {
|
2021-01-26 17:43:10 +03:00
|
|
|
|
final_module_path := valid_final_path_of_existing_module(name) or { continue }
|
2022-11-15 16:53:13 +03:00
|
|
|
|
eprintln('Removing module "${name}" ...')
|
|
|
|
|
verbose_println('removing folder ${final_module_path}')
|
2021-03-26 12:37:54 +03:00
|
|
|
|
os.rmdir_all(final_module_path) or {
|
2022-11-15 16:53:13 +03:00
|
|
|
|
verbose_println('error while removing "${final_module_path}": ${err.msg()}')
|
2021-03-26 12:37:54 +03:00
|
|
|
|
}
|
2020-01-04 00:07:58 +03:00
|
|
|
|
// delete author directory if it is empty
|
2019-12-30 07:22:28 +03:00
|
|
|
|
author := name.split('.')[0]
|
2020-06-30 22:42:16 +03:00
|
|
|
|
author_dir := os.real_path(os.join_path(settings.vmodules_path, author))
|
2021-03-26 12:37:54 +03:00
|
|
|
|
if !os.exists(author_dir) {
|
|
|
|
|
continue
|
|
|
|
|
}
|
2019-12-30 07:22:28 +03:00
|
|
|
|
if os.is_dir_empty(author_dir) {
|
2022-11-15 16:53:13 +03:00
|
|
|
|
verbose_println('removing author folder ${author_dir}')
|
2021-03-26 12:37:54 +03:00
|
|
|
|
os.rmdir(author_dir) or {
|
2022-11-15 16:53:13 +03:00
|
|
|
|
verbose_println('error while removing "${author_dir}": ${err.msg()}')
|
2021-03-26 12:37:54 +03:00
|
|
|
|
}
|
2019-12-30 07:22:28 +03:00
|
|
|
|
}
|
|
|
|
|
}
|
tools/vget => tools/v , search, install, etc
* compiler: rename vget to tools/vpm, implement draft support for v vpm search, v vpm update, v vpm install, v vpm remove, v vpm help .
* compiler: use "v pm" instead of "v vpm" to reduce the redundancy of typing, as suggested by slapden
* Use 'v install modulename', 'v search keywords', 'v update modulename', 'v remove modulename' instead of the longer 'v pm install modulename' etc.
2019-11-01 15:19:04 +03:00
|
|
|
|
}
|
|
|
|
|
|
2022-01-15 17:37:54 +03:00
|
|
|
|
fn valid_final_path_of_existing_module(modulename string) ?string {
|
2022-05-27 15:19:35 +03:00
|
|
|
|
name := if mod := get_mod_by_url(modulename) { mod.name } else { modulename }
|
|
|
|
|
minfo := mod_name_info(name)
|
|
|
|
|
if !os.exists(minfo.final_module_path) {
|
2022-11-15 16:53:13 +03:00
|
|
|
|
eprintln('No module with name "${minfo.mname_normalised}" exists at ${minfo.final_module_path}')
|
2020-01-04 00:07:58 +03:00
|
|
|
|
return none
|
|
|
|
|
}
|
2022-05-27 15:19:35 +03:00
|
|
|
|
if !os.is_dir(minfo.final_module_path) {
|
2022-11-15 16:53:13 +03:00
|
|
|
|
eprintln('Skipping "${minfo.final_module_path}", since it is not a folder.')
|
2021-08-18 18:58:04 +03:00
|
|
|
|
return none
|
|
|
|
|
}
|
2022-05-27 15:19:35 +03:00
|
|
|
|
vcs_used_in_dir(minfo.final_module_path) or {
|
2022-11-15 16:53:13 +03:00
|
|
|
|
eprintln('Skipping "${minfo.final_module_path}", since it does not use a supported vcs.')
|
2020-01-04 00:07:58 +03:00
|
|
|
|
return none
|
|
|
|
|
}
|
2022-05-27 15:19:35 +03:00
|
|
|
|
return minfo.final_module_path
|
tools/vget => tools/v , search, install, etc
* compiler: rename vget to tools/vpm, implement draft support for v vpm search, v vpm update, v vpm install, v vpm remove, v vpm help .
* compiler: use "v pm" instead of "v vpm" to reduce the redundancy of typing, as suggested by slapden
* Use 'v install modulename', 'v search keywords', 'v update modulename', 'v remove modulename' instead of the longer 'v pm install modulename' etc.
2019-11-01 15:19:04 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn ensure_vmodules_dir_exist() {
|
2020-01-04 00:07:58 +03:00
|
|
|
|
if !os.is_dir(settings.vmodules_path) {
|
2022-11-15 16:53:13 +03:00
|
|
|
|
println('Creating "${settings.vmodules_path}/" ...')
|
2021-03-01 02:18:14 +03:00
|
|
|
|
os.mkdir(settings.vmodules_path) or { panic(err) }
|
tools/vget => tools/v , search, install, etc
* compiler: rename vget to tools/vpm, implement draft support for v vpm search, v vpm update, v vpm install, v vpm remove, v vpm help .
* compiler: use "v pm" instead of "v vpm" to reduce the redundancy of typing, as suggested by slapden
* Use 'v install modulename', 'v search keywords', 'v update modulename', 'v remove modulename' instead of the longer 'v pm install modulename' etc.
2019-11-01 15:19:04 +03:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-03-13 22:52:49 +03:00
|
|
|
|
fn vpm_help() {
|
2023-02-01 12:18:23 +03:00
|
|
|
|
help.print_and_exit('vpm')
|
tools/vget => tools/v , search, install, etc
* compiler: rename vget to tools/vpm, implement draft support for v vpm search, v vpm update, v vpm install, v vpm remove, v vpm help .
* compiler: use "v pm" instead of "v vpm" to reduce the redundancy of typing, as suggested by slapden
* Use 'v install modulename', 'v search keywords', 'v update modulename', 'v remove modulename' instead of the longer 'v pm install modulename' etc.
2019-11-01 15:19:04 +03:00
|
|
|
|
}
|
2019-12-23 13:02:50 +03:00
|
|
|
|
|
2021-08-18 18:58:04 +03:00
|
|
|
|
fn vcs_used_in_dir(dir string) ?[]string {
|
|
|
|
|
mut vcs := []string{}
|
2020-01-04 00:07:58 +03:00
|
|
|
|
for repo_subfolder in supported_vcs_folders {
|
2020-06-30 22:42:16 +03:00
|
|
|
|
checked_folder := os.real_path(os.join_path(dir, repo_subfolder))
|
2020-01-04 00:07:58 +03:00
|
|
|
|
if os.is_dir(checked_folder) {
|
2021-08-18 18:58:04 +03:00
|
|
|
|
vcs << repo_subfolder.replace('.', '')
|
2020-01-04 00:07:58 +03:00
|
|
|
|
}
|
|
|
|
|
}
|
2021-08-18 18:58:04 +03:00
|
|
|
|
if vcs.len == 0 {
|
|
|
|
|
return none
|
|
|
|
|
}
|
|
|
|
|
return vcs
|
2020-01-04 00:07:58 +03:00
|
|
|
|
}
|
|
|
|
|
|
2021-08-18 18:58:04 +03:00
|
|
|
|
fn get_installed_modules() []string {
|
|
|
|
|
dirs := os.ls(settings.vmodules_path) or { return [] }
|
|
|
|
|
mut modules := []string{}
|
2019-12-30 07:22:28 +03:00
|
|
|
|
for dir in dirs {
|
2020-06-30 22:42:16 +03:00
|
|
|
|
adir := os.join_path(settings.vmodules_path, dir)
|
2020-01-04 00:07:58 +03:00
|
|
|
|
if dir in excluded_dirs || !os.is_dir(adir) {
|
2019-12-30 07:22:28 +03:00
|
|
|
|
continue
|
|
|
|
|
}
|
2021-08-18 18:58:04 +03:00
|
|
|
|
if os.exists(os.join_path(adir, 'v.mod')) && os.exists(os.join_path(adir, '.git', 'config')) {
|
2020-05-31 19:18:24 +03:00
|
|
|
|
// an official vlang module with a short module name, like `vsl`, `ui` or `markdown`
|
2021-08-18 18:58:04 +03:00
|
|
|
|
modules << dir
|
2020-05-31 19:18:24 +03:00
|
|
|
|
continue
|
|
|
|
|
}
|
2019-12-30 07:22:28 +03:00
|
|
|
|
author := dir
|
2021-01-26 17:43:10 +03:00
|
|
|
|
mods := os.ls(adir) or { continue }
|
2019-12-30 07:22:28 +03:00
|
|
|
|
for m in mods {
|
2021-08-18 18:58:04 +03:00
|
|
|
|
vcs_used_in_dir(os.join_path(adir, m)) or { continue }
|
2022-11-15 16:53:13 +03:00
|
|
|
|
modules << '${author}.${m}'
|
2019-12-30 07:22:28 +03:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return modules
|
|
|
|
|
}
|
|
|
|
|
|
2022-05-27 15:19:35 +03:00
|
|
|
|
struct ModNameInfo {
|
|
|
|
|
mut:
|
|
|
|
|
mname string // The-user.The-mod , *never* The-user.The-mod.git
|
|
|
|
|
mname_normalised string // the_user.the_mod
|
|
|
|
|
mname_as_path string // the_user/the_mod
|
|
|
|
|
final_module_path string // ~/.vmodules/the_user/the_mod
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn mod_name_info(mod_name string) ModNameInfo {
|
|
|
|
|
mut info := ModNameInfo{}
|
|
|
|
|
info.mname = if mod_name.ends_with('.git') { mod_name.replace('.git', '') } else { mod_name }
|
|
|
|
|
info.mname_normalised = info.mname.replace('-', '_').to_lower()
|
|
|
|
|
info.mname_as_path = info.mname_normalised.replace('.', os.path_separator)
|
|
|
|
|
info.final_module_path = os.real_path(os.join_path(settings.vmodules_path, info.mname_as_path))
|
|
|
|
|
return info
|
|
|
|
|
}
|
|
|
|
|
|
2022-05-27 15:22:47 +03:00
|
|
|
|
fn url_to_module_name(modulename string) string {
|
2022-05-27 15:19:35 +03:00
|
|
|
|
mut res := if mod := get_mod_by_url(modulename) { mod.name } else { modulename }
|
2022-05-27 15:22:47 +03:00
|
|
|
|
if res.ends_with('.git') {
|
|
|
|
|
res = res.replace('.git', '')
|
|
|
|
|
}
|
2022-05-27 15:19:35 +03:00
|
|
|
|
return res
|
|
|
|
|
}
|
|
|
|
|
|
2021-08-18 18:58:04 +03:00
|
|
|
|
fn get_all_modules() []string {
|
2020-01-04 00:07:58 +03:00
|
|
|
|
url := get_working_server_url()
|
2021-03-01 02:18:14 +03:00
|
|
|
|
r := http.get(url) or { panic(err) }
|
2019-12-30 07:22:28 +03:00
|
|
|
|
if r.status_code != 200 {
|
2022-11-15 16:53:13 +03:00
|
|
|
|
eprintln('Failed to search vpm.vlang.io. Status code: ${r.status_code}')
|
2019-12-30 07:22:28 +03:00
|
|
|
|
exit(1)
|
|
|
|
|
}
|
2022-05-29 20:27:18 +03:00
|
|
|
|
s := r.body
|
2019-12-30 07:22:28 +03:00
|
|
|
|
mut read_len := 0
|
2021-08-18 18:58:04 +03:00
|
|
|
|
mut modules := []string{}
|
2019-12-30 07:22:28 +03:00
|
|
|
|
for read_len < s.len {
|
2022-04-20 12:15:30 +03:00
|
|
|
|
mut start_token := "<a href='/mod"
|
2019-12-30 07:22:28 +03:00
|
|
|
|
end_token := '</a>'
|
|
|
|
|
// get the start index of the module entry
|
|
|
|
|
mut start_index := s.index_after(start_token, read_len)
|
|
|
|
|
if start_index == -1 {
|
2022-04-20 12:15:30 +03:00
|
|
|
|
start_token = '<a href="/mod'
|
|
|
|
|
start_index = s.index_after(start_token, read_len)
|
|
|
|
|
if start_index == -1 {
|
|
|
|
|
break
|
|
|
|
|
}
|
2019-12-30 07:22:28 +03:00
|
|
|
|
}
|
|
|
|
|
// get the index of the end of anchor (a) opening tag
|
|
|
|
|
// we use the previous start_index to make sure we are getting a module and not just a random 'a' tag
|
2022-04-20 12:15:30 +03:00
|
|
|
|
start_token = '>'
|
2019-12-30 07:22:28 +03:00
|
|
|
|
start_index = s.index_after(start_token, start_index) + start_token.len
|
2022-04-20 12:15:30 +03:00
|
|
|
|
|
2019-12-30 07:22:28 +03:00
|
|
|
|
// get the index of the end of module entry
|
|
|
|
|
end_index := s.index_after(end_token, start_index)
|
|
|
|
|
if end_index == -1 {
|
|
|
|
|
break
|
|
|
|
|
}
|
2021-08-18 18:58:04 +03:00
|
|
|
|
modules << s[start_index..end_index]
|
2019-12-30 07:22:28 +03:00
|
|
|
|
read_len = end_index
|
|
|
|
|
if read_len >= s.len {
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return modules
|
|
|
|
|
}
|
|
|
|
|
|
2021-08-18 18:58:04 +03:00
|
|
|
|
fn resolve_dependencies(name string, module_path string, module_names []string) {
|
|
|
|
|
vmod_path := os.join_path(module_path, 'v.mod')
|
|
|
|
|
if !os.exists(vmod_path) {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
data := os.read_file(vmod_path) or { return }
|
2023-02-08 21:37:04 +03:00
|
|
|
|
vmod_ := parse_vmod(data) or {
|
2022-10-08 11:33:49 +03:00
|
|
|
|
eprintln(err)
|
|
|
|
|
return
|
|
|
|
|
}
|
2020-04-26 14:49:31 +03:00
|
|
|
|
mut deps := []string{}
|
2021-08-18 18:58:04 +03:00
|
|
|
|
// filter out dependencies that were already specified by the user
|
2023-02-08 21:37:04 +03:00
|
|
|
|
for d in vmod_.deps {
|
2021-08-18 18:58:04 +03:00
|
|
|
|
if d !in module_names {
|
|
|
|
|
deps << d
|
2019-12-30 07:22:28 +03:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if deps.len > 0 {
|
2022-11-15 16:53:13 +03:00
|
|
|
|
println('Resolving ${deps.len} dependencies for module "${name}" ...')
|
|
|
|
|
verbose_println('Found dependencies: ${deps}')
|
2021-08-18 18:58:04 +03:00
|
|
|
|
vpm_install(deps, Source.vpm)
|
2019-12-30 07:22:28 +03:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-10-08 11:33:49 +03:00
|
|
|
|
fn parse_vmod(data string) !Vmod {
|
2022-11-15 16:53:13 +03:00
|
|
|
|
manifest := vmod.decode(data) or { return error('Parsing v.mod file failed, ${err}') }
|
2023-02-08 21:37:04 +03:00
|
|
|
|
mut vmod_ := Vmod{}
|
|
|
|
|
vmod_.name = manifest.name
|
|
|
|
|
vmod_.version = manifest.version
|
|
|
|
|
vmod_.deps = manifest.dependencies
|
|
|
|
|
return vmod_
|
2021-08-18 18:58:04 +03:00
|
|
|
|
}
|
|
|
|
|
|
2020-01-04 00:07:58 +03:00
|
|
|
|
fn get_working_server_url() string {
|
2021-01-26 17:43:10 +03:00
|
|
|
|
server_urls := if settings.server_urls.len > 0 {
|
|
|
|
|
settings.server_urls
|
|
|
|
|
} else {
|
2022-06-21 12:58:22 +03:00
|
|
|
|
vpm_server_urls
|
2021-01-26 17:43:10 +03:00
|
|
|
|
}
|
2020-01-04 00:07:58 +03:00
|
|
|
|
for url in server_urls {
|
2022-11-15 16:53:13 +03:00
|
|
|
|
verbose_println('Trying server url: ${url}')
|
2020-01-04 00:07:58 +03:00
|
|
|
|
http.head(url) or {
|
2022-11-15 16:53:13 +03:00
|
|
|
|
verbose_println(' ${url} failed.')
|
2020-01-04 00:07:58 +03:00
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
return url
|
|
|
|
|
}
|
|
|
|
|
panic('No responding vpm server found. Please check your network connectivity and try again later.')
|
|
|
|
|
}
|
|
|
|
|
|
2021-08-18 18:58:04 +03:00
|
|
|
|
// settings context:
|
|
|
|
|
struct VpmSettings {
|
|
|
|
|
mut:
|
|
|
|
|
is_help bool
|
|
|
|
|
is_verbose bool
|
|
|
|
|
server_urls []string
|
|
|
|
|
vmodules_path string
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const (
|
|
|
|
|
settings = &VpmSettings{}
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
fn init_settings() {
|
2023-04-13 08:38:21 +03:00
|
|
|
|
mut s := &VpmSettings(unsafe { nil })
|
2021-08-18 18:58:04 +03:00
|
|
|
|
unsafe {
|
|
|
|
|
s = settings
|
|
|
|
|
}
|
|
|
|
|
s.is_help = '-h' in os.args || '--help' in os.args || 'help' in os.args
|
|
|
|
|
s.is_verbose = '-v' in os.args
|
|
|
|
|
s.server_urls = cmdline.options(os.args, '-server-url')
|
|
|
|
|
s.vmodules_path = os.vmodules_dir()
|
|
|
|
|
}
|
|
|
|
|
|
2020-01-04 00:07:58 +03:00
|
|
|
|
fn verbose_println(s string) {
|
|
|
|
|
if settings.is_verbose {
|
|
|
|
|
println(s)
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-03-16 16:30:22 +03:00
|
|
|
|
|
2023-03-02 16:49:50 +03:00
|
|
|
|
fn get_mod_by_url(name string) !Mod {
|
2022-01-15 15:35:37 +03:00
|
|
|
|
if purl := urllib.parse(name) {
|
2022-11-15 16:53:13 +03:00
|
|
|
|
verbose_println('purl: ${purl}')
|
2022-01-15 15:35:37 +03:00
|
|
|
|
mod := Mod{
|
2022-01-15 17:37:54 +03:00
|
|
|
|
name: purl.path.trim_left('/').trim_right('/').replace('/', '.')
|
2022-01-15 15:35:37 +03:00
|
|
|
|
url: name
|
|
|
|
|
}
|
|
|
|
|
verbose_println(mod.str())
|
|
|
|
|
return mod
|
|
|
|
|
}
|
2022-11-15 16:53:13 +03:00
|
|
|
|
return error('invalid url: ${name}')
|
2022-01-15 17:37:54 +03:00
|
|
|
|
}
|
2022-01-15 15:35:37 +03:00
|
|
|
|
|
2023-03-02 16:49:50 +03:00
|
|
|
|
fn get_module_meta_info(name string) !Mod {
|
2022-01-15 17:37:54 +03:00
|
|
|
|
if mod := get_mod_by_url(name) {
|
|
|
|
|
return mod
|
|
|
|
|
}
|
|
|
|
|
mut errors := []string{}
|
2022-06-21 12:58:22 +03:00
|
|
|
|
|
|
|
|
|
for server_url in vpm_server_urls {
|
2023-05-25 03:47:58 +03:00
|
|
|
|
modurl := server_url + '/api/packages/${name}'
|
2022-11-15 16:53:13 +03:00
|
|
|
|
verbose_println('Retrieving module metadata from: "${modurl}" ...')
|
2020-03-16 16:30:22 +03:00
|
|
|
|
r := http.get(modurl) or {
|
2022-11-15 16:53:13 +03:00
|
|
|
|
errors << 'Http server did not respond to our request for "${modurl}" .'
|
|
|
|
|
errors << 'Error details: ${err}'
|
2020-03-16 16:30:22 +03:00
|
|
|
|
continue
|
|
|
|
|
}
|
2022-05-29 20:27:18 +03:00
|
|
|
|
if r.status_code == 404 || r.body.trim_space() == '404' {
|
2022-11-15 16:53:13 +03:00
|
|
|
|
errors << 'Skipping module "${name}", since "${server_url}" reported that "${name}" does not exist.'
|
2020-03-16 16:30:22 +03:00
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
if r.status_code != 200 {
|
2022-11-15 16:53:13 +03:00
|
|
|
|
errors << 'Skipping module "${name}", since "${server_url}" responded with ${r.status_code} http status code. Please try again later.'
|
2020-03-16 16:30:22 +03:00
|
|
|
|
continue
|
|
|
|
|
}
|
2022-05-29 20:27:18 +03:00
|
|
|
|
s := r.body
|
2020-03-16 16:30:22 +03:00
|
|
|
|
if s.len > 0 && s[0] != `{` {
|
|
|
|
|
errors << 'Invalid json data'
|
2022-01-15 17:37:54 +03:00
|
|
|
|
errors << s.trim_space().limit(100) + ' ...'
|
2020-03-16 16:30:22 +03:00
|
|
|
|
continue
|
|
|
|
|
}
|
2020-06-30 22:42:16 +03:00
|
|
|
|
mod := json.decode(Mod, s) or {
|
2022-11-15 16:53:13 +03:00
|
|
|
|
errors << 'Skipping module "${name}", since its information is not in json format.'
|
2020-03-16 16:30:22 +03:00
|
|
|
|
continue
|
|
|
|
|
}
|
2020-03-29 11:08:42 +03:00
|
|
|
|
if '' == mod.url || '' == mod.name {
|
2022-11-15 16:53:13 +03:00
|
|
|
|
errors << 'Skipping module "${name}", since it is missing name or url information.'
|
2020-03-16 16:30:22 +03:00
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
return mod
|
|
|
|
|
}
|
|
|
|
|
return error(errors.join_lines())
|
|
|
|
|
}
|
2021-05-24 15:17:57 +03:00
|
|
|
|
|
2023-05-25 03:47:58 +03:00
|
|
|
|
fn increment_module_download_count(name string) ! {
|
|
|
|
|
mut errors := []string{}
|
|
|
|
|
|
|
|
|
|
for server_url in vpm_server_urls {
|
|
|
|
|
modurl := server_url + '/api/packages/${name}/incr_downloads'
|
|
|
|
|
r := http.post(modurl, '') or {
|
|
|
|
|
errors << 'Http server did not respond to our request for "${modurl}" .'
|
|
|
|
|
errors << 'Error details: ${err}'
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
if r.status_code != 200 {
|
|
|
|
|
errors << 'Failed to increment the download count for module "${name}", since "${server_url}" responded with ${r.status_code} http status code. Please try again later.'
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
return error(errors.join_lines())
|
|
|
|
|
}
|
|
|
|
|
|
2021-05-24 15:17:57 +03:00
|
|
|
|
fn vpm_show(module_names []string) {
|
|
|
|
|
installed_modules := get_installed_modules()
|
|
|
|
|
for module_name in module_names {
|
2021-08-18 18:58:04 +03:00
|
|
|
|
if module_name !in installed_modules {
|
2021-05-24 15:17:57 +03:00
|
|
|
|
module_meta_info := get_module_meta_info(module_name) or { continue }
|
2021-08-18 18:58:04 +03:00
|
|
|
|
print('
|
2022-11-15 16:53:13 +03:00
|
|
|
|
Name: ${module_meta_info.name}
|
|
|
|
|
Homepage: ${module_meta_info.url}
|
|
|
|
|
Downloads: ${module_meta_info.nr_downloads}
|
2021-08-18 18:58:04 +03:00
|
|
|
|
Installed: False
|
|
|
|
|
--------
|
|
|
|
|
')
|
2021-05-24 15:17:57 +03:00
|
|
|
|
continue
|
|
|
|
|
}
|
2021-08-18 18:58:04 +03:00
|
|
|
|
path := os.join_path(os.vmodules_dir(), module_name.replace('.', os.path_separator))
|
|
|
|
|
mod := vmod.from_file(os.join_path(path, 'v.mod')) or { continue }
|
2022-11-15 16:53:13 +03:00
|
|
|
|
print('Name: ${mod.name}
|
|
|
|
|
Version: ${mod.version}
|
|
|
|
|
Description: ${mod.description}
|
|
|
|
|
Homepage: ${mod.repo_url}
|
|
|
|
|
Author: ${mod.author}
|
|
|
|
|
License: ${mod.license}
|
|
|
|
|
Location: ${path}
|
2021-08-18 18:58:04 +03:00
|
|
|
|
Requires: ${mod.dependencies.join(', ')}
|
|
|
|
|
--------
|
|
|
|
|
')
|
2021-05-24 15:17:57 +03:00
|
|
|
|
}
|
|
|
|
|
}
|