diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 000000000..d1273eaf9 --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +/pkg/types/version.go export-subst diff --git a/Makefile b/Makefile index e2203d2f4..fb0118e93 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,5 @@ TAG ?= $(shell git describe --match=NeVeRmAtCh --always --abbrev=40 --dirty) +GIT_VERSION ?= $(shell git describe --always --dirty) CONTAINER_RUNTIME ?= podman .PHONY: build @@ -7,7 +8,8 @@ build: gvproxy qemu-wrapper vm TOOLS_DIR := tools include tools/tools.mk -LDFLAGS = -s -w +VERSION_LDFLAGS=-X github.com/containers/gvisor-tap-vsock/pkg/types.gitVersion=$(GIT_VERSION) +LDFLAGS = -s -w $(VERSION_LDFLAGS) .PHONY: gvproxy gvproxy: diff --git a/cmd/gvproxy/main.go b/cmd/gvproxy/main.go index 8e6977513..cc5a5187d 100644 --- a/cmd/gvproxy/main.go +++ b/cmd/gvproxy/main.go @@ -56,6 +56,8 @@ const ( ) func main() { + version := types.NewVersion("gvproxy") + version.AddFlag() flag.Var(&endpoints, "listen", "control endpoint") flag.BoolVar(&debug, "debug", false, "Print debug info") flag.IntVar(&mtu, "mtu", 1500, "Set the MTU") @@ -72,6 +74,12 @@ func main() { flag.StringVar(&pidFile, "pid-file", "", "Generate a file with the PID in it") flag.Parse() + if version.ShowVersion() { + fmt.Println(version.String()) + os.Exit(0) + } + + log.Infof(version.String()) ctx, cancel := context.WithCancel(context.Background()) // Make this the last defer statement in the stack defer os.Exit(exitCode) diff --git a/cmd/ssh-over-vsock/main.go b/cmd/ssh-over-vsock/main.go index 2dbcca113..f94ed01eb 100644 --- a/cmd/ssh-over-vsock/main.go +++ b/cmd/ssh-over-vsock/main.go @@ -4,8 +4,10 @@ import ( "flag" "fmt" "net" + "os" "github.com/containers/gvisor-tap-vsock/pkg/transport" + "github.com/containers/gvisor-tap-vsock/pkg/types" "github.com/pkg/errors" "github.com/sirupsen/logrus" ) @@ -19,6 +21,8 @@ var ( ) func main() { + version := types.NewVersion("ssh-over-vsock") + version.AddFlag() flag.StringVar(&ip, "ip", "192.168.127.2", "ip of the host") flag.IntVar(&port, "port", 22, "port of the host") flag.StringVar(&user, "user", "", "ssh user") @@ -26,6 +30,11 @@ func main() { flag.StringVar(&endpoint, "url", "/tmp/network.sock", "url of the daemon") flag.Parse() + if version.ShowVersion() { + fmt.Println(version.String()) + os.Exit(0) + } + if err := run(); err != nil { logrus.Fatal(err) } diff --git a/cmd/vm/main_linux.go b/cmd/vm/main_linux.go index 882cffe8f..71e2106b9 100644 --- a/cmd/vm/main_linux.go +++ b/cmd/vm/main_linux.go @@ -35,6 +35,8 @@ var ( ) func main() { + version := types.NewVersion("gvforwarder") + version.AddFlag() flag.StringVar(&endpoint, "url", fmt.Sprintf("vsock://2:1024%s", types.ConnectPath), "url where the tap send packets") flag.StringVar(&iface, "iface", "tap0", "tap interface name") flag.StringVar(&stopIfIfaceExist, "stop-if-exist", "eth0,ens3,enp0s1", "stop if one of these interfaces exists at startup") @@ -44,6 +46,11 @@ func main() { flag.BoolVar(&tapPreexists, "preexisting", false, "use preexisting/preconfigured TAP interface") flag.Parse() + if version.ShowVersion() { + fmt.Println(version.String()) + os.Exit(0) + } + expected := strings.Split(stopIfIfaceExist, ",") links, err := netlink.LinkList() if err != nil { diff --git a/cmd/win-sshproxy/main.go b/cmd/win-sshproxy/main.go index b29332eaf..73d1fdd75 100644 --- a/cmd/win-sshproxy/main.go +++ b/cmd/win-sshproxy/main.go @@ -14,6 +14,7 @@ import ( "unsafe" "github.com/containers/gvisor-tap-vsock/pkg/sshclient" + "github.com/containers/gvisor-tap-vsock/pkg/types" "github.com/containers/winquit/pkg/winquit" "github.com/sirupsen/logrus" "golang.org/x/sync/errgroup" @@ -33,10 +34,15 @@ var ( func main() { args := os.Args if len(args) > 1 { - if args[1] == "-debug" { + switch args[1] { + case "-version": + version := types.NewVersion("win-sshproxy") + fmt.Println(version.String()) + os.Exit(0) + case "-debug": debug = true args = args[2:] - } else { + default: args = args[1:] } } diff --git a/pkg/types/version.go b/pkg/types/version.go new file mode 100644 index 000000000..845ba439b --- /dev/null +++ b/pkg/types/version.go @@ -0,0 +1,64 @@ +package types + +import ( + "flag" + "fmt" + "runtime/debug" + "strings" +) + +var ( + // set using the '-X github.com/containers/gvisor-tap-vsock/pkg/types.gitVersion' linker flag + gitVersion = "" + // set through .gitattributes when `git archive` is used + // see https://icinga.com/blog/2022/05/25/embedding-git-commit-information-in-go-binaries/ + gitArchiveVersion = "$Format:%(describe)$" +) + +type version struct { + binaryName string + showVersion bool +} + +func NewVersion(binaryName string) *version { //nolint:revive + return &version{ + binaryName: binaryName, + } +} + +func (ver *version) String() string { + return fmt.Sprintf("%s version %s", ver.binaryName, moduleVersion()) +} + +func (ver *version) AddFlag() { + flag.BoolVar(&ver.showVersion, "version", false, "Print version information") +} + +func (ver *version) ShowVersion() bool { + return ver.showVersion +} + +func moduleVersion() string { + switch { + // This will be substituted when building from a GitHub tarball + case !strings.HasPrefix(gitArchiveVersion, "$Format:"): + return gitArchiveVersion + // This will be set when building from git using make + case gitVersion != "": + return gitVersion + // moduleVersionFromBuildInfo() will be set when using `go install` + default: + return moduleVersionFromBuildInfo() + } +} + +func moduleVersionFromBuildInfo() string { + info, ok := debug.ReadBuildInfo() + if !ok { + return "" + } + if info.Main.Version == "(devel)" { + return "" + } + return info.Main.Version +}