cilium
101 строка · 2.5 Кб
1// SPDX-License-Identifier: Apache-2.0
2// Copyright Authors of Cilium
3
4package main
5
6import (
7"errors"
8"fmt"
9"os/exec"
10"regexp"
11
12"github.com/blang/semver/v4"
13)
14
15// A binaryCheck checks that a binary called name is installed and optionally at
16// least version minVersion (inclusive), and less than maxVersion (exclusive)
17type binaryCheck struct {
18name string
19command string
20alternateNames []string
21ifNotFound checkResult
22versionArgs []string
23versionRegexp *regexp.Regexp
24minVersion *semver.Version // inclusive
25maxVersion *semver.Version // exclusive
26hint string
27}
28
29func (c *binaryCheck) Name() string {
30return c.name
31}
32
33func (c *binaryCheck) Run() (checkResult, string) {
34var path string
35command := c.command
36if command == "" {
37command = c.name
38}
39for _, name := range append([]string{command}, c.alternateNames...) {
40var err error
41path, err = exec.LookPath(name)
42switch {
43case errors.Is(err, exec.ErrNotFound):
44continue
45case err != nil:
46return checkFailed, err.Error()
47}
48}
49if path == "" {
50return c.ifNotFound, fmt.Sprintf("%s not found in $PATH", c.name)
51}
52
53if c.versionArgs == nil {
54return checkOK, fmt.Sprintf("found %s", path)
55}
56
57output, err := exec.Command(path, c.versionArgs...).CombinedOutput()
58if err != nil {
59return checkFailed, err.Error()
60}
61
62version := output
63if c.versionRegexp != nil {
64match := c.versionRegexp.FindSubmatch(version)
65if len(match) != 2 {
66return checkFailed, fmt.Sprintf("found %s, could not parse version from %s", path, version)
67}
68version = match[1]
69}
70
71if c.minVersion != nil || c.maxVersion != nil {
72v, err := semver.ParseTolerant(string(version))
73if err != nil {
74return checkFailed, err.Error()
75}
76
77// only compare the major, minor, and patch versions. this is because
78// github.com/blang/semver treats any extra text is a pre-release
79// version, meaning that, e.g. clang version "10.0.0-4ubuntu1" compares
80// less than "10.0.0"
81effectiveVersion := semver.Version{
82Major: v.Major,
83Minor: v.Minor,
84Patch: v.Patch,
85}
86
87if c.minVersion != nil && effectiveVersion.LT(*c.minVersion) {
88return checkError, fmt.Sprintf("found %s, version %s, need at least %s", path, version, c.minVersion)
89}
90
91if c.maxVersion != nil && effectiveVersion.GTE(*c.maxVersion) {
92return checkError, fmt.Sprintf("found %s, version %s, need less than %s", path, version, c.maxVersion)
93}
94}
95
96return checkOK, fmt.Sprintf("found %s, version %s", path, version)
97}
98
99func (c *binaryCheck) Hint() string {
100return c.hint
101}
102