module main import os import v.vmod import v.help import net.urllib fn vpm_install(requested_modules []string, opts []string) { if settings.is_help { help.print_and_exit('vpm') } modules := if requested_modules.len == 0 { // Run `v install` in a directory of another V module without passing modules as arguments // to install its dependencies. if os.exists('./v.mod') { println('Detected v.mod file inside the project directory. Using it...') manifest := vmod.from_file('./v.mod') or { panic(err) } if manifest.dependencies.len == 0 { println('Nothing to install.') exit(0) } manifest.dependencies.clone() } else { eprintln('Specify a module for installation.') help.print_and_exit('vpm') return } } else { requested_modules.clone() } mut external_modules := modules.filter(it.starts_with('https://')) mut vpm_modules := modules.filter(it !in external_modules) installed_modules := get_installed_modules() if installed_modules.len > 0 && '--once' in opts { mut already_installed := []string{} if external_modules.len > 0 { mut i_deleted := []int{} for i, raw_url in external_modules { url := urllib.parse(raw_url) or { eprintln('Errors while parsing module url "${raw_url}" : ${err}') continue } mod_name := url.path.all_after_last('/') if mod_name in installed_modules { already_installed << mod_name i_deleted << i } } for i in i_deleted.reverse() { external_modules.delete(i) } } if vpm_modules.len > 0 { mut i_deleted := []int{} for i, mod_name in vpm_modules { if mod_name in installed_modules { already_installed << mod_name i_deleted << i continue } } for i in i_deleted.reverse() { vpm_modules.delete(i) } } if already_installed.len > 0 { verbose_println('Already installed modules: ${already_installed}') if already_installed.len == modules.len { verbose_println('All modules are already installed.') exit(0) } } } if vpm_modules.len > 0 { vpm_install_from_vpm(vpm_modules) } if external_modules.len > 0 { source := if '--hg' in opts { Source.hg } else { Source.git } vpm_install_from_vcs(external_modules, source) } } fn install_module(vcs string, name string, url string, final_module_path string) ! { cmd := '${vcs} ${supported_vcs_install_cmds[vcs]} "${url}" "${final_module_path}"' verbose_println(' command: ${cmd}') println('Installing module "${name}" from "${url}" to "${final_module_path}" ...') res := os.execute(cmd) if res.exit_code != 0 { verbose_println(' command output: ${res.output}') return error('Failed installing module "${name}" to "${final_module_path}" .') } } fn vpm_install_from_vpm(module_names []string) { mut errors := 0 for n in module_names { name := n.trim_space().replace('_', '-') mod := get_module_meta_info(name) or { errors++ eprintln('Errors while retrieving meta data for module ${name}:') eprintln(err) continue } mut vcs := mod.vcs if vcs == '' { vcs = supported_vcs_systems[0] } if vcs !in supported_vcs_systems { errors++ eprintln('Skipping module "${name}", since it uses an unsupported VCS {${vcs}} .') continue } ensure_vcs_is_installed(vcs) or { errors++ eprintln(err) continue } minfo := get_mod_name_info(mod.name) if os.exists(minfo.final_module_path) { vpm_update([name]) continue } install_module(vcs, name, mod.url, minfo.final_module_path) or { errors++ eprintln(err) continue } increment_module_download_count(name) or { errors++ eprintln('Errors while incrementing the download count for ${name}:') } resolve_dependencies(name, minfo.final_module_path, module_names) } if errors > 0 { exit(1) } } fn vpm_install_from_vcs(modules []string, vcs_key Source) { vcs := vcs_key.str() mut errors := 0 for raw_url in modules { url := urllib.parse(raw_url) or { errors++ eprintln('Errors while parsing module url "${raw_url}" : ${err}') continue } // Module identifier based on URL. // E.g.: `https://github.com/owner/awesome-v-project` -> `owner/awesome_v_project` mut ident := url.path#[1..].replace('-', '_') owner, repo_name := ident.split_once('/') or { errors++ eprintln('Errors while retrieving module name for: "${url}"') continue } mut final_module_path := os.real_path(os.join_path(settings.vmodules_path, owner.to_lower(), repo_name.to_lower())) if os.exists(final_module_path) { vpm_update([ident]) continue } ensure_vcs_is_installed(vcs) or { errors++ eprintln(err) continue } install_module(vcs, repo_name, url.str(), final_module_path) or { errors++ eprintln(err) continue } vmod_path := os.join_path(final_module_path, 'v.mod') if os.exists(vmod_path) { manifest := vmod.from_file(vmod_path) or { eprintln(err) return } minfo := get_mod_name_info(manifest.name) if final_module_path != minfo.final_module_path { println('Relocating module from "${ident}" to "${manifest.name}" ("${minfo.final_module_path}") ...') if os.exists(minfo.final_module_path) { eprintln('Warning module "${minfo.final_module_path}" already exists!') eprintln('Removing module "${minfo.final_module_path}" ...') os.rmdir_all(minfo.final_module_path) or { errors++ eprintln('Errors while removing "${minfo.final_module_path}" :') eprintln(err) continue } } os.mv(final_module_path, minfo.final_module_path) or { errors++ eprintln('Errors while relocating module "${repo_name}" :') eprintln(err) os.rmdir_all(final_module_path) or { errors++ eprintln('Errors while removing "${final_module_path}" :') eprintln(err) continue } continue } println('Module "${repo_name}" relocated to "${manifest.name}" successfully.') publisher_dir := os.dir(final_module_path) if os.is_dir_empty(publisher_dir) { os.rmdir(publisher_dir) or { errors++ eprintln('Errors while removing "${publisher_dir}" :') eprintln(err) } } final_module_path = minfo.final_module_path } ident = manifest.name } resolve_dependencies(ident, final_module_path, modules) } if errors > 0 { exit(1) } }