swadhinbiswas feat: initial release of VEET (Universal Linux App Uninstaller & Deep-Clean Residual Purger) · 8/15/2026
5e0888a
54 lines · 1.3 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
package detector

import (
	"context"
	"strconv"
	"strings"
	"time"

	"github.com/swadhinbiswas/veet/internal/model"
)

type rpmDetector struct {
	ex   Execer
	path string
}

// NewDnfDetector detects rpm packages via rpm (Fedora/RHEL/openSUSE etc).
func NewDnfDetector(ex Execer) Detector {
	path, _ := ex.LookPath("rpm")
	return &rpmDetector{ex: ex, path: path}
}

func (d *rpmDetector) Source() string  { return "dnf" }
func (d *rpmDetector) Available() bool { return d.path != "" }

func (d *rpmDetector) Detect(ctx context.Context) ([]model.AppInfo, error) {
	out, err := Exec(ctx, d.ex, "rpm", "-qa", "--queryformat",
		"%{INSTALLTIME}\t%{SIZE}\t%{NAME}\t%{VERSION}\n")
	if err != nil {
		return nil, err
	}
	var apps []model.AppInfo
	for _, line := range strings.Split(out, "\n") {
		parts := strings.Split(strings.TrimSpace(line), "\t")
		if len(parts) < 4 || parts[2] == "" {
			continue
		}
		installed := time.Time{}
		if sec, err := strconv.ParseInt(parts[0], 10, 64); err == nil && sec > 0 {
			installed = time.Unix(sec, 0)
		}
		sizeBytes, _ := strconv.ParseInt(parts[1], 10, 64)
		apps = append(apps, model.AppInfo{
			Name:          parts[2],
			Version:       parts[3],
			Source:        "dnf",
			InstalledOn:   installed,
			InstallSizeKB: sizeBytes / 1024,
			Status:        "Installed",
		})
	}
	return apps, nil
}