@@ -6,6 +6,7 @@ import "core:strings"
66import errors " ../../core/errors"
77import index " ../../core/index"
88import template " ../../core/template"
9+ import xbps " ../../core/xbps"
910import utils " ../../utils"
1011import config " ../config"
1112
@@ -14,6 +15,29 @@ is_pkg_installed :: proc(name: string) -> bool {
1415 return utils.run_command_silent ({" xbps-query" , name}) == 0
1516}
1617
18+ // Get the installed version of a package
19+ // Returns empty string if not installed
20+ get_installed_version :: proc (name: string ) -> (version: string , ok: bool ) {
21+ output, cmd_ok := utils.run_command_output ({" xbps-query" , name}, context .temp_allocator)
22+ if !cmd_ok {
23+ return " " , false
24+ }
25+
26+ // Parse pkgver from output
27+ for line in strings.split_lines_iterator (&output) {
28+ if strings.has_prefix (line, " pkgver:" ) {
29+ value := strings.trim_space (line[7 :])
30+ // Use xbps-uhelper for correct parsing of packages with dashes in names
31+ _, version, parse_ok := xbps.parse_pkgver (value)
32+ if parse_ok {
33+ return version, true
34+ }
35+ }
36+ }
37+
38+ return " " , false
39+ }
40+
1741// Check if package exists in official Void repos
1842is_in_official_repos :: proc (name: string ) -> (version: string , ok: bool ) {
1943 output, cmd_ok := utils.run_command_output ({" xbps-query" , " -R" , name}, context .temp_allocator)
@@ -25,9 +49,10 @@ is_in_official_repos :: proc(name: string) -> (version: string, ok: bool) {
2549 for line in strings.split_lines_iterator (&output) {
2650 if strings.has_prefix (line, " pkgver:" ) {
2751 value := strings.trim_space (line[7 :])
28- // Format: name-version
29- if idx := strings.last_index (value, " -" ); idx > 0 {
30- return strings.clone (value[idx + 1 :], context .temp_allocator), true
52+ // Use xbps-uhelper for correct parsing of packages with dashes in names
53+ _, version, parse_ok := xbps.parse_pkgver (value)
54+ if parse_ok {
55+ return version, true
3156 }
3257 }
3358 }
@@ -48,18 +73,35 @@ resolve_package :: proc(
4873 bool ,
4974) {
5075 // 1. Check if already installed
51- if is_pkg_installed (name) {
52- return Resolved_Package {
53- name = strings.clone (name, allocator),
54- source = .Official, // Treat as satisfied (empty version = already installed)
55- version = " " ,
56- depth = depth,
57- }, true
58- }
76+ installed_ver, is_installed := get_installed_version (name)
5977
6078 // 2. Check VUP index for binary
6179 if vup_pkg, ok := index.index_get_package (idx, name); ok {
6280 if url, url_ok := vup_pkg.repo_urls[arch]; url_ok {
81+ // If installed, check if VUP has a newer version
82+ if is_installed {
83+ if xbps.version_greater_than (vup_pkg.version, installed_ver, utils.run_command) {
84+ // VUP has a newer version - mark for upgrade
85+ return Resolved_Package {
86+ name = strings.clone (name, allocator),
87+ source = .VUP,
88+ version = strings.clone (vup_pkg.version, allocator),
89+ repo_url = strings.clone (url, allocator),
90+ category = strings.clone (vup_pkg.category, allocator),
91+ depth = depth,
92+ },
93+ true
94+ } else {
95+ // Already up to date
96+ return Resolved_Package {
97+ name = strings.clone (name, allocator),
98+ source = .Official, // Treat as satisfied (empty version = already installed)
99+ version = " " ,
100+ depth = depth,
101+ }, true
102+ }
103+ }
104+ // Not installed - install from VUP
63105 return Resolved_Package {
64106 name = strings.clone (name, allocator),
65107 source = .VUP,
@@ -72,7 +114,17 @@ resolve_package :: proc(
72114 }
73115 }
74116
75- // 3. Check official Void repos
117+ // 3. Already installed but not in VUP index - satisfied
118+ if is_installed {
119+ return Resolved_Package {
120+ name = strings.clone (name, allocator),
121+ source = .Official, // Treat as satisfied (empty version = already installed)
122+ version = " " ,
123+ depth = depth,
124+ }, true
125+ }
126+
127+ // 4. Check official Void repos
76128 if version, ok := is_in_official_repos (name); ok {
77129 return Resolved_Package {
78130 name = strings.clone (name, allocator),
@@ -83,7 +135,7 @@ resolve_package :: proc(
83135 true
84136 }
85137
86- // 4 . Not found anywhere - return false, no allocations made
138+ // 5 . Not found anywhere - return false, no allocations made
87139 return {}, false
88140}
89141
@@ -97,7 +149,7 @@ resolve_deps :: proc(
97149 Resolution,
98150 bool ,
99151) {
100- res := resolution_make (allocator)
152+ res := resolution_make (target, allocator)
101153
102154 arch, arch_ok := config.get_arch ()
103155 if !arch_ok {
@@ -235,22 +287,37 @@ fetch_and_parse_template :: proc(
235287resolution_print :: proc (r: ^Resolution) {
236288 fmt.println ()
237289
238- // Separate VUP and official packages
239- vup_pkgs: [dynamic ]string
240- official_pkgs: [dynamic ]string
290+ // Check if the target package itself is already installed
291+ target_satisfied := false
292+ for name in r.satisfied {
293+ if name == r.target {
294+ target_satisfied = true
295+ break
296+ }
297+ }
298+
299+ // If target is satisfied and nothing to install/build, just say package is installed
300+ if target_satisfied && len (r.to_install) == 0 && len (r.to_build) == 0 {
301+ fmt.printf (" Package already installed: %s\n " , r.target)
302+ return
303+ }
241304
305+ // Separate VUP packages and official dependencies to install
306+ vup_pkgs: [dynamic ]string
307+ official_deps_to_install: [dynamic ]string
242308
243309 for pkg in r.to_install {
244310 if pkg.source == .VUP {
245311 append (&vup_pkgs, pkg.name)
246312 } else {
247- append (&official_pkgs , pkg.name)
313+ append (&official_deps_to_install , pkg.name)
248314 }
249315 }
250316
317+ // VUP packages to install
251318 if len (vup_pkgs) > 0 {
252319 fmt.printf (" VUP packages (%d):\n " , len (vup_pkgs))
253- fmt.print (" " )
320+ fmt.print (" " )
254321 for name, i in vup_pkgs {
255322 if i > 0 {
256323 fmt.print (" " )
@@ -261,46 +328,59 @@ resolution_print :: proc(r: ^Resolution) {
261328 fmt.println ()
262329 }
263330
264- if len (official_pkgs) > 0 {
265- fmt.printf (" Official deps (%d):\n " , len (official_pkgs))
266- fmt.print (" " )
267- for name, i in official_pkgs {
331+ // Build from source
332+ if len (r.to_build) > 0 {
333+ fmt.printf (" Build from source (%d):\n " , len (r.to_build))
334+ fmt.print (" " )
335+ for pkg, i in r.to_build {
268336 if i > 0 {
269337 fmt.print (" " )
270338 }
271- fmt.print (name)
339+ fmt.print (pkg. name)
272340 }
273341 fmt.println ()
342+ fmt.println ()
274343 }
275344
276- if len (r.to_build) > 0 {
277- fmt.printf (" Build from source (%d):\n " , len (r.to_build))
278- fmt.print (" " )
279- for pkg, i in r.to_build {
345+ // Dependencies to install from official repos
346+ if len (official_deps_to_install) > 0 {
347+ fmt.printf (" Dependencies to install (%d):\n " , len (official_deps_to_install))
348+ fmt.print (" " )
349+ for name, i in official_deps_to_install {
280350 if i > 0 {
281351 fmt.print (" " )
282352 }
283- fmt.print (pkg. name)
353+ fmt.print (name)
284354 }
285355 fmt.println ()
286356 fmt.println ()
287357 }
288358
289- if len (r.satisfied) > 0 {
290- fmt.printf (" Already installed (%d):\n " , len (r.satisfied))
291- fmt.print (" " )
292- for name, i in r.satisfied {
359+ // Dependencies already satisfied (exclude target)
360+ deps_satisfied: [dynamic ]string
361+ for name in r.satisfied {
362+ if name != r.target {
363+ append (&deps_satisfied, name)
364+ }
365+ }
366+
367+ if len (deps_satisfied) > 0 {
368+ fmt.printf (" Dependencies already installed (%d):\n " , len (deps_satisfied))
369+ fmt.print (" " )
370+ for name, i in deps_satisfied {
293371 if i > 0 {
294372 fmt.print (" " )
295373 }
296374 fmt.print (name)
297375 }
298376 fmt.println ()
377+ fmt.println ()
299378 }
300379
380+ // Missing/unresolvable
301381 if len (r.missing) > 0 {
302382 fmt.printf (" Missing (%d):\n " , len (r.missing))
303- fmt.print (" " )
383+ fmt.print (" " )
304384 for name, i in r.missing {
305385 if i > 0 {
306386 fmt.print (" " )
0 commit comments