فهرست منبع

add support for rebuilding local packages

jguer 1 سال پیش
والد
کامیت
c29984a0fa
10فایلهای تغییر یافته به همراه180 افزوده شده و 139 حذف شده
  1. 4 53
      local_install.go
  2. 2 1
      local_install_test.go
  3. 1 1
      pkg/cmd/graph/main.go
  4. 41 71
      pkg/dep/dep_graph.go
  5. 6 5
      pkg/dep/dep_graph_test.go
  6. 117 0
      pkg/dep/srcinfo.go
  7. 1 1
      pkg/upgrade/service.go
  8. 6 5
      pkg/upgrade/service_test.go
  9. 1 1
      print.go
  10. 1 1
      sync.go

+ 4 - 53
local_install.go

@@ -5,8 +5,6 @@ package main
 import (
 	"context"
 	"fmt"
-	"os"
-	"path/filepath"
 	"strings"
 
 	"github.com/Jguer/yay/v12/pkg/db"
@@ -14,76 +12,29 @@ import (
 	"github.com/Jguer/yay/v12/pkg/multierror"
 	"github.com/Jguer/yay/v12/pkg/runtime"
 	"github.com/Jguer/yay/v12/pkg/settings"
-	"github.com/Jguer/yay/v12/pkg/settings/exe"
 	"github.com/Jguer/yay/v12/pkg/settings/parser"
 	"github.com/Jguer/yay/v12/pkg/sync"
 
-	gosrc "github.com/Morganamilo/go-srcinfo"
 	"github.com/leonelquinteros/gotext"
 	"github.com/pkg/errors"
 )
 
-var ErrNoBuildFiles = errors.New(gotext.Get("cannot find PKGBUILD and .SRCINFO in directory"))
-
-func srcinfoExists(ctx context.Context,
-	cmdBuilder exe.ICmdBuilder, targetDir string,
-) error {
-	srcInfoDir := filepath.Join(targetDir, ".SRCINFO")
-	pkgbuildDir := filepath.Join(targetDir, "PKGBUILD")
-	if _, err := os.Stat(srcInfoDir); err == nil {
-		if _, err := os.Stat(pkgbuildDir); err == nil {
-			return nil
-		}
-	}
-
-	if _, err := os.Stat(pkgbuildDir); err == nil {
-		// run makepkg to generate .SRCINFO
-		srcinfo, stderr, err := cmdBuilder.Capture(cmdBuilder.BuildMakepkgCmd(ctx, targetDir, "--printsrcinfo"))
-		if err != nil {
-			return fmt.Errorf("unable to generate .SRCINFO: %w - %s", err, stderr)
-		}
-
-		if err := os.WriteFile(srcInfoDir, []byte(srcinfo), 0o600); err != nil {
-			return fmt.Errorf("unable to write .SRCINFO: %w", err)
-		}
-
-		return nil
-	}
-
-	return fmt.Errorf("%w: %s", ErrNoBuildFiles, targetDir)
-}
-
 func installLocalPKGBUILD(
 	ctx context.Context,
 	run *runtime.Runtime,
 	cmdArgs *parser.Arguments,
 	dbExecutor db.Executor,
 ) error {
-	aurCache := run.AURClient
 	noCheck := strings.Contains(run.Cfg.MFlags, "--nocheck")
+	grapher := dep.NewGrapher(dbExecutor, run.AURClient, run.CmdBuilder, false, settings.NoConfirm,
+		cmdArgs.ExistsDouble("d", "nodeps"), noCheck, cmdArgs.ExistsArg("needed"),
+		run.Logger.Child("grapher"))
 
 	if len(cmdArgs.Targets) < 1 {
 		return errors.New(gotext.Get("no target directories specified"))
 	}
 
-	srcInfos := map[string]*gosrc.Srcinfo{}
-	for _, targetDir := range cmdArgs.Targets {
-		if err := srcinfoExists(ctx, run.CmdBuilder, targetDir); err != nil {
-			return err
-		}
-
-		pkgbuild, err := gosrc.ParseFile(filepath.Join(targetDir, ".SRCINFO"))
-		if err != nil {
-			return errors.Wrap(err, gotext.Get("failed to parse .SRCINFO"))
-		}
-
-		srcInfos[targetDir] = pkgbuild
-	}
-
-	grapher := dep.NewGrapher(dbExecutor, aurCache, false, settings.NoConfirm,
-		cmdArgs.ExistsDouble("d", "nodeps"), noCheck, cmdArgs.ExistsArg("needed"),
-		run.Logger.Child("grapher"))
-	graph, err := grapher.GraphFromSrcInfos(ctx, nil, srcInfos)
+	graph, err := grapher.GraphFromSrcInfoDirs(ctx, nil, cmdArgs.Targets)
 	if err != nil {
 		return err
 	}

+ 2 - 1
local_install_test.go

@@ -19,6 +19,7 @@ import (
 	"github.com/stretchr/testify/require"
 
 	"github.com/Jguer/yay/v12/pkg/db/mock"
+	"github.com/Jguer/yay/v12/pkg/dep"
 	mockaur "github.com/Jguer/yay/v12/pkg/dep/mock"
 	"github.com/Jguer/yay/v12/pkg/runtime"
 	"github.com/Jguer/yay/v12/pkg/settings"
@@ -743,7 +744,7 @@ func TestIntegrationLocalInstallMissingFiles(t *testing.T) {
 	}
 
 	err = handleCmd(context.Background(), config, cmdArgs, db)
-	require.ErrorIs(t, err, ErrNoBuildFiles)
+	require.ErrorIs(t, err, dep.ErrNoBuildFiles)
 
 	require.Len(t, mockRunner.ShowCalls, len(wantShow))
 	require.Len(t, mockRunner.CaptureCalls, len(wantCapture))

+ 1 - 1
pkg/cmd/graph/main.go

@@ -46,7 +46,7 @@ func handleCmd(logger *text.Logger) error {
 		return errors.Wrap(err, gotext.Get("failed to retrieve aur Cache"))
 	}
 
-	grapher := dep.NewGrapher(dbExecutor, aurCache, true, settings.NoConfirm,
+	grapher := dep.NewGrapher(dbExecutor, aurCache, run.CmdBuilder, true, settings.NoConfirm,
 		cmdArgs.ExistsDouble("d", "nodeps"), false, false,
 		run.Logger.Child("grapher"))
 

+ 41 - 71
pkg/dep/dep_graph.go

@@ -15,9 +15,15 @@ import (
 	"github.com/Jguer/yay/v12/pkg/dep/topo"
 	"github.com/Jguer/yay/v12/pkg/intrange"
 	aur "github.com/Jguer/yay/v12/pkg/query"
+	"github.com/Jguer/yay/v12/pkg/settings/exe"
 	"github.com/Jguer/yay/v12/pkg/text"
 )
 
+const (
+	sourceAUR          = "aur"
+	sourceCacheSRCINFO = "srcinfo"
+)
+
 type InstallInfo struct {
 	Source       Source
 	Reason       Reason
@@ -93,26 +99,34 @@ var colorMap = map[Reason]string{
 	CheckDep: "forestgreen",
 }
 
+type SourceHandler interface {
+	Graph(ctx context.Context, graph *topo.Graph[string, *InstallInfo], targets []Target) (*topo.Graph[string, *InstallInfo], error)
+	Test(target Target) bool
+}
+
 type Grapher struct {
 	logger        *text.Logger
 	providerCache map[string][]aur.Pkg
 
 	dbExecutor  db.Executor
 	aurClient   aurc.QueryClient
+	cmdBuilder  exe.ICmdBuilder
 	fullGraph   bool // If true, the graph will include all dependencies including already installed ones or repo
 	noConfirm   bool // If true, the graph will not prompt for confirmation
 	noDeps      bool // If true, the graph will not include dependencies
 	noCheckDeps bool // If true, the graph will not include check dependencies
 	needed      bool // If true, the graph will only include packages that are not installed
+	handlers    map[string][]SourceHandler
 }
 
-func NewGrapher(dbExecutor db.Executor, aurCache aurc.QueryClient,
+func NewGrapher(dbExecutor db.Executor, aurCache aurc.QueryClient, cmdBuilder exe.ICmdBuilder,
 	fullGraph, noConfirm, noDeps, noCheckDeps, needed bool,
 	logger *text.Logger,
 ) *Grapher {
 	return &Grapher{
 		dbExecutor:    dbExecutor,
 		aurClient:     aurCache,
+		cmdBuilder:    cmdBuilder,
 		fullGraph:     fullGraph,
 		noConfirm:     noConfirm,
 		noDeps:        noDeps,
@@ -120,6 +134,7 @@ func NewGrapher(dbExecutor db.Executor, aurCache aurc.QueryClient,
 		needed:        needed,
 		providerCache: make(map[string][]aurc.Pkg, 5),
 		logger:        logger,
+		handlers:      make(map[string][]SourceHandler),
 	}
 }
 
@@ -127,6 +142,10 @@ func NewGraph() *topo.Graph[string, *InstallInfo] {
 	return topo.New[string, *InstallInfo]()
 }
 
+func (g *Grapher) RegisterSourceHandler(handler SourceHandler, source string) {
+	g.handlers[source] = append(g.handlers[source], handler)
+}
+
 func (g *Grapher) GraphFromTargets(ctx context.Context,
 	graph *topo.Graph[string, *InstallInfo], targets []string,
 ) (*topo.Graph[string, *InstallInfo], error) {
@@ -135,6 +154,7 @@ func (g *Grapher) GraphFromTargets(ctx context.Context,
 	}
 
 	aurTargets := make([]string, 0, len(targets))
+	srcinfoTargets := make([]string, 0)
 
 	for _, targetString := range targets {
 		target := ToTarget(targetString)
@@ -142,7 +162,7 @@ func (g *Grapher) GraphFromTargets(ctx context.Context,
 		switch target.DB {
 		case "": // unspecified db
 			if pkg := g.dbExecutor.SyncSatisfier(target.Name); pkg != nil {
-				g.GraphSyncPkg(ctx, graph, pkg, nil)
+				GraphSyncPkg(ctx, g.dbExecutor, graph, g.logger, pkg, nil)
 
 				continue
 			}
@@ -156,15 +176,17 @@ func (g *Grapher) GraphFromTargets(ctx context.Context,
 			}
 
 			fallthrough
-		case "aur":
+		case sourceAUR:
 			aurTargets = append(aurTargets, target.Name)
+		case sourceCacheSRCINFO:
+			srcinfoTargets = append(srcinfoTargets, target.Name)
 		default:
 			pkg, err := g.dbExecutor.SatisfierFromDB(target.Name, target.DB)
 			if err != nil {
 				return nil, err
 			}
 			if pkg != nil {
-				g.GraphSyncPkg(ctx, graph, pkg, nil)
+				GraphSyncPkg(ctx, g.dbExecutor, graph, g.logger, pkg, nil)
 
 				continue
 			}
@@ -189,6 +211,11 @@ func (g *Grapher) GraphFromTargets(ctx context.Context,
 		return nil, errA
 	}
 
+	graph, errS := g.GraphFromSrcInfoDirs(ctx, graph, srcinfoTargets)
+	if errS != nil {
+		return nil, errS
+	}
+
 	return graph, nil
 }
 
@@ -236,63 +263,6 @@ func (g *Grapher) addAurPkgProvides(pkg *aurc.Pkg, graph *topo.Graph[string, *In
 	}
 }
 
-func (g *Grapher) GraphFromSrcInfos(ctx context.Context, graph *topo.Graph[string, *InstallInfo],
-	srcInfos map[string]*gosrc.Srcinfo,
-) (*topo.Graph[string, *InstallInfo], error) {
-	if graph == nil {
-		graph = NewGraph()
-	}
-
-	aurPkgsAdded := []*aurc.Pkg{}
-	for pkgBuildDir, pkgbuild := range srcInfos {
-		pkgBuildDir := pkgBuildDir
-
-		aurPkgs, err := makeAURPKGFromSrcinfo(g.dbExecutor, pkgbuild)
-		if err != nil {
-			return nil, err
-		}
-
-		if len(aurPkgs) > 1 {
-			var errPick error
-			aurPkgs, errPick = g.pickSrcInfoPkgs(aurPkgs)
-			if errPick != nil {
-				return nil, errPick
-			}
-		}
-
-		for _, pkg := range aurPkgs {
-			pkg := pkg
-
-			reason := Explicit
-			if pkg := g.dbExecutor.LocalPackage(pkg.Name); pkg != nil {
-				reason = Reason(pkg.Reason())
-			}
-
-			graph.AddNode(pkg.Name)
-
-			g.addAurPkgProvides(pkg, graph)
-
-			g.ValidateAndSetNodeInfo(graph, pkg.Name, &topo.NodeInfo[*InstallInfo]{
-				Color:      colorMap[reason],
-				Background: bgColorMap[AUR],
-				Value: &InstallInfo{
-					Source:      SrcInfo,
-					Reason:      reason,
-					SrcinfoPath: &pkgBuildDir,
-					AURBase:     &pkg.PackageBase,
-					Version:     pkg.Version,
-				},
-			})
-		}
-
-		aurPkgsAdded = append(aurPkgsAdded, aurPkgs...)
-	}
-
-	g.AddDepsForPkgs(ctx, aurPkgsAdded, graph)
-
-	return graph, nil
-}
-
 func (g *Grapher) AddDepsForPkgs(ctx context.Context, pkgs []*aur.Pkg, graph *topo.Graph[string, *InstallInfo]) {
 	for _, pkg := range pkgs {
 		g.addDepNodes(ctx, pkg, graph)
@@ -313,8 +283,8 @@ func (g *Grapher) addDepNodes(ctx context.Context, pkg *aur.Pkg, graph *topo.Gra
 	}
 }
 
-func (g *Grapher) GraphSyncPkg(ctx context.Context,
-	graph *topo.Graph[string, *InstallInfo],
+func GraphSyncPkg(ctx context.Context, dbExecutor db.Executor,
+	graph *topo.Graph[string, *InstallInfo], logger *text.Logger,
 	pkg alpm.IPackage, upgradeInfo *db.SyncUpgrade,
 ) *topo.Graph[string, *InstallInfo] {
 	if graph == nil {
@@ -323,7 +293,7 @@ func (g *Grapher) GraphSyncPkg(ctx context.Context,
 
 	graph.AddNode(pkg.Name())
 	_ = pkg.Provides().ForEach(func(p *alpm.Depend) error {
-		g.logger.Debugln(pkg.Name() + " provides: " + p.String())
+		logger.Debugln(pkg.Name() + " provides: " + p.String())
 		graph.Provides(p.Name, p, pkg.Name())
 		return nil
 	})
@@ -337,7 +307,7 @@ func (g *Grapher) GraphSyncPkg(ctx context.Context,
 	}
 
 	if upgradeInfo == nil {
-		if localPkg := g.dbExecutor.LocalPackage(pkg.Name()); localPkg != nil {
+		if localPkg := dbExecutor.LocalPackage(pkg.Name()); localPkg != nil {
 			info.Reason = Reason(localPkg.Reason())
 		}
 	} else {
@@ -346,7 +316,7 @@ func (g *Grapher) GraphSyncPkg(ctx context.Context,
 		info.LocalVersion = upgradeInfo.LocalVersion
 	}
 
-	g.ValidateAndSetNodeInfo(graph, pkg.Name(), &topo.NodeInfo[*InstallInfo]{
+	validateAndSetNodeInfo(graph, pkg.Name(), &topo.NodeInfo[*InstallInfo]{
 		Color:      colorMap[info.Reason],
 		Background: bgColorMap[info.Source],
 		Value:      info,
@@ -365,7 +335,7 @@ func (g *Grapher) GraphSyncGroup(ctx context.Context,
 
 	graph.AddNode(groupName)
 
-	g.ValidateAndSetNodeInfo(graph, groupName, &topo.NodeInfo[*InstallInfo]{
+	validateAndSetNodeInfo(graph, groupName, &topo.NodeInfo[*InstallInfo]{
 		Color:      colorMap[Explicit],
 		Background: bgColorMap[Sync],
 		Value: &InstallInfo{
@@ -392,7 +362,7 @@ func (g *Grapher) GraphAURTarget(ctx context.Context,
 
 	g.addAurPkgProvides(pkg, graph)
 
-	g.ValidateAndSetNodeInfo(graph, pkg.Name, &topo.NodeInfo[*InstallInfo]{
+	validateAndSetNodeInfo(graph, pkg.Name, &topo.NodeInfo[*InstallInfo]{
 		Color:      colorMap[instalInfo.Reason],
 		Background: bgColorMap[AUR],
 		Value:      instalInfo,
@@ -564,7 +534,7 @@ func (g *Grapher) findDepsFromAUR(ctx context.Context,
 	return pkgsToAdd
 }
 
-func (g *Grapher) ValidateAndSetNodeInfo(graph *topo.Graph[string, *InstallInfo],
+func validateAndSetNodeInfo(graph *topo.Graph[string, *InstallInfo],
 	node string, nodeInfo *topo.NodeInfo[*InstallInfo],
 ) {
 	info := graph.GetNodeInfo(node)
@@ -623,7 +593,7 @@ func (g *Grapher) addNodes(
 		}
 
 		if g.fullGraph {
-			g.ValidateAndSetNodeInfo(
+			validateAndSetNodeInfo(
 				graph,
 				depName,
 				&topo.NodeInfo[*InstallInfo]{Color: colorMap[depType], Background: bgColorMap[Local]})
@@ -648,7 +618,7 @@ func (g *Grapher) addNodes(
 		}
 
 		dbName := alpmPkg.DB().Name()
-		g.ValidateAndSetNodeInfo(
+		validateAndSetNodeInfo(
 			graph,
 			alpmPkg.Name(),
 			&topo.NodeInfo[*InstallInfo]{

+ 6 - 5
pkg/dep/dep_graph_test.go

@@ -19,6 +19,7 @@ import (
 	"github.com/Jguer/yay/v12/pkg/db/mock"
 	mockaur "github.com/Jguer/yay/v12/pkg/dep/mock"
 	aur "github.com/Jguer/yay/v12/pkg/query"
+	"github.com/Jguer/yay/v12/pkg/settings/exe"
 	"github.com/Jguer/yay/v12/pkg/text"
 )
 
@@ -200,7 +201,7 @@ func TestGrapher_GraphFromTargets_jellyfin(t *testing.T) {
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
 			g := NewGrapher(tt.fields.dbExecutor,
-				tt.fields.aurCache, false, true,
+				tt.fields.aurCache, &exe.MockBuilder{Runner: &exe.MockRunner{}}, false, true,
 				tt.fields.noDeps, tt.fields.noCheckDeps, false,
 				text.NewLogger(io.Discard, io.Discard, &os.File{}, true, "test"))
 			got, err := g.GraphFromTargets(context.Background(), nil, tt.args.targets)
@@ -314,7 +315,7 @@ func TestGrapher_GraphProvides_androidsdk(t *testing.T) {
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
 			g := NewGrapher(tt.fields.dbExecutor,
-				tt.fields.aurCache, false, true,
+				tt.fields.aurCache, &exe.MockBuilder{Runner: &exe.MockRunner{}}, false, true,
 				tt.fields.noDeps, tt.fields.noCheckDeps, false,
 				text.NewLogger(io.Discard, io.Discard, &os.File{}, true, "test"))
 			got, err := g.GraphFromTargets(context.Background(), nil, tt.args.targets)
@@ -517,7 +518,7 @@ func TestGrapher_GraphFromAUR_Deps_ceph_bin(t *testing.T) {
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
 			g := NewGrapher(mockDB, mockAUR,
-				false, true, false, false, false,
+				&exe.MockBuilder{Runner: &exe.MockRunner{}}, false, true, false, false, false,
 				text.NewLogger(io.Discard, io.Discard, &os.File{}, true, "test"))
 			got, err := g.GraphFromTargets(context.Background(), nil, tt.targets)
 			require.NoError(t, err)
@@ -661,7 +662,7 @@ func TestGrapher_GraphFromAUR_Deps_gourou(t *testing.T) {
 
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
-			g := NewGrapher(mockDB, mockAUR,
+			g := NewGrapher(mockDB, mockAUR, &exe.MockBuilder{Runner: &exe.MockRunner{}},
 				false, true, false, false, false,
 				text.NewLogger(io.Discard, io.Discard, &os.File{}, true, "test"))
 			got, err := g.GraphFromTargets(context.Background(), nil, tt.targets)
@@ -799,7 +800,7 @@ func TestGrapher_GraphFromTargets_ReinstalledDeps(t *testing.T) {
 
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
-			g := NewGrapher(mockDB, mockAUR,
+			g := NewGrapher(mockDB, mockAUR, &exe.MockBuilder{Runner: &exe.MockRunner{}},
 				false, true, false, false, false,
 				text.NewLogger(io.Discard, io.Discard, &os.File{}, true, "test"))
 			got, err := g.GraphFromTargets(context.Background(), nil, tt.targets)

+ 117 - 0
pkg/dep/srcinfo.go

@@ -0,0 +1,117 @@
+package dep
+
+import (
+	"context"
+	"errors"
+	"fmt"
+	"os"
+	"path/filepath"
+
+	aurc "github.com/Jguer/aur"
+	gosrc "github.com/Morganamilo/go-srcinfo"
+	"github.com/leonelquinteros/gotext"
+
+	"github.com/Jguer/yay/v12/pkg/dep/topo"
+	"github.com/Jguer/yay/v12/pkg/settings/exe"
+)
+
+var ErrNoBuildFiles = errors.New(gotext.Get("cannot find PKGBUILD and .SRCINFO in directory"))
+
+func (g *Grapher) GraphFromSrcInfoDirs(ctx context.Context, graph *topo.Graph[string, *InstallInfo],
+	srcInfosDirs []string,
+) (*topo.Graph[string, *InstallInfo], error) {
+	if graph == nil {
+		graph = NewGraph()
+	}
+
+	srcInfos := map[string]*gosrc.Srcinfo{}
+	for _, targetDir := range srcInfosDirs {
+		if err := srcinfoExists(ctx, g.cmdBuilder, targetDir); err != nil {
+			return nil, err
+		}
+
+		pkgbuild, err := gosrc.ParseFile(filepath.Join(targetDir, ".SRCINFO"))
+		if err != nil {
+			return nil, fmt.Errorf("%s: %w", gotext.Get("failed to parse .SRCINFO"), err)
+		}
+
+		srcInfos[targetDir] = pkgbuild
+	}
+
+	aurPkgsAdded := []*aurc.Pkg{}
+	for pkgBuildDir, pkgbuild := range srcInfos {
+		pkgBuildDir := pkgBuildDir
+
+		aurPkgs, err := makeAURPKGFromSrcinfo(g.dbExecutor, pkgbuild)
+		if err != nil {
+			return nil, err
+		}
+
+		if len(aurPkgs) > 1 {
+			var errPick error
+			aurPkgs, errPick = g.pickSrcInfoPkgs(aurPkgs)
+			if errPick != nil {
+				return nil, errPick
+			}
+		}
+
+		for _, pkg := range aurPkgs {
+			pkg := pkg
+
+			reason := Explicit
+			if pkg := g.dbExecutor.LocalPackage(pkg.Name); pkg != nil {
+				reason = Reason(pkg.Reason())
+			}
+
+			graph.AddNode(pkg.Name)
+
+			g.addAurPkgProvides(pkg, graph)
+
+			validateAndSetNodeInfo(graph, pkg.Name, &topo.NodeInfo[*InstallInfo]{
+				Color:      colorMap[reason],
+				Background: bgColorMap[AUR],
+				Value: &InstallInfo{
+					Source:      SrcInfo,
+					Reason:      reason,
+					SrcinfoPath: &pkgBuildDir,
+					AURBase:     &pkg.PackageBase,
+					Version:     pkg.Version,
+				},
+			})
+		}
+
+		aurPkgsAdded = append(aurPkgsAdded, aurPkgs...)
+	}
+
+	g.AddDepsForPkgs(ctx, aurPkgsAdded, graph)
+
+	return graph, nil
+}
+
+func srcinfoExists(ctx context.Context,
+	cmdBuilder exe.ICmdBuilder, targetDir string,
+) error {
+	srcInfoDir := filepath.Join(targetDir, ".SRCINFO")
+	pkgbuildDir := filepath.Join(targetDir, "PKGBUILD")
+	if _, err := os.Stat(srcInfoDir); err == nil {
+		if _, err := os.Stat(pkgbuildDir); err == nil {
+			return nil
+		}
+	}
+
+	if _, err := os.Stat(pkgbuildDir); err == nil {
+		// run makepkg to generate .SRCINFO
+		srcinfo, stderr, err := cmdBuilder.Capture(cmdBuilder.BuildMakepkgCmd(ctx, targetDir, "--printsrcinfo"))
+		if err != nil {
+			return fmt.Errorf("unable to generate .SRCINFO: %w - %s", err, stderr)
+		}
+
+		if err := os.WriteFile(srcInfoDir, []byte(srcinfo), 0o600); err != nil {
+			return fmt.Errorf("unable to write .SRCINFO: %w", err)
+		}
+
+		return nil
+	}
+
+	return fmt.Errorf("%w: %s", ErrNoBuildFiles, targetDir)
+}

+ 1 - 1
pkg/upgrade/service.go

@@ -173,7 +173,7 @@ func (u *UpgradeService) upGraph(ctx context.Context, graph *topo.Graph[string,
 			}
 
 			upgradeInfo := up
-			graph = u.grapher.GraphSyncPkg(ctx, graph, up.Package, &upgradeInfo)
+			graph = dep.GraphSyncPkg(ctx, u.dbExecutor, graph, u.log, up.Package, &upgradeInfo)
 		}
 
 		errs.Add(err)

+ 6 - 5
pkg/upgrade/service_test.go

@@ -21,6 +21,7 @@ import (
 	"github.com/Jguer/yay/v12/pkg/dep/topo"
 	"github.com/Jguer/yay/v12/pkg/query"
 	"github.com/Jguer/yay/v12/pkg/settings"
+	"github.com/Jguer/yay/v12/pkg/settings/exe"
 	"github.com/Jguer/yay/v12/pkg/settings/parser"
 	"github.com/Jguer/yay/v12/pkg/text"
 	"github.com/Jguer/yay/v12/pkg/vcs"
@@ -338,7 +339,7 @@ func TestUpgradeService_GraphUpgrades(t *testing.T) {
 	}
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
-			grapher := dep.NewGrapher(dbExe, mockAUR,
+			grapher := dep.NewGrapher(dbExe, mockAUR, &exe.MockBuilder{Runner: &exe.MockRunner{}},
 				false, true, false, false, false, text.NewLogger(tt.fields.output, os.Stderr,
 					tt.fields.input, true, "test"))
 
@@ -520,7 +521,7 @@ func TestUpgradeService_GraphUpgradesMissingDep(t *testing.T) {
 	}
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
-			grapher := dep.NewGrapher(dbExe, mockAUR,
+			grapher := dep.NewGrapher(dbExe, mockAUR, &exe.MockBuilder{Runner: &exe.MockRunner{}},
 				false, true, false, false, false, text.NewLogger(tt.fields.output, os.Stderr,
 					tt.fields.input, true, "test"))
 
@@ -641,7 +642,7 @@ func TestUpgradeService_GraphUpgradesNoUpdates(t *testing.T) {
 	}
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
-			grapher := dep.NewGrapher(dbExe, mockAUR,
+			grapher := dep.NewGrapher(dbExe, mockAUR, &exe.MockBuilder{Runner: &exe.MockRunner{}},
 				false, true, false, false, false, text.NewLogger(tt.fields.output, os.Stderr,
 					tt.fields.input, true, "test"))
 
@@ -756,7 +757,7 @@ func TestUpgradeService_Warnings(t *testing.T) {
 
 	logger := text.NewLogger(io.Discard, os.Stderr,
 		strings.NewReader("\n"), true, "test")
-	grapher := dep.NewGrapher(dbExe, mockAUR,
+	grapher := dep.NewGrapher(dbExe, mockAUR, &exe.MockBuilder{Runner: &exe.MockRunner{}},
 		false, true, false, false, false, logger)
 
 	cfg := &settings.Configuration{
@@ -926,7 +927,7 @@ func TestUpgradeService_GraphUpgrades_zfs_dkms(t *testing.T) {
 
 			logger := text.NewLogger(io.Discard, os.Stderr,
 				tt.fields.input, true, "test")
-			grapher := dep.NewGrapher(dbExe, mockAUR,
+			grapher := dep.NewGrapher(dbExe, mockAUR, &exe.MockBuilder{Runner: &exe.MockRunner{}},
 				false, true, false, false, false, logger)
 
 			cfg := &settings.Configuration{

+ 1 - 1
print.go

@@ -133,7 +133,7 @@ func printUpdateList(ctx context.Context, run *runtime.Runtime, cmdArgs *parser.
 	defer func() { settings.NoConfirm = oldNoConfirm }()
 
 	targets := mapset.NewThreadUnsafeSet(cmdArgs.Targets...)
-	grapher := dep.NewGrapher(dbExecutor, run.AURClient, false, true,
+	grapher := dep.NewGrapher(dbExecutor, run.AURClient, run.CmdBuilder, false, true,
 		false, false, cmdArgs.ExistsArg("needed"), logger.Child("grapher"))
 
 	upService := upgrade.NewUpgradeService(

+ 1 - 1
sync.go

@@ -43,7 +43,7 @@ func syncInstall(ctx context.Context,
 		}
 	}
 
-	grapher := dep.NewGrapher(dbExecutor, aurCache, false, settings.NoConfirm,
+	grapher := dep.NewGrapher(dbExecutor, aurCache, run.CmdBuilder, false, settings.NoConfirm,
 		noDeps, noCheck, cmdArgs.ExistsArg("needed"), run.Logger.Child("grapher"))
 
 	graph, err := grapher.GraphFromTargets(ctx, nil, cmdArgs.Targets)