Skip to content

Commit

Permalink
Merge pull request #43 from getsolus/fix-history-backport
Browse files Browse the repository at this point in the history
Fix history generation for monorepo (v1.5 backport)
  • Loading branch information
silkeh authored Sep 20, 2023
2 parents b801a72 + 1fc3f56 commit 76736ae
Show file tree
Hide file tree
Showing 3 changed files with 85 additions and 79 deletions.
150 changes: 76 additions & 74 deletions builder/history.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,17 @@
package builder

import (
"bytes"
"encoding/xml"
"errors"
"fmt"
git "github.com/libgit2/git2go/v34"
"os"
"os/exec"
"path/filepath"
"regexp"
"sort"
"strings"
"time"
)

Expand Down Expand Up @@ -151,75 +154,30 @@ func GetFileContents(repo *git.Repository, tag, path string) ([]byte, error) {
//
// The repository path will be taken as the directory name of the pkgfile that
// is given to this function.
func NewPackageHistory(pkgfile string) (*PackageHistory, error) {
// Repodir
path := filepath.Dir(pkgfile)
func NewPackageHistory(repo *git.Repository, pkgfile string) (*PackageHistory, error) {
repoDir := abs(filepath.Dir(strings.TrimSuffix(repo.Path(), "/")))
pkgDir := abs(filepath.Dir(pkgfile))

repo, err := git.OpenRepository(path)
if err != nil {
return nil, err
}
// Get all the tags
var tags []string
tags, err = repo.Tags.List()
refs, err := gitLog(pkgDir)
if err != nil {
return nil, err
}

updates := make(map[string]*PackageUpdate)

// Iterate all of the tags
err = repo.Tags.Foreach(func(name string, id *git.Oid) error {
if name == "" || id == nil {
return nil
}

var commit *git.Commit
for _, ref := range refs {
oid, _ := git.NewOid(ref)

obj, err := repo.Lookup(id)
commit, err := repo.LookupCommit(oid)
if err != nil {
return err
return nil, fmt.Errorf("unable to resolve commit %q: %w", ref, err)
}

switch obj.Type() {
// Unannotated tag
case git.ObjectCommit:
commit, err = obj.AsCommit()
if err != nil {
return err
}
tags = append(tags, name)
// Annotated tag with commit target
case git.ObjectTag:
tag, err := obj.AsTag()
if err != nil {
return err
}
commit, err = repo.LookupCommit(tag.TargetId())
if err != nil {
return err
}
tags = append(tags, name)
default:
return fmt.Errorf("Internal git error, found %s", obj.Type().String())
}
if commit == nil {
return nil
}
commitObj := NewPackageUpdate(name, commit, id.String())
updates[name] = commitObj
return nil
})
// Foreach went bork
if err != nil {
return nil, err
updates[ref] = NewPackageUpdate(ref, commit, ref)
}
// Sort the tags by -refname
sort.Sort(sort.Reverse(sort.StringSlice(tags)))

ret := &PackageHistory{pkgfile: pkgfile}
ret.scanUpdates(repo, updates, tags)
updates = nil
ret := &PackageHistory{pkgfile: rel(repoDir, pkgfile)}
ret.scanUpdates(repo, updates)

if len(ret.Updates) < 1 {
return nil, errors.New("No usable git history found")
Expand All @@ -229,7 +187,41 @@ func NewPackageHistory(pkgfile string) (*PackageHistory, error) {
return ret, nil
}

// SortUpdatesByRelease is a simple wrapper to allowing sorting history
func execGit(args ...string) (string, error) {
var buf bytes.Buffer

cmd := exec.Command("git", args...)
cmd.Stdout = &buf

if err := cmd.Run(); err != nil {
return "", fmt.Errorf("error running Git: %w", err)
}

return buf.String(), nil
}

func gitLog(path string) ([]string, error) {
out, err := execGit("-C", path, "log", "--pretty=format:%H", path)
if err != nil {
return nil, fmt.Errorf("unable to get Git history: %w", err)
}

return strings.Split(out, "\n"), nil
}

func rel(base, target string) string {
s, _ := filepath.Rel(abs(base), abs(target))

return s
}

func abs(path string) string {
s, _ := filepath.Abs(path)

return s
}

// SortUpdatesByRelease is a simple wrapper to allowing sorting history.
type SortUpdatesByRelease []*PackageUpdate

func (a SortUpdatesByRelease) Len() int {
Expand All @@ -241,22 +233,20 @@ func (a SortUpdatesByRelease) Swap(i, j int) {
}

func (a SortUpdatesByRelease) Less(i, j int) bool {
if a[i].Package.Release == a[j].Package.Release {
return a[i].Time.Before(a[j].Time)
}

return a[i].Package.Release < a[j].Package.Release
}

// scanUpdates will go back through the collected, "ok" tags, and analyze
// them to be more useful.
func (p *PackageHistory) scanUpdates(repo *git.Repository, updates map[string]*PackageUpdate, tags []string) {
// basename of file
fname := filepath.Base(p.pkgfile)

var updateSet []*PackageUpdate
// Iterate the commit set in order
for _, tagID := range tags {
update := updates[tagID]
if update == nil {
continue
}
func (p *PackageHistory) scanUpdates(repo *git.Repository, updates map[string]*PackageUpdate) {
fname := p.pkgfile
updateSet := make(map[int]*PackageUpdate, len(updates))

for _, update := range updates {
b, err := GetFileContents(repo, update.ObjectID, fname)
if err != nil {
continue
Expand All @@ -267,16 +257,28 @@ func (p *PackageHistory) scanUpdates(repo *git.Repository, updates map[string]*P
if pkg, err = NewYmlPackageFromBytes(b); err != nil {
continue
}

if u, ok := updateSet[pkg.Release]; ok && u.Time.Before(update.Time) {
continue
}

update.Package = pkg
updateSet = append(updateSet, update)
updateSet[pkg.Release] = update
}
sort.Sort(sort.Reverse(SortUpdatesByRelease(updateSet)))
if len(updateSet) >= MaxChangelogEntries {
p.Updates = updateSet[:MaxChangelogEntries]
} else {
p.Updates = updateSet

updateList := make(SortUpdatesByRelease, 0, len(updates))

for _, update := range updateSet {
updateList = append(updateList, update)
}

sort.Sort(sort.Reverse(updateList))

if len(updateList) >= MaxChangelogEntries {
p.Updates = updateList[:MaxChangelogEntries]
} else {
p.Updates = updateList
}
}

// YPKG provides ypkg-gen-history history.xml compatibility
Expand Down
12 changes: 8 additions & 4 deletions builder/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,17 @@ package builder

import (
"errors"
log "github.com/DataDrake/waterlog"
"github.com/getsolus/libosdev/disk"
"os"
"os/signal"
"path/filepath"
"strings"
"sync"
"syscall"
"time"

log "github.com/DataDrake/waterlog"
"github.com/getsolus/libosdev/disk"
git "github.com/libgit2/git2go/v34"
)

var (
Expand Down Expand Up @@ -179,8 +181,10 @@ func (m *Manager) SetPackage(pkg *Package) error {
// Obtain package history for git builds
if pkg.Type == PackageTypeYpkg {
repoDir := filepath.Dir(pkg.Path)
if PathExists(filepath.Join(repoDir, ".git")) {
if history, err := NewPackageHistory(pkg.Path); err == nil {
repo, err := git.OpenRepositoryExtended(repoDir, 0, "/")

if err == nil {
if history, err := NewPackageHistory(repo, pkg.Path); err == nil {
log.Debugln("Obtained package history")
m.history = history
} else {
Expand Down
2 changes: 1 addition & 1 deletion cli/version.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import (

const (
// SolbuildVersion is the current public version of solbuild
SolbuildVersion = "1.5.3.0"
SolbuildVersion = "1.5.4"
)

func init() {
Expand Down

0 comments on commit 76736ae

Please sign in to comment.