diff --git a/cmd/tools/vpm/common.v b/cmd/tools/vpm/common.v index d32a8312a4b314..5d8c228e26cbec 100644 --- a/cmd/tools/vpm/common.v +++ b/cmd/tools/vpm/common.v @@ -39,10 +39,10 @@ fn get_mod_date_info(mut pp pool.PoolProcessor, idx int, wid int) &ModuleDateInf } path := get_path_of_existing_module(result.name) or { return result } vcs := vcs_used_in_dir(path) or { return result } - is_hg := vcs.cmd == 'hg' + args := vcs_info[vcs].args mut outputs := []string{} - for step in vcs.args.outdated { - cmd := '${vcs.cmd} ${vcs.args.path} "${path}" ${step}' + for step in args.outdated { + cmd := [vcs.str(), args.path, os.quoted_path(path), step].join(' ') res := os.execute(cmd) if res.exit_code < 0 { verbose_println('Error command: ${cmd}') @@ -50,14 +50,13 @@ fn get_mod_date_info(mut pp pool.PoolProcessor, idx int, wid int) &ModuleDateInf result.exec_err = true return result } - if is_hg && res.exit_code == 1 { + if vcs == .hg && res.exit_code == 1 { result.outdated = true return result } outputs << res.output } - // vcs.cmd == 'git' - if !is_hg && outputs[1] != outputs[2] { + if vcs == .git && outputs[1] != outputs[2] { result.outdated = true } return result @@ -217,10 +216,6 @@ fn get_path_of_existing_module(mod_name string) ?string { vpm_error('skipping `${path}`, since it is not a directory.') return none } - vcs_used_in_dir(path) or { - vpm_error('skipping `${path}`, since it uses an unsupported version control system.') - return none - } return path } @@ -252,12 +247,6 @@ fn ensure_vmodules_dir_exist() { } } -fn (vcs &VCS) is_executable() ! { - os.find_abs_path_of_executable(vcs.cmd) or { - return error('VPM needs `${vcs.cmd}` to be installed.') - } -} - fn increment_module_download_count(name string) ! { if settings.no_dl_count_increment { println('Skipping download count increment for `${name}`.') @@ -296,15 +285,6 @@ fn resolve_dependencies(manifest ?vmod.Manifest, modules []string) { } } -fn vcs_used_in_dir(dir string) ?VCS { - for vcs in supported_vcs.values() { - if os.is_dir(os.real_path(os.join_path(dir, vcs.dir))) { - return vcs - } - } - return none -} - fn verbose_println(msg string) { if settings.is_verbose { println(msg) diff --git a/cmd/tools/vpm/install.v b/cmd/tools/vpm/install.v index 915046fc149454..2ce87b95c341d2 100644 --- a/cmd/tools/vpm/install.v +++ b/cmd/tools/vpm/install.v @@ -121,8 +121,9 @@ fn (m Module) install() InstallResult { } } vcs := m.vcs or { settings.vcs } - version_opt := if m.version != '' { ' ${vcs.args.version} ${m.version}' } else { '' } - cmd := '${vcs.cmd} ${vcs.args.install}${version_opt} "${m.url}" "${m.install_path}"' + args := vcs_info[vcs].args + version_opt := if m.version != '' { '${args.version} ${m.version}' } else { '' } + cmd := [vcs.str(), args.install, version_opt, m.url, os.quoted_path(m.install_path)].join(' ') vpm_log(@FILE_LINE, @FN, 'command: ${cmd}') println('Installing `${m.name}`...') verbose_println(' cloning from `${m.url}` to `${m.install_path_fmted}`') diff --git a/cmd/tools/vpm/parse.v b/cmd/tools/vpm/parse.v index 2e67f0ebe36c85..8a2cfbd9ffd712 100644 --- a/cmd/tools/vpm/parse.v +++ b/cmd/tools/vpm/parse.v @@ -28,7 +28,7 @@ mut: fn parse_query(query []string) []Module { mut p := Parser{ - is_git_setting: settings.vcs.cmd == 'git' + is_git_setting: settings.vcs == .git } for m in query { p.parse_module(m) @@ -96,12 +96,12 @@ fn (mut p Parser) parse_module(m string) { // Verify VCS. mut is_git_module := true vcs := if info.vcs != '' { - info_vcs := supported_vcs[info.vcs] or { + info_vcs := vcs_from_str(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' + 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++ @@ -109,7 +109,7 @@ fn (mut p Parser) parse_module(m string) { } info_vcs } else { - supported_vcs['git'] + VCS.git } vcs.is_executable() or { vpm_error(err.msg()) diff --git a/cmd/tools/vpm/settings.v b/cmd/tools/vpm/settings.v index 81eb3f38f25868..b1dcb84b006ec7 100644 --- a/cmd/tools/vpm/settings.v +++ b/cmd/tools/vpm/settings.v @@ -35,7 +35,7 @@ fn init_settings() VpmSettings { is_verbose: '-v' in opts || '--verbose' in opts is_force: '-f' in opts || '--force' in opts server_urls: cmdline.options(args, '--server-urls') - vcs: supported_vcs[if '--hg' in opts { 'hg' } else { 'git' }] + vcs: if '--hg' in opts { .hg } else { .git } vmodules_path: os.vmodules_dir() no_dl_count_increment: os.getenv('CI') != '' || (no_inc_env != '' && no_inc_env != '0') fail_on_prompt: os.getenv('VPM_FAIL_ON_PROMPT') != '' diff --git a/cmd/tools/vpm/update.v b/cmd/tools/vpm/update.v index 6d63aa7a3b2a0b..6da8bebf214f82 100644 --- a/cmd/tools/vpm/update.v +++ b/cmd/tools/vpm/update.v @@ -54,7 +54,8 @@ fn update_module(mut pp pool.PoolProcessor, idx int, wid int) &UpdateResult { vpm_error(err.msg()) return &UpdateResult{} } - cmd := '${vcs.cmd} ${vcs.args.path} "${install_path}" ${vcs.args.update}' + args := vcs_info[vcs].args + cmd := [vcs.str(), args.path, os.quoted_path(install_path), args.update].join(' ') vpm_log(@FILE_LINE, @FN, 'cmd: ${cmd}') println('Updating module `${name}` in `${fmt_mod_path(install_path)}`...') res := os.execute_opt(cmd) or { diff --git a/cmd/tools/vpm/vcs.v b/cmd/tools/vpm/vcs.v new file mode 100644 index 00000000000000..24f5e35b0ba248 --- /dev/null +++ b/cmd/tools/vpm/vcs.v @@ -0,0 +1,67 @@ +module main + +import os + +// Supported version control system commands. +enum VCS { + git + hg +} + +struct VCSInfo { + dir string @[required] + args struct { + install string @[required] + version string @[required] // flag to specify a version, added to install. + path string @[required] // flag to specify a path. E.g., used to explicitly work on a path during multithreaded updating. + update string @[required] + outdated []string @[required] + } +} + +const vcs_info = { + VCS.git: VCSInfo{ + dir: '.git' + args: struct { + install: 'clone --depth=1 --recursive --shallow-submodules' + version: '--single-branch -b' + update: 'pull --recurse-submodules' // pulling with `--depth=1` leads to conflicts when the upstream has more than 1 new commits. + path: '-C' + outdated: ['fetch', 'rev-parse @', 'rev-parse @{u}'] + } + } + VCS.hg: VCSInfo{ + dir: '.hg' + args: struct { + install: 'clone' + version: '' // not supported yet. + update: 'pull --update' + path: '-R' + outdated: ['incoming'] + } + } +} + +fn (vcs &VCS) is_executable() ! { + cmd := vcs.str() + os.find_abs_path_of_executable(cmd) or { + return error('VPM requires that `${cmd}` is executable.') + } +} + +fn vcs_used_in_dir(dir string) ?VCS { + for vcs, info in vcs_info { + if os.is_dir(os.real_path(os.join_path(dir, info.dir))) { + return vcs + } + } + return none +} + +fn vcs_from_str(str string) ?VCS { + return match str { + 'git' { .git } + 'hg' { .hg } + else { none } + } +} diff --git a/cmd/tools/vpm/vpm.v b/cmd/tools/vpm/vpm.v index 3c3ad4b997fc18..54159efbdee88f 100644 --- a/cmd/tools/vpm/vpm.v +++ b/cmd/tools/vpm/vpm.v @@ -9,48 +9,12 @@ import rand import v.help import v.vmod -struct VCS { - dir string @[required] - cmd string @[required] - args struct { - install string @[required] - version string @[required] // flag to specify a version, added to install. - path string @[required] // flag to specify a path. E.g., used to explicitly work on a path during multithreaded updating. - update string @[required] - outdated []string @[required] - } -} - const settings = init_settings() const default_vpm_server_urls = ['https://vpm.vlang.io', 'https://vpm.url4e.com'] const vpm_server_urls = rand.shuffle_clone(default_vpm_server_urls) or { [] } // ensure that all queries are distributed fairly const valid_vpm_commands = ['help', 'search', 'install', 'update', 'upgrade', 'outdated', 'list', 'remove', 'show'] const excluded_dirs = ['cache', 'vlib'] -const supported_vcs = { - 'git': VCS{ - dir: '.git' - cmd: 'git' - args: struct { - install: 'clone --depth=1 --recursive --shallow-submodules' - version: '--single-branch -b' - update: 'pull --recurse-submodules' // pulling with `--depth=1` leads to conflicts when the upstream has more than 1 new commits. - path: '-C' - outdated: ['fetch', 'rev-parse @', 'rev-parse @{u}'] - } - } - 'hg': VCS{ - dir: '.hg' - cmd: 'hg' - args: struct { - install: 'clone' - version: '' // not supported yet. - update: 'pull --update' - path: '-R' - outdated: ['incoming'] - } - } -} fn main() { // This tool is intended to be launched by the v frontend,