mirror of
https://github.com/Jguer/yay.git
synced 2024-11-06 17:17:22 +01:00
cdaee7d1d4
Split packages are now grouped together when printing displaying the package base and the packages inside of the base to beinstalled. If only one packge is to be installed from a base and the package name matches the base name print normally Only build and install once per package base Only ask questions once per package base for editing pkgbuils and clean build
469 lines
10 KiB
Go
469 lines
10 KiB
Go
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"os/exec"
|
|
"io/ioutil"
|
|
"strings"
|
|
|
|
alpm "github.com/jguer/go-alpm"
|
|
rpc "github.com/mikkeloscar/aur"
|
|
gopkg "github.com/mikkeloscar/gopkgbuild"
|
|
)
|
|
|
|
// Install handles package installs
|
|
func install(parser *arguments) error {
|
|
aurs, repos, missing, err := packageSlices(parser.targets.toSlice())
|
|
srcinfos := make(map[string]*gopkg.PKGBUILD)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if len(missing) > 0 {
|
|
fmt.Println(missing)
|
|
fmt.Println("Could not find all Targets")
|
|
}
|
|
|
|
arguments := parser.copy()
|
|
arguments.delArg("u", "sysupgrade")
|
|
arguments.delArg("y", "refresh")
|
|
arguments.op = "S"
|
|
arguments.targets = make(stringSet)
|
|
arguments.addTarget(repos...)
|
|
|
|
if len(repos) != 0 {
|
|
err := passToPacman(arguments)
|
|
if err != nil {
|
|
fmt.Println("Error installing repo packages.")
|
|
}
|
|
}
|
|
|
|
if len(aurs) != 0 {
|
|
//todo mamakeke pretty
|
|
fmt.Println(greenFg(arrow), greenFg("Resolving Dependencies"))
|
|
|
|
dt, err := getDepTree(aurs)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if len(dt.Missing) > 0 {
|
|
fmt.Println(dt.Missing)
|
|
return fmt.Errorf("Could not find all Deps")
|
|
}
|
|
|
|
dc, err := getDepCatagories(aurs, dt)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
for _, pkg := range dc.Aur {
|
|
if pkg.Maintainer == "" {
|
|
fmt.Println(boldRedFgBlackBg(arrow+" Warning:"),
|
|
blackBg(pkg.Name+"-"+pkg.Version+" is orphaned"))
|
|
}
|
|
}
|
|
|
|
//printDownloadsFromRepo("Repo", dc.Repo)
|
|
//printDownloadsFromRepo("Repo Make", dc.RepoMake)
|
|
//printDownloadsFromAur("AUR", dc.Aur)
|
|
//printDownloadsFromAur("AUR Make", dc.AurMake)
|
|
|
|
//fmt.Println(dc.MakeOnly)
|
|
//fmt.Println(dc.AurSet)
|
|
|
|
printDepCatagories(dc)
|
|
|
|
askCleanBuilds(dc.Aur, dc.Bases)
|
|
fmt.Println()
|
|
|
|
if !continueTask("Proceed with install?", "nN") {
|
|
return fmt.Errorf("Aborting due to user")
|
|
}
|
|
|
|
if len(dc.Repo) > 0 {
|
|
arguments := parser.copy()
|
|
arguments.delArg("u", "sysupgrade")
|
|
arguments.delArg("y", "refresh")
|
|
arguments.op = "S"
|
|
arguments.targets = make(stringSet)
|
|
arguments.addArg("needed", "asdeps")
|
|
for _, pkg := range dc.Repo {
|
|
arguments.addTarget(pkg.Name())
|
|
}
|
|
|
|
oldConfirm := config.NoConfirm
|
|
config.NoConfirm = true
|
|
passToPacman(arguments)
|
|
config.NoConfirm = oldConfirm
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
// if !continueTask("Proceed with download?", "nN") {
|
|
// return fmt.Errorf("Aborting due to user")
|
|
// }
|
|
|
|
if _, ok := arguments.options["gendb"]; !ok {
|
|
//err = checkForConflicts(dc.Aur, dc.AurMake, dc.Repo, dc.RepoMake)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
err = dowloadPkgBuilds(dc.Aur, dc.Bases)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
err = askEditPkgBuilds(dc.Aur, dc.Bases)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if _, ok := arguments.options["gendb"]; ok {
|
|
fmt.Println("GenDB finished. No packages were installed")
|
|
return nil
|
|
}
|
|
|
|
// if !continueTask("Proceed with install?", "nN") {
|
|
// return fmt.Errorf("Aborting due to user")
|
|
// }
|
|
|
|
err = downloadPkgBuildsSources(dc.Aur)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
err = parsesrcinfos(dc.Aur, srcinfos)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
err = buildInstallPkgBuilds(dc.Aur, srcinfos, parser.targets, parser, dc.Bases)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if len(dc.MakeOnly) > 0 {
|
|
if continueTask("Remove make dependencies?", "yY") {
|
|
return nil
|
|
}
|
|
|
|
removeArguments := makeArguments()
|
|
removeArguments.addArg("R", "u")
|
|
|
|
for pkg := range dc.MakeOnly {
|
|
removeArguments.addTarget(pkg)
|
|
}
|
|
|
|
oldValue := config.NoConfirm
|
|
config.NoConfirm = true
|
|
passToPacman(removeArguments)
|
|
config.NoConfirm = oldValue
|
|
}
|
|
|
|
if config.CleanAfter {
|
|
clean(dc.Aur)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func askCleanBuilds(pkgs []*rpc.Pkg, bases map[string][]*rpc.Pkg) {
|
|
for _, pkg := range pkgs {
|
|
dir := config.BuildDir + pkg.PackageBase + "/"
|
|
|
|
if _, err := os.Stat(dir); !os.IsNotExist(err) {
|
|
str := pkg.Name
|
|
if len(bases[pkg.PackageBase]) > 1 || pkg.PackageBase != pkg.Name {
|
|
str += " ("
|
|
for _, split := range bases[pkg.PackageBase] {
|
|
str += split.Name + " "
|
|
}
|
|
str = str[:len(str)-1] + ")"
|
|
}
|
|
|
|
if !continueTask(str + " Directory exists. Clean Build?", "yY") {
|
|
_ = os.RemoveAll(config.BuildDir + pkg.PackageBase)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func checkForConflicts(aur []*rpc.Pkg, aurMake []*rpc.Pkg, repo []*alpm.Package,
|
|
repoMake []*alpm.Package) error {
|
|
|
|
localDb, err := alpmHandle.LocalDb()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
var toRemove []string
|
|
|
|
for _, pkg := range aur {
|
|
for _, cpkg := range pkg.Conflicts {
|
|
if _, err := localDb.PkgByName(cpkg); err == nil {
|
|
toRemove = append(toRemove, cpkg)
|
|
}
|
|
}
|
|
}
|
|
|
|
for _, pkg := range aurMake {
|
|
for _, cpkg := range pkg.Conflicts {
|
|
if _, err := localDb.PkgByName(cpkg); err == nil {
|
|
toRemove = append(toRemove, cpkg)
|
|
}
|
|
}
|
|
}
|
|
|
|
for _, pkg := range repo {
|
|
pkg.Conflicts().ForEach(func(conf alpm.Depend) error {
|
|
if _, err := localDb.PkgByName(conf.Name); err == nil {
|
|
toRemove = append(toRemove, conf.Name)
|
|
}
|
|
return nil
|
|
})
|
|
}
|
|
|
|
for _, pkg := range repoMake {
|
|
pkg.Conflicts().ForEach(func(conf alpm.Depend) error {
|
|
if _, err := localDb.PkgByName(conf.Name); err == nil {
|
|
toRemove = append(toRemove, conf.Name)
|
|
}
|
|
return nil
|
|
})
|
|
}
|
|
|
|
if len(toRemove) != 0 {
|
|
fmt.Println(
|
|
redFg("The following packages conflict with packages to install:"))
|
|
for _, pkg := range toRemove {
|
|
fmt.Println(yellowFg(pkg))
|
|
}
|
|
|
|
if !continueTask("Remove conflicting package(s)?", "nN") {
|
|
return fmt.Errorf("Aborting due to user")
|
|
}
|
|
|
|
removeArguments := makeArguments()
|
|
removeArguments.addArg("R", "d", "d")
|
|
|
|
for _, pkg := range toRemove {
|
|
removeArguments.addTarget(pkg)
|
|
}
|
|
|
|
oldValue := config.NoConfirm
|
|
config.NoConfirm = true
|
|
passToPacman(removeArguments)
|
|
config.NoConfirm = oldValue
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func askEditPkgBuilds(pkgs []*rpc.Pkg, bases map[string][]*rpc.Pkg) (error) {
|
|
for _, pkg := range pkgs {
|
|
dir := config.BuildDir + pkg.PackageBase + "/"
|
|
|
|
str := "Edit PKGBUILD? " + pkg.PackageBase
|
|
if len(bases[pkg.PackageBase]) > 1 || pkg.PackageBase != pkg.Name {
|
|
str += " ("
|
|
for _, split := range bases[pkg.PackageBase] {
|
|
str += split.Name + " "
|
|
}
|
|
str = str[:len(str)-1] + ")"
|
|
}
|
|
|
|
if !continueTask(str, "yY") {
|
|
editcmd := exec.Command(editor(), dir+"PKGBUILD")
|
|
editcmd.Stdin, editcmd.Stdout, editcmd.Stderr = os.Stdin, os.Stdout, os.Stderr
|
|
editcmd.Run()
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
|
|
func parsesrcinfos(pkgs []*rpc.Pkg, srcinfos map[string]*gopkg.PKGBUILD) (error) {
|
|
|
|
for _, pkg := range pkgs {
|
|
dir := config.BuildDir + pkg.PackageBase + "/"
|
|
|
|
cmd := exec.Command(config.MakepkgBin, "--printsrcinfo")
|
|
cmd.Stderr = os.Stderr
|
|
cmd.Dir = dir
|
|
srcinfo, err := cmd.Output()
|
|
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
pkgbuild, err := gopkg.ParseSRCINFOContent(srcinfo)
|
|
if err == nil {
|
|
srcinfos[pkg.PackageBase] = pkgbuild
|
|
|
|
for _, pkgsource := range pkgbuild.Source {
|
|
owner, repo := parseSource(pkgsource)
|
|
if owner != "" && repo != "" {
|
|
err = branchInfo(pkg.Name, owner, repo)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func dowloadPkgBuilds(pkgs []*rpc.Pkg, bases map[string][]*rpc.Pkg) (err error) {
|
|
for _, pkg := range pkgs {
|
|
//todo make pretty
|
|
str := "Downloading: " + pkg.PackageBase+"-"+pkg.Version
|
|
if len(bases[pkg.PackageBase]) > 1 || pkg.PackageBase != pkg.Name {
|
|
str += " ("
|
|
for _, split := range bases[pkg.PackageBase] {
|
|
str += split.Name + " "
|
|
}
|
|
str = str[:len(str)-1] + ")"
|
|
}
|
|
fmt.Println(str)
|
|
|
|
err = downloadAndUnpack(baseURL+pkg.URLPath, config.BuildDir, false)
|
|
if err != nil {
|
|
return
|
|
}
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
func downloadPkgBuildsSources(pkgs []*rpc.Pkg) (err error) {
|
|
for _, pkg := range pkgs {
|
|
dir := config.BuildDir + pkg.PackageBase + "/"
|
|
err = passToMakepkg(dir, "--nobuild", "--nocheck", "--noprepare", "--nodeps")
|
|
if err != nil {
|
|
return
|
|
}
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
func buildInstallPkgBuilds(pkgs []*rpc.Pkg, srcinfos map[string]*gopkg.PKGBUILD, targets stringSet, parser *arguments, bases map[string][]*rpc.Pkg) (error) {
|
|
//for n := len(pkgs) -1 ; n > 0; n-- {
|
|
for n := 0; n < len(pkgs); n++ {
|
|
pkg := pkgs[n]
|
|
|
|
dir := config.BuildDir + pkg.PackageBase + "/"
|
|
built := true
|
|
|
|
srcinfo := srcinfos[pkg.PackageBase]
|
|
version := srcinfo.CompleteVersion()
|
|
|
|
for _, split:= range bases[pkg.PackageBase] {
|
|
file, err := completeFileName(dir, split.Name + "-" + version.String())
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if file == "" {
|
|
built = false
|
|
}
|
|
}
|
|
|
|
if built {
|
|
fmt.Println(boldRedFgBlackBg(arrow+" Warning:"),
|
|
blackBg(pkg.Name+"-"+pkg.Version+ " Already made -- skipping build"))
|
|
} else {
|
|
err := passToMakepkg(dir, "-Cscf", "--noconfirm")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
arguments := parser.copy()
|
|
arguments.targets = make(stringSet)
|
|
arguments.op = "U"
|
|
arguments.delArg("confirm")
|
|
arguments.delArg("c", "clean")
|
|
arguments.delArg("q", "quiet")
|
|
arguments.delArg("q", "quiet")
|
|
arguments.delArg("y", "refresh")
|
|
arguments.delArg("u", "sysupgrade")
|
|
arguments.delArg("w", "downloadonly")
|
|
|
|
depArguments := makeArguments()
|
|
depArguments.addArg("D", "asdeps")
|
|
|
|
for _, split := range bases[pkg.PackageBase] {
|
|
file, err := completeFileName(dir, split.Name + "-" + version.String())
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if file == "" {
|
|
return fmt.Errorf("Could not find built package " + split.Name + "-" + version.String())
|
|
}
|
|
|
|
arguments.addTarget(file)
|
|
if !targets.get(split.Name) {
|
|
depArguments.addTarget(split.Name)
|
|
}
|
|
}
|
|
|
|
oldConfirm := config.NoConfirm
|
|
config.NoConfirm = true
|
|
err := passToPacman(arguments)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if len(depArguments.targets) > 0 {
|
|
err = passToPacman(depArguments)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
config.NoConfirm = oldConfirm
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func clean(pkgs []*rpc.Pkg) {
|
|
for _, pkg := range pkgs {
|
|
dir := config.BuildDir + pkg.PackageBase + "/"
|
|
|
|
fmt.Println(boldGreenFg(arrow +
|
|
" CleanAfter enabled. Deleting " + pkg.Name +" source folder."))
|
|
os.RemoveAll(dir)
|
|
}
|
|
}
|
|
|
|
|
|
func completeFileName(dir, name string) (string, error) {
|
|
files, err := ioutil.ReadDir(dir)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
for _, file := range files {
|
|
if file.IsDir() {
|
|
continue
|
|
}
|
|
|
|
if strings.HasPrefix(file.Name(), name) {
|
|
return dir + file.Name(), nil
|
|
}
|
|
}
|
|
|
|
return "", nil
|
|
}
|