yay/local_install.go

320 lines
8.2 KiB
Go
Raw Normal View History

2022-09-09 20:57:18 +02:00
// Experimental code for install local with dependency refactoring
// Not at feature parity with install.go
2022-08-21 07:14:52 +02:00
package main
import (
"context"
2022-09-06 23:38:47 +02:00
"fmt"
2022-08-22 23:28:53 +02:00
"os"
"path/filepath"
2022-08-21 07:14:52 +02:00
"github.com/Jguer/yay/v11/pkg/db"
2022-08-22 23:28:53 +02:00
"github.com/Jguer/yay/v11/pkg/dep"
2022-09-09 20:57:18 +02:00
"github.com/Jguer/yay/v11/pkg/download"
2022-09-04 23:45:40 +02:00
"github.com/Jguer/yay/v11/pkg/metadata"
2022-09-06 23:38:47 +02:00
"github.com/Jguer/yay/v11/pkg/settings"
2022-09-09 20:57:18 +02:00
"github.com/Jguer/yay/v11/pkg/settings/exe"
2022-08-21 07:14:52 +02:00
"github.com/Jguer/yay/v11/pkg/settings/parser"
2022-09-11 23:15:31 +02:00
"github.com/Jguer/yay/v11/pkg/text"
2022-08-22 23:28:53 +02:00
"github.com/leonelquinteros/gotext"
"github.com/pkg/errors"
2022-09-11 23:15:31 +02:00
gosrc "github.com/Morganamilo/go-srcinfo"
mapset "github.com/deckarep/golang-set/v2"
2022-08-21 07:14:52 +02:00
)
2022-09-09 20:57:18 +02:00
var ErrInstallRepoPkgs = errors.New(gotext.Get("error installing repo packages"))
2022-08-21 07:14:52 +02:00
func installLocalPKGBUILD(
ctx context.Context,
cmdArgs *parser.Arguments,
dbExecutor db.Executor,
) error {
2022-09-06 23:38:47 +02:00
aurCache, err := metadata.NewAURCache(filepath.Join(config.BuildDir, "aur.json"))
2022-09-04 23:45:40 +02:00
if err != nil {
return errors.Wrap(err, gotext.Get("failed to retrieve aur Cache"))
}
2022-08-22 23:28:53 +02:00
wd, err := os.Getwd()
if err != nil {
return errors.Wrap(err, gotext.Get("failed to retrieve working directory"))
}
if len(cmdArgs.Targets) > 1 {
return errors.New(gotext.Get("only one target is allowed"))
}
if len(cmdArgs.Targets) == 1 {
wd = cmdArgs.Targets[0]
}
pkgbuild, err := gosrc.ParseFile(filepath.Join(wd, ".SRCINFO"))
if err != nil {
return errors.Wrap(err, gotext.Get("failed to parse .SRCINFO"))
}
2022-09-06 23:38:47 +02:00
grapher := dep.NewGrapher(dbExecutor, aurCache, false, settings.NoConfirm, os.Stdout)
2022-09-11 23:15:31 +02:00
graph, err := grapher.GraphFromSrcInfo(wd, pkgbuild)
2022-08-22 23:28:53 +02:00
if err != nil {
return err
}
2022-09-09 17:38:48 +02:00
topoSorted := graph.TopoSortedLayerMap()
2022-09-07 00:01:23 +02:00
fmt.Println(topoSorted, len(topoSorted))
2022-08-22 23:28:53 +02:00
2022-09-09 20:57:18 +02:00
preparer := &Preparer{dbExecutor: dbExecutor, cmdBuilder: config.Runtime.CmdBuilder}
2022-09-09 17:38:48 +02:00
installer := &Installer{dbExecutor: dbExecutor}
2022-09-12 00:10:19 +02:00
pkgBuildDirs, err := preparer.PrepareWorkspace(ctx, topoSorted)
if err != nil {
2022-09-09 20:57:18 +02:00
return err
}
2022-09-12 00:10:19 +02:00
return installer.Install(ctx, cmdArgs, topoSorted, pkgBuildDirs)
2022-09-09 20:57:18 +02:00
}
type Preparer struct {
2022-09-11 23:15:31 +02:00
dbExecutor db.Executor
cmdBuilder exe.ICmdBuilder
aurBases []string
pkgBuildDirs []string
2022-09-09 20:57:18 +02:00
}
func (preper *Preparer) PrepareWorkspace(ctx context.Context, targets []map[string]*dep.InstallInfo,
2022-09-12 00:10:19 +02:00
) (map[string]string, error) {
pkgBuildDirs := make(map[string]string, 0)
2022-09-09 20:57:18 +02:00
for _, layer := range targets {
for pkgBase, info := range layer {
if info.Source == dep.AUR {
preper.aurBases = append(preper.aurBases, pkgBase)
2022-09-12 00:10:19 +02:00
pkgBuildDirs[pkgBase] = filepath.Join(config.BuildDir, pkgBase)
2022-09-11 23:15:31 +02:00
} else if info.Source == dep.SrcInfo {
2022-09-12 00:10:19 +02:00
pkgBuildDirs[pkgBase] = *info.SrcinfoPath
2022-09-09 20:57:18 +02:00
}
}
}
2022-09-11 23:15:31 +02:00
if _, errA := download.AURPKGBUILDRepos(ctx,
preper.cmdBuilder, preper.aurBases, config.AURURL, config.BuildDir, false); errA != nil {
2022-09-12 00:10:19 +02:00
return nil, errA
2022-09-09 20:57:18 +02:00
}
2022-09-09 17:38:48 +02:00
2022-09-11 23:15:31 +02:00
if errP := downloadPKGBUILDSourceFanout(ctx, config.Runtime.CmdBuilder,
preper.pkgBuildDirs, false, config.MaxConcurrentDownloads); errP != nil {
text.Errorln(errP)
}
2022-09-12 00:10:19 +02:00
return pkgBuildDirs, nil
2022-09-09 17:38:48 +02:00
}
type Installer struct {
dbExecutor db.Executor
}
2022-09-12 00:10:19 +02:00
func (installer *Installer) Install(ctx context.Context,
cmdArgs *parser.Arguments,
targets []map[string]*dep.InstallInfo,
pkgBuildDirs map[string]string,
) error {
2022-09-09 17:38:48 +02:00
// Reorganize targets into layers of dependencies
for i := len(targets) - 1; i >= 0; i-- {
2022-09-12 00:10:19 +02:00
err := installer.handleLayer(ctx, cmdArgs, targets[i], pkgBuildDirs)
2022-09-09 17:38:48 +02:00
if err != nil {
// rollback
return err
}
}
return nil
}
2022-09-12 00:10:19 +02:00
func (installer *Installer) handleLayer(ctx context.Context,
cmdArgs *parser.Arguments, layer map[string]*dep.InstallInfo, pkgBuildDirs map[string]string,
) error {
2022-09-09 17:38:48 +02:00
// Install layer
2022-09-17 14:31:54 +02:00
nameToBaseMap := make(map[string]string, 0)
syncDeps, syncExp := mapset.NewThreadUnsafeSet[string](), mapset.NewThreadUnsafeSet[string]()
aurDeps, aurExp := mapset.NewThreadUnsafeSet[string](), mapset.NewThreadUnsafeSet[string]()
2022-09-09 17:38:48 +02:00
for name, info := range layer {
2022-09-17 14:31:54 +02:00
switch info.Source {
2022-09-12 00:10:19 +02:00
case dep.SrcInfo:
fallthrough
2022-09-09 20:57:18 +02:00
case dep.AUR:
2022-09-17 14:31:54 +02:00
nameToBaseMap[name] = *info.AURBase
switch info.Reason {
case dep.Explicit:
if cmdArgs.ExistsArg("asdeps", "asdep") {
aurDeps.Add(name)
} else {
aurExp.Add(name)
2022-09-11 23:15:31 +02:00
}
2022-09-17 14:31:54 +02:00
case dep.CheckDep:
fallthrough
case dep.MakeDep:
fallthrough
case dep.Dep:
aurDeps.Add(name)
2022-09-11 23:15:31 +02:00
}
2022-09-09 20:57:18 +02:00
case dep.Sync:
2022-09-17 14:31:54 +02:00
switch info.Reason {
case dep.Explicit:
if cmdArgs.ExistsArg("asdeps", "asdep") {
syncDeps.Add(name)
} else {
syncExp.Add(name)
2022-09-09 20:57:18 +02:00
}
2022-09-17 14:31:54 +02:00
case dep.CheckDep:
fallthrough
case dep.MakeDep:
fallthrough
case dep.Dep:
syncDeps.Add(name)
2022-09-09 20:57:18 +02:00
}
}
}
fmt.Println(syncDeps, syncExp)
2022-09-17 14:31:54 +02:00
errShow := installer.installSyncPackages(ctx, cmdArgs, syncDeps, syncExp)
2022-09-09 20:57:18 +02:00
if errShow != nil {
return ErrInstallRepoPkgs
}
2022-09-17 14:31:54 +02:00
errAur := installer.installAURPackages(ctx, cmdArgs, aurDeps, aurExp, nameToBaseMap, pkgBuildDirs, false)
2022-09-12 00:10:19 +02:00
return errAur
2022-08-21 07:14:52 +02:00
}
2022-09-09 20:57:18 +02:00
2022-09-17 14:31:54 +02:00
func (installer *Installer) installAURPackages(ctx context.Context,
cmdArgs *parser.Arguments,
aurDepNames, aurExpNames mapset.Set[string],
nameToBase, pkgBuildDirsByBase map[string]string,
installIncompatible bool,
) error {
deps, exp := make([]string, 0, aurDepNames.Cardinality()), make([]string, 0, aurExpNames.Cardinality())
for _, name := range aurDepNames.Union(aurExpNames).ToSlice() {
base := nameToBase[name]
dir := pkgBuildDirsByBase[base]
2022-09-11 23:15:31 +02:00
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))
}
2022-09-17 14:31:54 +02:00
names, err := installer.getNewTargets(pkgdests, name)
2022-09-12 00:10:19 +02:00
if err != nil {
return err
2022-09-11 23:15:31 +02:00
}
2022-09-17 14:31:54 +02:00
isDep := installer.isDep(cmdArgs, aurExpNames, name)
if isDep {
deps = append(deps, names...)
} else {
exp = append(exp, names...)
}
2022-09-11 23:15:31 +02:00
}
if err := doInstall(ctx, cmdArgs, deps, exp); err != nil {
return errors.New(fmt.Sprintf(gotext.Get("error installing:")+" %v %v", deps, exp))
}
return nil
}
2022-09-17 14:31:54 +02:00
func (*Installer) isDep(cmdArgs *parser.Arguments, aurExpNames mapset.Set[string], name string) bool {
switch {
case cmdArgs.ExistsArg("asdeps", "asdep"):
return true
case cmdArgs.ExistsArg("asexplicit", "asexp"):
return false
case aurExpNames.Contains(name):
return false
}
2022-09-11 23:15:31 +02:00
2022-09-17 14:31:54 +02:00
return true
}
func (installer *Installer) getNewTargets(pkgdests map[string]string, name string,
) ([]string, error) {
pkgdest, ok := pkgdests[name]
names := make([]string, 0, 2)
if !ok {
return nil, errors.New(gotext.Get("could not find PKGDEST for: %s", name))
}
if _, errStat := os.Stat(pkgdest); os.IsNotExist(errStat) {
return nil, errors.New(
gotext.Get(
"the PKGDEST for %s is listed by makepkg but does not exist: %s",
name, pkgdest))
}
names = append(names, name)
2022-09-11 23:15:31 +02:00
2022-09-17 14:31:54 +02:00
debugName := pkgdest + "-debug"
pkgdestDebug, ok := pkgdests[debugName]
if ok {
if _, errStat := os.Stat(pkgdestDebug); errStat == nil {
names = append(names, debugName)
2022-09-11 23:15:31 +02:00
}
}
2022-09-17 14:31:54 +02:00
return names, nil
2022-09-11 23:15:31 +02:00
}
func (*Installer) installSyncPackages(ctx context.Context, cmdArgs *parser.Arguments,
2022-09-09 20:57:18 +02:00
syncDeps, // repo targets that are deps
2022-09-17 14:31:54 +02:00
syncExp mapset.Set[string], // repo targets that are exp
2022-09-09 20:57:18 +02:00
) error {
2022-09-17 14:31:54 +02:00
repoTargets := syncDeps.Union(syncExp).ToSlice()
2022-09-12 00:10:19 +02:00
if len(repoTargets) == 0 {
return nil
}
2022-09-09 20:57:18 +02:00
arguments := cmdArgs.Copy()
arguments.DelArg("asdeps", "asdep")
arguments.DelArg("asexplicit", "asexp")
arguments.DelArg("i", "install")
arguments.Op = "S"
arguments.ClearTargets()
arguments.AddTarget(repoTargets...)
2022-09-11 23:15:31 +02:00
2022-09-09 20:57:18 +02:00
errShow := config.Runtime.CmdBuilder.Show(config.Runtime.CmdBuilder.BuildPacmanCmd(ctx,
arguments, config.Runtime.Mode, settings.NoConfirm))
2022-09-17 14:31:54 +02:00
if errD := asdeps(ctx, cmdArgs, syncDeps.ToSlice()); errD != nil {
2022-09-09 20:57:18 +02:00
return errD
}
2022-09-17 14:31:54 +02:00
if errE := asexp(ctx, cmdArgs, syncExp.ToSlice()); errE != nil {
2022-09-09 20:57:18 +02:00
return errE
}
return errShow
}