add --check-version command line flag (#5786)

this allows to check whether a new version is available without upgrading.
This commit is contained in:
Alessandro Ros
2026-05-19 11:42:32 +02:00
committed by GitHub
parent abdd47e45b
commit e7b811fdc0
8 changed files with 156 additions and 105 deletions
+20 -5
View File
@@ -35,6 +35,7 @@ import (
"github.com/bluenviron/mediamtx/internal/servers/rtsp"
"github.com/bluenviron/mediamtx/internal/servers/srt"
"github.com/bluenviron/mediamtx/internal/servers/webrtc"
"github.com/bluenviron/mediamtx/internal/upgrade"
)
//go:generate go run ./versiongetter
@@ -97,9 +98,10 @@ func getRTPMaxPayloadSize(udpMaxPayloadSize int, rtspEncryption conf.Encryption)
}
var cli struct {
Confpath string `arg:"" default:""`
Version bool `help:"print version"`
Upgrade bool `help:"upgrade executable to the latest version"`
Confpath string `arg:"" default:""`
Version bool `help:"print version"`
CheckVersion bool `help:"check whether a new version is available"`
Upgrade bool `help:"upgrade executable to the latest version"`
}
// Core is an instance of MediaMTX.
@@ -159,9 +161,22 @@ func New(args []string) (*Core, bool) {
os.Exit(0)
}
if cli.CheckVersion {
var newVersionAvailable bool
newVersionAvailable, err = upgrade.CheckVersion(string(version), getArch())
if err != nil {
fmt.Printf("ERR: %v\n", err)
os.Exit(1)
}
if newVersionAvailable {
os.Exit(2)
}
os.Exit(0)
}
if cli.Upgrade {
err = upgrade() //nolint:staticcheck
if err != nil { //nolint:staticcheck
err = upgrade.Upgrade(string(version), getArch())
if err != nil {
fmt.Printf("ERR: %v\n", err)
os.Exit(1)
}
-9
View File
@@ -1,9 +0,0 @@
//go:build !enable_upgrade
package core
import "fmt"
func upgrade() error {
return fmt.Errorf("upgrade command is not available")
}
@@ -30,7 +30,6 @@ var (
dumpPath = ""
)
func multiplyAndDivide(v, m, d int64) int64 {
secs := v / d
dec := v % d
+32
View File
@@ -0,0 +1,32 @@
package upgrade
import (
"fmt"
"github.com/Masterminds/semver/v3"
)
// CheckVersion checks whether a new version is available.
// Returns true if a newer version is available.
func CheckVersion(version, _ string) (bool, error) {
if !currentRegexp.MatchString(version) {
return false, fmt.Errorf("current version (%v) is not official and cannot be checked", version)
}
fmt.Println("getting latest version...")
latest, err := latestRemoteVersion()
if err != nil {
return false, err
}
current, _ := semver.NewVersion(version)
if current.GreaterThanEqual(latest) {
fmt.Printf("current version (%v) is up to date\n", "v"+current.String())
return false, nil
}
fmt.Printf("a new version is available: %v (current: %v)\n", "v"+latest.String(), "v"+current.String())
return true, nil
}
+43
View File
@@ -0,0 +1,43 @@
//go:build !windows
package upgrade
import (
"archive/tar"
"compress/gzip"
"errors"
"fmt"
"io"
)
const extension = "tar.gz"
func extractExecutable(r io.Reader) ([]byte, error) {
gzReader, err := gzip.NewReader(r)
if err != nil {
return nil, err
}
defer gzReader.Close() //nolint:errcheck
tarReader := tar.NewReader(gzReader)
for {
var header *tar.Header
header, err = tarReader.Next()
if err != nil {
if errors.Is(err, io.EOF) {
return nil, fmt.Errorf("executable not found")
}
return nil, err
}
if header.Name == executable {
var buf []byte
buf, err = io.ReadAll(tarReader)
if err != nil {
return nil, err
}
return buf, nil
}
}
}
@@ -0,0 +1,43 @@
package upgrade
import (
"archive/zip"
"bytes"
"fmt"
"io"
)
const extension = "zip"
func extractExecutable(r io.Reader) ([]byte, error) {
data, err := io.ReadAll(r)
if err != nil {
return nil, err
}
zipReader, err := zip.NewReader(bytes.NewReader(data), int64(len(data)))
if err != nil {
return nil, err
}
for _, file := range zipReader.File {
if file.Name == executable+".exe" {
var rc io.ReadCloser
rc, err = file.Open()
if err != nil {
return nil, err
}
defer rc.Close()
var buf []byte
buf, err = io.ReadAll(rc)
if err != nil {
return nil, err
}
return buf, nil
}
}
return nil, fmt.Errorf("executable not found")
}
@@ -1,14 +1,9 @@
//go:build enable_upgrade
package core
// Package upgrade contains functions to upgrade the executable.
package upgrade
import (
"archive/tar"
"archive/zip"
"bytes"
"compress/gzip"
"fmt"
"io"
"net/http"
"regexp"
"runtime"
@@ -61,68 +56,10 @@ func latestRemoteVersion() (*semver.Version, error) {
return versions[0], nil
}
func extractExecutable(r io.Reader) ([]byte, error) {
gzReader, err := gzip.NewReader(r)
if err != nil {
return nil, err
}
defer gzReader.Close()
tarReader := tar.NewReader(gzReader)
for {
header, err := tarReader.Next()
if err == io.EOF {
return nil, fmt.Errorf("executable not found")
}
if err != nil {
return nil, err
}
if header.Name == executable {
buf, err := io.ReadAll(tarReader)
if err != nil {
return nil, err
}
return buf, nil
}
}
}
func extractExecutableWin(r io.Reader) ([]byte, error) {
data, err := io.ReadAll(r)
if err != nil {
return nil, err
}
zipReader, err := zip.NewReader(bytes.NewReader(data), int64(len(data)))
if err != nil {
return nil, err
}
for _, file := range zipReader.File {
if file.Name == executable+".exe" {
rc, err := file.Open()
if err != nil {
return nil, err
}
defer rc.Close()
buf, err := io.ReadAll(rc)
if err != nil {
return nil, err
}
return buf, nil
}
}
return nil, fmt.Errorf("executable not found")
}
func upgrade() error {
if !currentRegexp.MatchString(string(version)) {
return fmt.Errorf("current version (%v) is not official and cannot be upgraded", string(version))
// Upgrade downloads the latest executable and replaces the current one with it.
func Upgrade(version, arch string) error {
if !currentRegexp.MatchString(version) {
return fmt.Errorf("current version (%v) is not official and cannot be upgraded", version)
}
fmt.Println("getting latest version...")
@@ -132,7 +69,7 @@ func upgrade() error {
return err
}
current, _ := semver.NewVersion(string(version))
current, _ := semver.NewVersion(version)
if current.GreaterThanEqual(latest) {
fmt.Printf("current version (%v) is up to date\n", "v"+current.String())
@@ -141,14 +78,7 @@ func upgrade() error {
fmt.Printf("downloading version %v...\n", "v"+latest.String())
var extension string
if runtime.GOOS == "windows" {
extension = "zip"
} else {
extension = "tar.gz"
}
ur := fmt.Sprintf(downloadURL, "v"+latest.String(), "v"+latest.String(), runtime.GOOS, getArch(), extension)
ur := fmt.Sprintf(downloadURL, "v"+latest.String(), "v"+latest.String(), runtime.GOOS, arch, extension)
res, err := http.Get(ur)
if err != nil {
@@ -160,11 +90,9 @@ func upgrade() error {
return fmt.Errorf("bad status code: %v", res.StatusCode)
}
var exe []byte
if runtime.GOOS == "windows" {
exe, err = extractExecutableWin(res.Body)
} else {
exe, err = extractExecutable(res.Body)
exe, err := extractExecutable(res.Body)
if err != nil {
return err
}
err = selfupdate.Apply(bytes.NewReader(exe), selfupdate.Options{})
+7 -7
View File
@@ -14,33 +14,33 @@ RUN cp mediamtx.yml LICENSE tmp/
RUN go generate ./...
FROM build-base AS build-windows-amd64
RUN GOOS=windows GOARCH=amd64 go build -tags enable_upgrade -o "tmp/$(BINARY_NAME).exe"
RUN GOOS=windows GOARCH=amd64 go build -o "tmp/$(BINARY_NAME).exe"
RUN go install github.com/tc-hib/go-winres@v0.3.3
RUN go-winres patch --in scripts/winres.json --product-version "$$(git describe --tags --abbrev=0 | sed 's/^v//')" --file-version "$$(git describe --tags --abbrev=0 | sed 's/^v//')" tmp/mediamtx.exe
RUN cd tmp && zip -q "../binaries/$(BINARY_NAME)_$$(cat ../internal/core/VERSION)_windows_amd64.zip" "$(BINARY_NAME).exe" mediamtx.yml LICENSE
FROM build-base AS build-linux-amd64
RUN GOOS=linux GOARCH=amd64 go build -tags enable_upgrade -o "tmp/$(BINARY_NAME)"
RUN GOOS=linux GOARCH=amd64 go build -o "tmp/$(BINARY_NAME)"
RUN tar -C tmp -czf "binaries/$(BINARY_NAME)_$$(cat internal/core/VERSION)_linux_amd64.tar.gz" --owner=0 --group=0 "$(BINARY_NAME)" mediamtx.yml LICENSE
FROM build-base AS build-darwin-amd64
RUN GOOS=darwin GOARCH=amd64 go build -tags enable_upgrade -o "tmp/$(BINARY_NAME)"
RUN GOOS=darwin GOARCH=amd64 go build -o "tmp/$(BINARY_NAME)"
RUN tar -C tmp -czf "binaries/$(BINARY_NAME)_$$(cat internal/core/VERSION)_darwin_amd64.tar.gz" --owner=0 --group=0 "$(BINARY_NAME)" mediamtx.yml LICENSE
FROM build-base AS build-darwin-arm64
RUN GOOS=darwin GOARCH=arm64 go build -tags enable_upgrade -o "tmp/$(BINARY_NAME)"
RUN GOOS=darwin GOARCH=arm64 go build -o "tmp/$(BINARY_NAME)"
RUN tar -C tmp -czf "binaries/$(BINARY_NAME)_$$(cat internal/core/VERSION)_darwin_arm64.tar.gz" --owner=0 --group=0 "$(BINARY_NAME)" mediamtx.yml LICENSE
FROM build-base AS build-linux-armv6
RUN GOOS=linux GOARCH=arm GOARM=6 go build -tags enable_upgrade -o "tmp/$(BINARY_NAME)"
RUN GOOS=linux GOARCH=arm GOARM=6 go build -o "tmp/$(BINARY_NAME)"
RUN tar -C tmp -czf "binaries/$(BINARY_NAME)_$$(cat internal/core/VERSION)_linux_armv6.tar.gz" --owner=0 --group=0 "$(BINARY_NAME)" mediamtx.yml LICENSE
FROM build-base AS build-linux-armv7
RUN GOOS=linux GOARCH=arm GOARM=7 go build -tags enable_upgrade -o "tmp/$(BINARY_NAME)"
RUN GOOS=linux GOARCH=arm GOARM=7 go build -o "tmp/$(BINARY_NAME)"
RUN tar -C tmp -czf "binaries/$(BINARY_NAME)_$$(cat internal/core/VERSION)_linux_armv7.tar.gz" --owner=0 --group=0 "$(BINARY_NAME)" mediamtx.yml LICENSE
FROM build-base AS build-linux-arm64
RUN GOOS=linux GOARCH=arm64 go build -tags enable_upgrade -o "tmp/$(BINARY_NAME)"
RUN GOOS=linux GOARCH=arm64 go build -o "tmp/$(BINARY_NAME)"
RUN tar -C tmp -czf "binaries/$(BINARY_NAME)_$$(cat internal/core/VERSION)_linux_arm64.tar.gz" --owner=0 --group=0 "$(BINARY_NAME)" mediamtx.yml LICENSE
FROM $(BASE_IMAGE)