File: version.go

package info (click to toggle)
golang-github-containers-common 0.64.1%2Bds1-2
  • links: PTS, VCS
  • area: main
  • in suites: experimental
  • size: 5,932 kB
  • sloc: makefile: 132; sh: 111
file content (140 lines) | stat: -rw-r--r-- 4,057 bytes parent folder | download | duplicates (3)
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
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
package version

import (
	"bytes"
	"fmt"
	"os/exec"
	"strings"

	"github.com/containers/storage/pkg/fileutils"
)

const (
	UnknownPackage = "Unknown"
)

// Note: This function is copied from containers/podman libpod/util.go
// Please see https://github.com/containers/common/pull/1460
func queryPackageVersion(cmdArg ...string) string {
	err := fileutils.Exists(cmdArg[0])
	if err != nil {
		return ""
	}
	output := UnknownPackage
	if 1 < len(cmdArg) {
		cmd := exec.Command(cmdArg[0], cmdArg[1:]...)
		if outp, err := cmd.Output(); err == nil {
			output = string(outp)
			switch cmdArg[0] {
			case "/usr/bin/dlocate":
				// can return multiple matches
				l := strings.Split(output, "\n")
				output = l[0]
				r := strings.Split(output, ": ")
				regexpFormat := `^..\s` + r[0] + `\s`
				cmd = exec.Command(cmdArg[0], "-P", regexpFormat, "-l")
				cmd.Env = []string{"COLUMNS=160"} // show entire value
				// dlocate always returns exit code 1 for list command
				if outp, _ = cmd.Output(); len(outp) > 0 {
					lines := strings.Split(string(outp), "\n")
					if len(lines) > 1 {
						line := lines[len(lines)-2] // trailing newline
						f := strings.Fields(line)
						if len(f) >= 2 {
							return f[1] + "_" + f[2]
						}
					}
				}
			case "/usr/bin/dpkg":
				r := strings.Split(output, ": ")
				queryFormat := `${Package}_${Version}_${Architecture}`
				cmd = exec.Command("/usr/bin/dpkg-query", "-f", queryFormat, "-W", r[0])
				if outp, err := cmd.Output(); err == nil {
					output = string(outp)
				}
			case "/usr/bin/pacman":
				pkg := strings.Trim(output, "\n")
				cmd = exec.Command(cmdArg[0], "-Q", "--", pkg)
				if outp, err := cmd.Output(); err == nil {
					output = strings.ReplaceAll(string(outp), " ", "-")
				}
			case "/sbin/apk":
				prefix := cmdArg[len(cmdArg)-1] + " is owned by "
				output = strings.Replace(output, prefix, "", 1)
			}
		}
	}
	return strings.Trim(output, "\n")
}

// Note: This function is copied from containers/podman libpod/util.go
// Please see https://github.com/containers/common/pull/1460
func Package(program string) string { // program is full path
	err := fileutils.Exists(program)
	if err != nil {
		return UnknownPackage
	}

	type Packager struct {
		Format  string
		Command []string
	}
	packagers := []Packager{
		{"rpm", []string{"/usr/bin/rpm", "-q", "-f"}},
		{"deb", []string{"/usr/bin/dlocate", "-F"}},             // Debian, Ubuntu (quick)
		{"deb", []string{"/usr/bin/dpkg", "-S"}},                // Debian, Ubuntu (slow)
		{"pacman", []string{"/usr/bin/pacman", "-Qoq"}},         // Arch
		{"gentoo", []string{"/usr/bin/qfile", "-qv"}},           // Gentoo (quick)
		{"gentoo", []string{"/usr/bin/equery", "b"}},            // Gentoo (slow)
		{"apk", []string{"/sbin/apk", "info", "-W"}},            // Alpine
		{"pkg", []string{"/usr/local/sbin/pkg", "which", "-q"}}, // FreeBSD
	}

	lastformat := ""
	for _, packager := range packagers {
		if packager.Format == lastformat {
			continue
		}
		cmd := packager.Command
		cmd = append(cmd, program)
		if out := queryPackageVersion(cmd...); out != UnknownPackage {
			if out == "" {
				continue
			}
			return out
		}
		lastformat = packager.Format
	}
	return UnknownPackage
}

// Note: This function is copied from containers/podman libpod/util.go
// Please see https://github.com/containers/common/pull/1460
func Program(name string) (string, error) {
	return program(name, false)
}

func ProgramDnsname(name string) (string, error) {
	return program(name, true)
}

func program(program string, dnsname bool) (string, error) {
	cmd := exec.Command(program, "--version")
	var stdout bytes.Buffer
	var stderr bytes.Buffer
	cmd.Stdout = &stdout
	cmd.Stderr = &stderr

	err := cmd.Run()
	if err != nil {
		return "", fmt.Errorf("`%v --version` failed: %v %v (%v)", program, stderr.String(), stdout.String(), err)
	}

	output := strings.TrimSuffix(stdout.String(), "\n")
	// dnsname --version returns the information to stderr
	if dnsname {
		output = strings.TrimSuffix(stderr.String(), "\n")
	}

	return output, nil
}