diff --git a/aur_source.go b/aur_source.go index 271ac7e4..cd9f8063 100644 --- a/aur_source.go +++ b/aur_source.go @@ -3,7 +3,6 @@ package main import ( "context" "fmt" - "path/filepath" "runtime" "sync" @@ -11,7 +10,6 @@ import ( "github.com/Jguer/yay/v11/pkg/multierror" "github.com/Jguer/yay/v11/pkg/settings/exe" - "github.com/Jguer/yay/v11/pkg/stringset" "github.com/Jguer/yay/v11/pkg/text" ) @@ -30,50 +28,49 @@ func (e *ErrDownloadSource) Unwrap() error { return e.inner } -func downloadPKGBUILDSource(ctx context.Context, cmdBuilder exe.ICmdBuilder, dest, - base string, incompatible stringset.StringSet, +func downloadPKGBUILDSource(ctx context.Context, + cmdBuilder exe.ICmdBuilder, pkgBuildDir string, installIncompatible bool, ) error { - dir := filepath.Join(dest, base) args := []string{"--verifysource", "-Ccf"} - if incompatible.Get(base) { + if installIncompatible { args = append(args, "--ignorearch") } err := cmdBuilder.Show( - cmdBuilder.BuildMakepkgCmd(ctx, dir, args...)) + cmdBuilder.BuildMakepkgCmd(ctx, pkgBuildDir, args...)) if err != nil { - return ErrDownloadSource{inner: err, pkgName: base, errOut: ""} + return ErrDownloadSource{inner: err} } return nil } -func downloadPKGBUILDSourceWorker(ctx context.Context, wg *sync.WaitGroup, dest string, - cBase <-chan string, valOut chan<- string, errOut chan<- error, - cmdBuilder exe.ICmdBuilder, incompatible stringset.StringSet, +func downloadPKGBUILDSourceWorker(ctx context.Context, wg *sync.WaitGroup, + dirChannel <-chan string, valOut chan<- string, errOut chan<- error, + cmdBuilder exe.ICmdBuilder, incompatible bool, ) { - for base := range cBase { - err := downloadPKGBUILDSource(ctx, cmdBuilder, dest, base, incompatible) + for pkgBuildDir := range dirChannel { + err := downloadPKGBUILDSource(ctx, cmdBuilder, pkgBuildDir, incompatible) if err != nil { - errOut <- ErrDownloadSource{inner: err, pkgName: base, errOut: ""} + errOut <- ErrDownloadSource{inner: err, pkgName: pkgBuildDir, errOut: ""} } else { - valOut <- base + valOut <- pkgBuildDir } } wg.Done() } -func downloadPKGBUILDSourceFanout(ctx context.Context, cmdBuilder exe.ICmdBuilder, dest string, - bases []string, incompatible stringset.StringSet, maxConcurrentDownloads int, +func downloadPKGBUILDSourceFanout(ctx context.Context, cmdBuilder exe.ICmdBuilder, pkgBuildDirs []string, + incompatible bool, maxConcurrentDownloads int, ) error { - if len(bases) == 0 { + if len(pkgBuildDirs) == 0 { return nil // no work to do } - if len(bases) == 1 { - return downloadPKGBUILDSource(ctx, cmdBuilder, dest, bases[0], incompatible) + if len(pkgBuildDirs) == 1 { + return downloadPKGBUILDSource(ctx, cmdBuilder, pkgBuildDirs[0], incompatible) } var ( @@ -89,8 +86,8 @@ func downloadPKGBUILDSourceFanout(ctx context.Context, cmdBuilder exe.ICmdBuilde } go func() { - for _, base := range bases { - c <- base + for _, pkgbuildDir := range pkgBuildDirs { + c <- pkgbuildDir } close(c) @@ -100,7 +97,7 @@ func downloadPKGBUILDSourceFanout(ctx context.Context, cmdBuilder exe.ICmdBuilde wg.Add(numOfWorkers) for s := 0; s < numOfWorkers; s++ { - go downloadPKGBUILDSourceWorker(ctx, wg, dest, c, + go downloadPKGBUILDSourceWorker(ctx, wg, c, fanInChanValues, fanInChanErrors, cmdBuilder, incompatible) } diff --git a/aur_source_test.go b/aur_source_test.go index 623f05a2..79612fca 100644 --- a/aur_source_test.go +++ b/aur_source_test.go @@ -4,6 +4,7 @@ import ( "context" "fmt" "os/exec" + "path/filepath" "sync/atomic" "testing" @@ -11,7 +12,6 @@ import ( "github.com/Jguer/yay/v11/pkg/multierror" "github.com/Jguer/yay/v11/pkg/settings/exe" - "github.com/Jguer/yay/v11/pkg/stringset" ) type TestMakepkgBuilder struct { @@ -53,7 +53,7 @@ func Test_downloadPKGBUILDSource(t *testing.T) { want: "makepkg --nocheck --config /etc/not.conf --verifysource -Ccf", wantDir: "/tmp/yay-bin", } - err := downloadPKGBUILDSource(context.TODO(), cmdBuilder, "/tmp", "yay-bin", stringset.Make()) + err := downloadPKGBUILDSource(context.TODO(), cmdBuilder, filepath.Join("/tmp", "yay-bin"), false) assert.NoError(t, err) assert.Equal(t, 1, int(cmdBuilder.passes)) } @@ -70,7 +70,7 @@ func Test_downloadPKGBUILDSourceError(t *testing.T) { wantDir: "/tmp/yay-bin", showError: &exec.ExitError{}, } - err := downloadPKGBUILDSource(context.TODO(), cmdBuilder, "/tmp", "yay-bin", stringset.Make()) + err := downloadPKGBUILDSource(context.TODO(), cmdBuilder, filepath.Join("/tmp", "yay-bin"), false) assert.Error(t, err) assert.EqualError(t, err, "error downloading sources: \x1b[36myay-bin\x1b[0m \n\t context: \n\t \n") } @@ -81,7 +81,7 @@ func Test_downloadPKGBUILDSourceError(t *testing.T) { func Test_downloadPKGBUILDSourceFanout(t *testing.T) { t.Parallel() - bases := []string{"yay", "yay-bin", "yay-git", "yay-v11", "yay-v12"} + pkgBuildDirs := []string{"/tmp/yay", "/tmp/yay-bin", "/tmp/yay-git", "/tmp/yay-v11", "/tmp/yay-v12"} for _, maxConcurrentDownloads := range []int{0, 3} { t.Run(fmt.Sprintf("maxconcurrentdownloads set to %d", maxConcurrentDownloads), func(t *testing.T) { cmdBuilder := &TestMakepkgBuilder{ @@ -92,7 +92,7 @@ func Test_downloadPKGBUILDSourceFanout(t *testing.T) { test: t, } - err := downloadPKGBUILDSourceFanout(context.TODO(), cmdBuilder, "/tmp", bases, stringset.Make(), maxConcurrentDownloads) + err := downloadPKGBUILDSourceFanout(context.TODO(), cmdBuilder, pkgBuildDirs, false, maxConcurrentDownloads) assert.NoError(t, err) assert.Equal(t, 5, int(cmdBuilder.passes)) }) @@ -112,9 +112,9 @@ func Test_downloadPKGBUILDSourceFanoutNoCC(t *testing.T) { test: t, } - bases := []string{"yay"} + pkgBuildDirs := []string{"/tmp/yay"} - err := downloadPKGBUILDSourceFanout(context.TODO(), cmdBuilder, "/tmp", bases, stringset.Make(), 0) + err := downloadPKGBUILDSourceFanout(context.TODO(), cmdBuilder, pkgBuildDirs, false, 0) assert.NoError(t, err) assert.Equal(t, 1, int(cmdBuilder.passes)) } @@ -133,15 +133,15 @@ func Test_downloadPKGBUILDSourceFanoutError(t *testing.T) { showError: &exec.ExitError{}, } - bases := []string{ - "yay", - "yay-bin", - "yay-git", - "yay-v11", - "yay-v12", + pkgBuildDirs := []string{ + "/tmp/yay", + "/tmp/yay-bin", + "/tmp/yay-git", + "/tmp/yay-v11", + "/tmp/yay-v12", } - err := downloadPKGBUILDSourceFanout(context.TODO(), cmdBuilder, "/tmp", bases, stringset.Make(), 0) + err := downloadPKGBUILDSourceFanout(context.TODO(), cmdBuilder, pkgBuildDirs, false, 0) assert.Error(t, err) assert.Equal(t, 5, int(cmdBuilder.passes)) assert.Len(t, err.(*multierror.MultiError).Errors, 5) diff --git a/go.mod b/go.mod index be50faba..be1b0618 100644 --- a/go.mod +++ b/go.mod @@ -27,6 +27,7 @@ require ( require github.com/tidwall/gjson v1.14.3 require ( + github.com/deckarep/golang-set/v2 v2.1.0 github.com/itchyny/gojq v0.12.8 github.com/itchyny/timefmt-go v0.1.3 // indirect github.com/ohler55/ojg v1.14.4 diff --git a/go.sum b/go.sum index 2b3c5448..7203fc29 100644 --- a/go.sum +++ b/go.sum @@ -17,6 +17,8 @@ github.com/bradleyjkemp/cupaloy v2.3.0+incompatible/go.mod h1:Au1Xw1sgaJ5iSFktEh github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/deckarep/golang-set/v2 v2.1.0 h1:g47V4Or+DUdzbs8FxCCmgb6VYd+ptPAngjM6dtGktsI= +github.com/deckarep/golang-set/v2 v2.1.0/go.mod h1:VAky9rY/yGXJOLEDv3OMci+7wtDpOF4IN+y82NBOac4= github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542 h1:2VTzZjLZBgl62/EtslCrtky5vbi9dd7HrQPQIx6wqiw= github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542/go.mod h1:Ow0tF8D4Kplbc8s8sSb3V2oUCygFHVp8gC3Dn6U4MNI= diff --git a/install.go b/install.go index 24a2c577..5582702a 100644 --- a/install.go +++ b/install.go @@ -331,12 +331,16 @@ func install(ctx context.Context, cmdArgs *parser.Arguments, dbExecutor db.Execu }() bases := make([]string, 0, len(do.Aur)) + pkgBuildDirs := make([]string, 0, len(do.Aur)) for _, base := range do.Aur { bases = append(bases, base.Pkgbase()) + pkgBuildDirs = append(pkgBuildDirs, filepath.Join(config.BuildDir, base.Pkgbase())) } - if errP := downloadPKGBUILDSourceFanout(ctx, config.Runtime.CmdBuilder, config.BuildDir, - bases, incompatible, config.MaxConcurrentDownloads); errP != nil { + if errP := downloadPKGBUILDSourceFanout(ctx, + config.Runtime.CmdBuilder, + pkgBuildDirs, + len(incompatible) > 0, config.MaxConcurrentDownloads); errP != nil { text.Errorln(errP) } @@ -589,18 +593,6 @@ func buildInstallPkgbuilds( incompatible stringset.StringSet, conflicts stringset.MapStringSet, noDeps, noCheck bool, ) error { - arguments := cmdArgs.Copy() - arguments.ClearTargets() - arguments.Op = "U" - arguments.DelArg("confirm") - arguments.DelArg("noconfirm") - arguments.DelArg("c", "clean") - arguments.DelArg("q", "quiet") - arguments.DelArg("q", "quiet") - arguments.DelArg("y", "refresh") - arguments.DelArg("u", "sysupgrade") - arguments.DelArg("w", "downloadonly") - deps := make([]string, 0) exp := make([]string, 0) oldConfirm := settings.NoConfirm @@ -636,8 +628,7 @@ func buildInstallPkgbuilds( } if !satisfied || !config.BatchInstall { - err = doInstall(ctx, arguments, cmdArgs, deps, exp) - arguments.ClearTargets() + err = doInstall(ctx, cmdArgs, deps, exp) deps = make([]string, 0) exp = make([]string, 0) @@ -755,7 +746,7 @@ func buildInstallPkgbuilds( for _, split := range base { for suffix, optional := range map[string]bool{"": false, "-debug": true} { deps, exp, errAdd = doAddTarget(dp, localNamesCache, remoteNamesCache, - arguments, cmdArgs, pkgdests, deps, exp, split.Name+suffix, optional) + cmdArgs, pkgdests, deps, exp, split.Name+suffix, optional) if errAdd != nil { return errAdd } @@ -776,7 +767,7 @@ func buildInstallPkgbuilds( wg.Wait() } - err = doInstall(ctx, arguments, cmdArgs, deps, exp) + err = doInstall(ctx, cmdArgs, deps, exp) if err != nil { go config.Runtime.VCSStore.RemovePackage([]string{do.Aur[len(do.Aur)-1].String()}) } @@ -786,11 +777,26 @@ func buildInstallPkgbuilds( return err } -func doInstall(ctx context.Context, arguments, cmdArgs *parser.Arguments, pkgDeps, pkgExp []string) error { - if len(arguments.Targets) == 0 { +func doInstall(ctx context.Context, cmdArgs *parser.Arguments, pkgDeps, pkgExp []string) error { + arguments := cmdArgs.Copy() + arguments.ClearTargets() + arguments.Op = "U" + arguments.DelArg("confirm") + arguments.DelArg("noconfirm") + arguments.DelArg("c", "clean") + arguments.DelArg("q", "quiet") + arguments.DelArg("q", "quiet") + arguments.DelArg("y", "refresh") + arguments.DelArg("u", "sysupgrade") + arguments.DelArg("w", "downloadonly") + + if len(pkgDeps)+len(pkgExp) == 0 { return nil } + arguments.AddTarget(pkgDeps...) + arguments.AddTarget(pkgExp...) + if errShow := config.Runtime.CmdBuilder.Show(config.Runtime.CmdBuilder.BuildPacmanCmd(ctx, arguments, config.Runtime.Mode, settings.NoConfirm)); errShow != nil { return errShow @@ -808,7 +814,7 @@ func doInstall(ctx context.Context, arguments, cmdArgs *parser.Arguments, pkgDep } func doAddTarget(dp *dep.Pool, localNamesCache, remoteNamesCache stringset.StringSet, - arguments, cmdArgs *parser.Arguments, pkgdests map[string]string, + cmdArgs *parser.Arguments, pkgdests map[string]string, deps, exp []string, name string, optional bool, ) (newDeps, newExp []string, err error) { pkgdest, ok := pkgdests[name] @@ -831,8 +837,6 @@ func doAddTarget(dp *dep.Pool, localNamesCache, remoteNamesCache stringset.Strin name, pkgdest)) } - arguments.AddTarget(pkgdest) - switch { case cmdArgs.ExistsArg("asdeps", "asdep"): deps = append(deps, name) @@ -840,6 +844,8 @@ func doAddTarget(dp *dep.Pool, localNamesCache, remoteNamesCache stringset.Strin exp = append(exp, name) case !dp.Explicit.Get(name) && !localNamesCache.Get(name) && !remoteNamesCache.Get(name): deps = append(deps, name) + default: + exp = append(exp, name) } return deps, exp, nil diff --git a/local_install.go b/local_install.go index 8794b34a..ac80d126 100644 --- a/local_install.go +++ b/local_install.go @@ -15,9 +15,12 @@ import ( "github.com/Jguer/yay/v11/pkg/settings" "github.com/Jguer/yay/v11/pkg/settings/exe" "github.com/Jguer/yay/v11/pkg/settings/parser" - gosrc "github.com/Morganamilo/go-srcinfo" + "github.com/Jguer/yay/v11/pkg/text" "github.com/leonelquinteros/gotext" "github.com/pkg/errors" + + gosrc "github.com/Morganamilo/go-srcinfo" + mapset "github.com/deckarep/golang-set/v2" ) var ErrInstallRepoPkgs = errors.New(gotext.Get("error installing repo packages")) @@ -52,7 +55,7 @@ func installLocalPKGBUILD( grapher := dep.NewGrapher(dbExecutor, aurCache, false, settings.NoConfirm, os.Stdout) - graph, err := grapher.GraphFromSrcInfo(pkgbuild) + graph, err := grapher.GraphFromSrcInfo(wd, pkgbuild) if err != nil { return err } @@ -71,9 +74,10 @@ func installLocalPKGBUILD( } type Preparer struct { - dbExecutor db.Executor - cmdBuilder exe.ICmdBuilder - aurBases []string + dbExecutor db.Executor + cmdBuilder exe.ICmdBuilder + aurBases []string + pkgBuildDirs []string } func (preper *Preparer) PrepareWorkspace(ctx context.Context, targets []map[string]*dep.InstallInfo, @@ -82,16 +86,22 @@ func (preper *Preparer) PrepareWorkspace(ctx context.Context, targets []map[stri for pkgBase, info := range layer { if info.Source == dep.AUR { preper.aurBases = append(preper.aurBases, pkgBase) + preper.pkgBuildDirs = append(preper.pkgBuildDirs, filepath.Join(config.BuildDir, pkgBase)) + } else if info.Source == dep.SrcInfo { + preper.pkgBuildDirs = append(preper.pkgBuildDirs, *info.SrcinfoPath) } } } - _, errA := download.AURPKGBUILDRepos(ctx, - preper.cmdBuilder, preper.aurBases, config.AURURL, config.BuildDir, false) - if errA != nil { + if _, errA := download.AURPKGBUILDRepos(ctx, + preper.cmdBuilder, preper.aurBases, config.AURURL, config.BuildDir, false); errA != nil { return errA } + if errP := downloadPKGBUILDSourceFanout(ctx, config.Runtime.CmdBuilder, + preper.pkgBuildDirs, false, config.MaxConcurrentDownloads); errP != nil { + text.Errorln(errP) + } return nil } @@ -144,9 +154,28 @@ func (installer *Installer) handleLayer(ctx context.Context, cmdArgs *parser.Arg syncDeps, syncExp := make([]string, 0), make([]string, 0) repoTargets := make([]string, 0) + aurDeps, aurExp := mapset.NewSet[string](), mapset.NewSet[string]() for source, reasons := range depByTypeAndReason { switch source { case dep.AUR: + for reason, names := range reasons { + for _, name := range names { + switch reason { + case dep.Explicit: + if cmdArgs.ExistsArg("asdeps", "asdep") { + aurDeps.Add(name) + } else { + aurExp.Add(name) + } + case dep.CheckDep: + fallthrough + case dep.MakeDep: + fallthrough + case dep.Dep: + aurDeps.Add(name) + } + } + } case dep.Sync: for reason, names := range reasons { switch reason { @@ -171,7 +200,7 @@ func (installer *Installer) handleLayer(ctx context.Context, cmdArgs *parser.Arg fmt.Println(syncDeps, syncExp) - errShow := installer.installRepoPackages(ctx, cmdArgs, repoTargets, syncDeps, syncExp) + errShow := installer.installSyncPackages(ctx, cmdArgs, repoTargets, syncDeps, syncExp) if errShow != nil { return ErrInstallRepoPkgs } @@ -179,7 +208,86 @@ func (installer *Installer) handleLayer(ctx context.Context, cmdArgs *parser.Arg return nil } -func (*Installer) installRepoPackages(ctx context.Context, cmdArgs *parser.Arguments, +func (*Installer) installAURPackages(ctx context.Context, cmdArgs *parser.Arguments, aurBaseDeps, aurBaseExp mapset.Set[string], pkgBuildDirs map[string]string, installIncompatible bool) error { + deps, exp := make([]string, 0, aurBaseDeps.Cardinality()), make([]string, 0, aurBaseExp.Cardinality()) + for _, base := range aurBaseDeps.Union(aurBaseExp).ToSlice() { + dir := pkgBuildDirs[base] + args := []string{"--nobuild", "-fC"} + + if installIncompatible { + args = append(args, "--ignorearch") + } + + // pkgver bump + if err := config.Runtime.CmdBuilder.Show( + config.Runtime.CmdBuilder.BuildMakepkgCmd(ctx, dir, args...)); err != nil { + return errors.New(gotext.Get("error making: %s", base)) + } + + pkgdests, _, errList := parsePackageList(ctx, dir) + if errList != nil { + return errList + } + + args = []string{"-cf", "--noconfirm", "--noextract", "--noprepare", "--holdver"} + + if installIncompatible { + args = append(args, "--ignorearch") + } + + if errMake := config.Runtime.CmdBuilder.Show( + config.Runtime.CmdBuilder.BuildMakepkgCmd(ctx, + dir, args...)); errMake != nil { + return errors.New(gotext.Get("error making: %s", base)) + } + + for suffix, optional := range map[string]bool{"": false, "-debug": true} { + newDeps, newExp, err := getNewTargets(cmdArgs, pkgdests, base+suffix, aurBaseDeps.Contains(base), optional) + if err != nil { + return err + } + deps = append(deps, newDeps...) + exp = append(exp, newExp...) + } + } + + if err := doInstall(ctx, cmdArgs, deps, exp); err != nil { + return errors.New(fmt.Sprintf(gotext.Get("error installing:")+" %v %v", deps, exp)) + } + + return nil +} + +func getNewTargets(cmdArgs *parser.Arguments, pkgdests map[string]string, name string, isDep, optional bool, +) (deps, exp []string, err error) { + for pkgName, pkgDest := range pkgdests { + if _, errStat := os.Stat(pkgDest); os.IsNotExist(errStat) { + if optional { + continue + } + + return deps, exp, errors.New( + gotext.Get( + "the PKGDEST for %s is listed by makepkg but does not exist: %s", + pkgName, pkgDest)) + } + + switch { + case cmdArgs.ExistsArg("asdeps", "asdep"): + deps = append(deps, name) + case cmdArgs.ExistsArg("asexplicit", "asexp"): + exp = append(exp, name) + case isDep: + deps = append(deps, name) + default: + exp = append(exp, name) + } + } + + return deps, exp, nil +} + +func (*Installer) installSyncPackages(ctx context.Context, cmdArgs *parser.Arguments, repoTargets, // all repo targets syncDeps, // repo targets that are deps syncExp []string, // repo targets that are exp @@ -191,6 +299,7 @@ func (*Installer) installRepoPackages(ctx context.Context, cmdArgs *parser.Argum arguments.Op = "S" arguments.ClearTargets() arguments.AddTarget(repoTargets...) + errShow := config.Runtime.CmdBuilder.Show(config.Runtime.CmdBuilder.BuildPacmanCmd(ctx, arguments, config.Runtime.Mode, settings.NoConfirm)) diff --git a/pkg/dep/depGraph.go b/pkg/dep/depGraph.go index c9cfa59d..9dbad973 100644 --- a/pkg/dep/depGraph.go +++ b/pkg/dep/depGraph.go @@ -17,8 +17,9 @@ import ( ) type InstallInfo struct { - Source Source - Reason Reason + Source Source + Reason Reason + SrcinfoPath *string } func (i *InstallInfo) String() string { @@ -100,7 +101,7 @@ func NewGrapher(dbExecutor db.Executor, aurCache *metadata.AURCache, fullGraph, } } -func (g *Grapher) GraphFromSrcInfo(pkgbuild *gosrc.Srcinfo) (*topo.Graph[string, *InstallInfo], error) { +func (g *Grapher) GraphFromSrcInfo(pkgBuildDir string, pkgbuild *gosrc.Srcinfo) (*topo.Graph[string, *InstallInfo], error) { graph := topo.New[string, *InstallInfo]() aurPkgs, err := makeAURPKGFromSrcinfo(g.dbExecutor, pkgbuild) @@ -119,8 +120,9 @@ func (g *Grapher) GraphFromSrcInfo(pkgbuild *gosrc.Srcinfo) (*topo.Graph[string, Color: colorMap[Explicit], Background: bgColorMap[AUR], Value: &InstallInfo{ - Source: SrcInfo, - Reason: Explicit, + Source: SrcInfo, + Reason: Explicit, + SrcinfoPath: &pkgBuildDir, }, })