@@ -4,6 +4,12 @@ import os
44import v.vmod
55import v.help
66
7+ enum InstallResult {
8+ installed
9+ failed
10+ skipped
11+ }
12+
713fn vpm_install (query []string ) {
814 if settings.is_help {
915 help.print_and_exit ('vpm' )
@@ -88,8 +94,8 @@ fn vpm_install_from_vpm(modules []Module) {
8894 last_errors := errors
8995 vcs := if m.vcs != '' {
9096 supported_vcs[m.vcs] or {
91- errors++
9297 vpm_error ('skipping `${m.name} `, since it uses an unsupported version control system `${m.vcs} `.' )
98+ errors++
9399 continue
94100 }
95101 } else {
@@ -100,18 +106,19 @@ fn vpm_install_from_vpm(modules []Module) {
100106 errors++
101107 continue
102108 }
103- if os.exists (m.install_path) {
104- vpm_update ([m.name])
105- continue
106- }
107- m.install (vcs) or {
108- errors++
109- vpm_error (err.msg ())
110- continue
109+ match m.install (vcs) {
110+ .installed {}
111+ .failed {
112+ errors++
113+ continue
114+ }
115+ .skipped {
116+ continue
117+ }
111118 }
112119 increment_module_download_count (m.name) or {
113- errors++
114120 vpm_error ('failed to increment the download count for `${m.name} `' , details: err.msg ())
121+ errors++
115122 }
116123 if last_errors == errors {
117124 println ('Installed `${m.name} `.' )
@@ -124,27 +131,27 @@ fn vpm_install_from_vpm(modules []Module) {
124131}
125132
126133fn vpm_install_from_vcs (modules []Module) {
127- mut errors := 0
134+ vpm_log (@FILE_LINE, @FN, 'modules: ${modules} ' )
128135 vcs := supported_vcs[settings.vcs]
136+ vcs.is_executable () or {
137+ vpm_error (err.msg ())
138+ exit (1 )
139+ }
129140 urls := modules.map (it .url)
141+ mut errors := 0
130142 for m in modules {
131143 vpm_log (@FILE_LINE, @FN, 'module: ${m} ' )
132144 last_errors := errors
133- if os.exists (m.install_path) {
134- vpm_update ([m.name])
135- continue
136- }
137- vcs.is_executable () or {
138- vpm_error (err.msg ())
139- errors++
140- continue
141- }
142- m.install (vcs) or {
143- errors++
144- vpm_error (err.msg ())
145- continue
145+ match m.install (vcs) {
146+ .installed {}
147+ .failed {
148+ errors++
149+ continue
150+ }
151+ .skipped {
152+ continue
153+ }
146154 }
147- // Note: increment error count when v.mod becomes mandatory for external modules.
148155 manifest := get_manifest (m.install_path) or { continue }
149156 final_path := os.real_path (os.join_path (settings.vmodules_path, manifest.name.replace ('-' ,
150157 '_' ).to_lower ()))
@@ -201,13 +208,57 @@ fn vpm_install_from_vcs(modules []Module) {
201208 }
202209}
203210
204- fn (m Module) install (vcs & VCS) ! {
205- cmd := '${vcs.cmd} ${vcs.args.install} "${m.url} " "${m.install_path} "'
211+ fn (m Module) install (vcs & VCS) InstallResult {
212+ if m.is_installed {
213+ // Case: installed, but not an explicit version. Update instead of continuing the installation.
214+ if m.version == '' && m.installed_version == '' {
215+ vpm_update ([if m.is_external { m.url } else { m.name }])
216+ return .skipped
217+ }
218+ // Case: installed, but conflicting. Confirmation or -[-f]orce flag required.
219+ if settings.is_force || m.confirm_install () {
220+ m.remove () or {
221+ vpm_error ('failed to remove `${m.name} `.' , details: err.msg ())
222+ return .failed
223+ }
224+ } else {
225+ return .skipped
226+ }
227+ }
228+ install_arg := if m.version != '' {
229+ '${vcs.args.install} --single-branch -b ${m.version} '
230+ } else {
231+ vcs.args.install
232+ }
233+ cmd := '${vcs.cmd} ${install_arg} "${m.url} " "${m.install_path} "'
206234 vpm_log (@FILE_LINE, @FN, 'command: ${cmd} ' )
207- println ('Installing module `${m.name} ` from `${m.url} ` to `${m.install_path} ` ...' )
208- os.execute_opt (cmd) or {
209- vpm_log (@FILE_LINE, @FN, 'cmd output: ${err} ' )
210- return error ('failed to install module `${m.name} ` to `${m.install_path} `.' )
235+ println ('Installing `${m.name} `...' )
236+ verbose_println (' cloning from `${m.url} ` to `${m.install_path} `' )
237+ res := os.execute_opt (cmd) or {
238+ vpm_error ('failed to install `${m.name} `.' , details: err.msg ())
239+ return .failed
240+ }
241+ vpm_log (@FILE_LINE, @FN, 'cmd output: ${res.output} ' )
242+ return .installed
243+ }
244+
245+ fn (m Module) confirm_install () bool {
246+ if m.installed_version == m.version {
247+ println ('Module `${m.name}${at_version(m.installed_version)} ` is already installed, use --force to overwrite.' )
248+ return false
249+ } else {
250+ install_version := at_version (if m.version == '' { 'latest' } else { m.version })
251+ println ('Module `${m.name}${at_version(m.installed_version)} ` is already installed at `${m.install_path} `.' )
252+ input := os.input ('Replace it with `${m.name}${install_version} `? [Y/n]: ' )
253+ match input.to_lower () {
254+ '' , 'y' {
255+ return true
256+ }
257+ else {
258+ verbose_println ('Skipping `${m.name} `.' )
259+ return false
260+ }
261+ }
211262 }
212263}
213264
@@ -220,3 +271,7 @@ fn (m Module) remove() ! {
220271 }
221272 verbose_println ('Removed `${m.name} `.' )
222273}
274+
275+ fn at_version (version string ) string {
276+ return if version != '' { '@${version} ' } else { '' }
277+ }
0 commit comments