Files
rtsp-simple-server/internal/core/versiongetter/main.go
2025-07-26 16:44:32 +02:00

144 lines
3.4 KiB
Go

// Package main contains an utility to get the server version
package main
import (
"fmt"
"log"
"os"
"path/filepath"
"strconv"
"strings"
"github.com/go-git/go-billy/v5/osfs"
"github.com/go-git/go-git/v5"
"github.com/go-git/go-git/v5/plumbing"
"github.com/go-git/go-git/v5/plumbing/cache"
"github.com/go-git/go-git/v5/plumbing/object"
"github.com/go-git/go-git/v5/storage/filesystem"
)
// Golang version of git describe --tags
func gitDescribeTags(repo *git.Repository) (string, error) {
head, err := repo.Head()
if err != nil {
return "", fmt.Errorf("failed to get HEAD: %w", err)
}
tagIterator, err := repo.Tags()
if err != nil {
return "", fmt.Errorf("failed to get tags: %w", err)
}
defer tagIterator.Close()
tags := make(map[plumbing.Hash]*plumbing.Reference)
err = tagIterator.ForEach(func(t *plumbing.Reference) error {
if to, err2 := repo.TagObject(t.Hash()); err2 == nil {
tags[to.Target] = t
} else {
tags[t.Hash()] = t
}
return nil
})
if err != nil {
return "", fmt.Errorf("failed to iterate tags: %w", err)
}
cIter, err := repo.Log(&git.LogOptions{From: head.Hash()})
if err != nil {
return "", fmt.Errorf("failed to get log: %w", err)
}
i := 0
for {
var commit *object.Commit
commit, err = cIter.Next()
if err != nil {
return "", fmt.Errorf("failed to get next commit: %w", err)
}
if str, ok := tags[commit.Hash]; ok {
label := strings.TrimPrefix(string(str.Name()), "refs/tags/")
if i != 0 {
label += "-" + strconv.FormatInt(int64(i), 10) + "-" + head.Hash().String()[:8]
}
return label, nil
}
i++
}
}
func tagFromGit() error {
// [git.PlainOpen] uses a ChrootOS that limits filesystem access to the .git directory only.
//
// Unfortunately, this can cause issues with package build environments such as Arch Linux's,
// where .git/objects/info/alternates points to a directory outside of the .git directory.
//
// To work around this, specify an AlternatesFS that allows access to the entire filesystem.
dotGitAbs, _ := filepath.Abs("../../.git")
storerFs := osfs.New(dotGitAbs, osfs.WithBoundOS())
storer := filesystem.NewStorageWithOptions(storerFs, cache.NewObjectLRUDefault(), filesystem.Options{
AlternatesFS: osfs.New("/", osfs.WithBoundOS()),
})
workTreeAbs, _ := filepath.Abs("../../")
worktreeFs := osfs.New(workTreeAbs, osfs.WithBoundOS())
repo, err := git.Open(storer, worktreeFs)
if err != nil {
return fmt.Errorf("failed to open repository: %w", err)
}
version, err := gitDescribeTags(repo)
if err != nil {
return fmt.Errorf("failed to get version: %w", err)
}
wt, err := repo.Worktree()
if err != nil {
return fmt.Errorf("failed to get worktree: %w", err)
}
status, err := wt.Status()
if err != nil {
return fmt.Errorf("failed to get status: %w", err)
}
if !status.IsClean() {
version += "-dirty"
}
err = os.WriteFile("VERSION", []byte(version), 0o644)
if err != nil {
return fmt.Errorf("failed to write version file: %w", err)
}
log.Printf("ok (%s)", version)
return nil
}
func do() error {
log.Println("getting mediamtx version...")
err := tagFromGit()
if err != nil {
log.Println("WARN: cannot get tag from .git folder, using v0.0.0 as version")
err = os.WriteFile("VERSION", []byte("v0.0.0"), 0o644)
if err != nil {
return fmt.Errorf("failed to write version file: %w", err)
}
}
return nil
}
func main() {
err := do()
if err != nil {
log.Printf("ERR: %v", err)
os.Exit(1)
}
}