From b4f4a42d50e5495b70b57d0bd14cb32847ff122f Mon Sep 17 00:00:00 2001 From: Jguer Date: Wed, 2 Aug 2017 18:24:03 +0100 Subject: [PATCH] Flattened architecture. Does not compile --- actions.go | 64 ---- aur/aur.go | 256 -------------- aur/query.go | 44 --- aur/result.go | 255 -------------- clean.go | 60 ++++ cmd.go | 127 ++++--- completions.go | 60 ++++ config/config.go => config.go | 133 ++------ depencies.go | 76 +++++ download.go | 122 +++++++ install.go | 175 ++++++++++ install/i.go | 39 --- pacman/pacman.go | 427 ------------------------ pacman/pacman_test.go => pacman_test.go | 2 +- print.go | 183 ++++++++++ query.go | 369 ++++++++++++++++++-- upgrade.go | 41 ++- aur/vcs/github.go => vcs.go | 68 ++-- aur/vcs/github_test.go => vcs_test.go | 2 +- 19 files changed, 1174 insertions(+), 1329 deletions(-) delete mode 100644 actions.go delete mode 100644 aur/aur.go delete mode 100644 aur/query.go delete mode 100644 aur/result.go create mode 100644 clean.go create mode 100644 completions.go rename config/config.go => config.go (60%) create mode 100644 depencies.go create mode 100644 download.go create mode 100644 install.go delete mode 100644 install/i.go rename pacman/pacman_test.go => pacman_test.go (98%) create mode 100644 print.go rename aur/vcs/github.go => vcs.go (70%) rename aur/vcs/github_test.go => vcs_test.go (98%) diff --git a/actions.go b/actions.go deleted file mode 100644 index dcc4c78e..00000000 --- a/actions.go +++ /dev/null @@ -1,64 +0,0 @@ -package main - -import ( - "fmt" - "os" - - aur "github.com/jguer/yay/aur" - "github.com/jguer/yay/config" - pac "github.com/jguer/yay/pacman" -) - -// Install handles package installs -func install(pkgs []string, flags []string) error { - aurs, repos, _ := pac.PackageSlices(pkgs) - - if len(repos) != 0 { - err := config.PassToPacman("-S", repos, flags) - if err != nil { - fmt.Println("Error installing repo packages.") - } - } - - if len(aurs) != 0 { - err := aur.Install(aurs, flags) - if err != nil { - fmt.Println("Error installing aur packages.") - } - } - return nil -} - -// CleanDependencies removels all dangling dependencies in system -func cleanDependencies(pkgs []string) error { - hanging, err := pac.HangingPackages() - if err != nil { - return err - } - - if len(hanging) != 0 { - if !config.ContinueTask("Confirm Removal?", "nN") { - return nil - } - err = pac.CleanRemove(hanging) - } - - return err -} - -// GetPkgbuild gets the pkgbuild of the package 'pkg' trying the ABS first and then the AUR trying the ABS first and then the AUR. -func getPkgbuild(pkg string) (err error) { - wd, err := os.Getwd() - if err != nil { - return - } - wd = wd + "/" - - err = pac.GetPkgbuild(pkg, wd) - if err == nil { - return - } - - err = aur.GetPkgbuild(pkg, wd) - return -} diff --git a/aur/aur.go b/aur/aur.go deleted file mode 100644 index fc75d195..00000000 --- a/aur/aur.go +++ /dev/null @@ -1,256 +0,0 @@ -package aur - -import ( - "bufio" - "fmt" - "net/http" - "os" - "sort" - "strings" - - alpm "github.com/jguer/go-alpm" - vcs "github.com/jguer/yay/aur/vcs" - "github.com/jguer/yay/config" - "github.com/jguer/yay/pacman" - rpc "github.com/mikkeloscar/aur" -) - -// BaseURL givers the AUR default address. -const BaseURL string = "https://aur.archlinux.org" - -var specialDBsauce = false - -// NarrowSearch searches AUR and narrows based on subarguments -func NarrowSearch(pkgS []string, sortS bool) (Query, error) { - if len(pkgS) == 0 { - return nil, nil - } - - r, err := rpc.Search(pkgS[0]) - if err != nil { - return nil, err - } - - if len(pkgS) == 1 { - if sortS { - sort.Sort(Query(r)) - } - return r, err - } - - var aq Query - var n int - - for _, res := range r { - match := true - for _, pkgN := range pkgS[1:] { - if !(strings.Contains(res.Name, pkgN) || strings.Contains(strings.ToLower(res.Description), pkgN)) { - match = false - break - } - } - - if match { - n++ - aq = append(aq, res) - } - } - - if sortS { - sort.Sort(aq) - } - - return aq, err -} - -// Install sends system commands to make and install a package from pkgName -func Install(pkgName []string, flags []string) (err error) { - q, err := rpc.Info(pkgName) - if err != nil { - return - } - - if len(q) != len(pkgName) { - fmt.Printf("Some package from list\n%+v\ndoes not exist", pkgName) - } - - var finalrm []string - for _, i := range q { - mrm, err := PkgInstall(&i, flags) - if err != nil { - fmt.Println("Error installing", i.Name, ":", err) - } - finalrm = append(finalrm, mrm...) - } - - if len(finalrm) != 0 { - err = RemoveMakeDeps(finalrm) - } - - return err -} - -// CreateDevelDB forces yay to create a DB of the existing development packages -func CreateDevelDB() error { - foreign, err := pacman.ForeignPackages() - if err != nil { - return err - } - - keys := make([]string, len(foreign)) - i := 0 - for k := range foreign { - keys[i] = k - i++ - } - - config.YayConf.NoConfirm = true - specialDBsauce = true - err = Install(keys, nil) - return err -} - -func develUpgrade(foreign map[string]alpm.Package, flags []string) error { - fmt.Println(" Checking development packages...") - develUpdates := vcs.CheckUpdates(foreign) - if len(develUpdates) != 0 { - for _, q := range develUpdates { - fmt.Printf("\x1b[1m\x1b[32m==>\x1b[33;1m %s\x1b[0m\n", q) - } - // Install updated packages - if !config.ContinueTask("Proceed with upgrade?", "nN") { - return nil - } - - err := Install(develUpdates, flags) - if err != nil { - fmt.Println(err) - } - } - - return nil -} - -// Upgrade tries to update every foreign package installed in the system -// func Upgrade(flags []string) error { -// fmt.Println("\x1b[1;36;1m::\x1b[0m\x1b[1m Starting AUR upgrade...\x1b[0m") - -// foreign, err := pacman.ForeignPackages() -// if err != nil { -// return err -// } -// keys := make([]string, len(foreign)) -// i := 0 -// for k := range foreign { -// keys[i] = k -// i++ -// } - -// if config.YayConf.Devel { -// err := develUpgrade(foreign, flags) -// if err != nil { -// fmt.Println(err) -// } -// } - -// var q Query -// var j int -// for i = len(keys); i != 0; i = j { -// j = i - config.YayConf.RequestSplitN -// if j < 0 { -// j = 0 -// } -// qtemp, err := rpc.Info(keys[j:i]) -// q = append(q, qtemp...) -// if err != nil { -// return err -// } -// } - -// var buffer bytes.Buffer -// buffer.WriteString("\n") -// outdated := q[:0] -// for i, res := range q { -// fmt.Printf("\r Checking %d/%d packages...", i+1, len(q)) - -// if _, ok := foreign[res.Name]; ok { -// // Leaving this here for now, warn about downgrades later -// if (config.YayConf.TimeUpdate && (int64(res.LastModified) > foreign[res.Name].BuildDate().Unix())) || -// alpm.VerCmp(foreign[res.Name].Version(), res.Version) < 0 { -// buffer.WriteString(fmt.Sprintf("\x1b[1m\x1b[32m==>\x1b[33;1m %s: \x1b[0m%s \x1b[33;1m-> \x1b[0m%s\n", -// res.Name, foreign[res.Name].Version(), res.Version)) -// outdated = append(outdated, res) -// } -// } -// } -// fmt.Println(buffer.String()) - -// //If there are no outdated packages, don't prompt -// if len(outdated) == 0 { -// fmt.Println("there is nothing to do") -// return nil -// } - -// // Install updated packages -// if !config.ContinueTask("Proceed with upgrade?", "nN") { -// return nil -// } - -// var finalmdeps []string -// for _, pkgi := range outdated { -// mdeps, err := PkgInstall(&pkgi, flags) -// finalmdeps = append(finalmdeps, mdeps...) -// if err != nil { -// fmt.Println(err) -// } -// } - -// err = pacman.CleanRemove(finalmdeps) -// if err != nil { -// fmt.Println(err) -// } - -// return nil -// } - -// GetPkgbuild downloads pkgbuild from the AUR. -func GetPkgbuild(pkgN string, dir string) (err error) { - aq, err := rpc.Info([]string{pkgN}) - if err != nil { - return err - } - - if len(aq) == 0 { - return fmt.Errorf("no results") - } - - fmt.Printf("\x1b[1;32m==>\x1b[1;33m %s \x1b[1;32mfound in AUR.\x1b[0m\n", pkgN) - config.DownloadAndUnpack(BaseURL+aq[0].URLPath, dir, false) - return -} - -//CreateAURList creates a new completion file -func CreateAURList(out *os.File) (err error) { - resp, err := http.Get("https://aur.archlinux.org/packages.gz") - if err != nil { - return err - } - defer resp.Body.Close() - - scanner := bufio.NewScanner(resp.Body) - - scanner.Scan() - for scanner.Scan() { - fmt.Print(scanner.Text()) - out.WriteString(scanner.Text()) - if config.YayConf.Shell == "fish" { - fmt.Print("\tAUR\n") - out.WriteString("\tAUR\n") - } else { - fmt.Print("\n") - out.WriteString("\n") - } - } - - return nil -} diff --git a/aur/query.go b/aur/query.go deleted file mode 100644 index 80b00088..00000000 --- a/aur/query.go +++ /dev/null @@ -1,44 +0,0 @@ -package aur - -import ( - "fmt" - - "github.com/jguer/yay/config" - rpc "github.com/mikkeloscar/aur" -) - -// Query is a collection of Results -type Query []rpc.Pkg - -func (q Query) Len() int { - return len(q) -} - -func (q Query) Less(i, j int) bool { - if config.YayConf.SortMode == config.BottomUp { - return q[i].NumVotes < q[j].NumVotes - } - return q[i].NumVotes > q[j].NumVotes -} - -func (q Query) Swap(i, j int) { - q[i], q[j] = q[j], q[i] -} - -// MissingPackage warns if the Query was unable to find a package -func (q Query) MissingPackage(pkgS []string) { - for _, depName := range pkgS { - found := false - for _, dep := range q { - if dep.Name == depName { - found = true - break - } - } - - if !found { - fmt.Println("\x1b[31mUnable to find", depName, "in AUR\x1b[0m") - } - } - return -} diff --git a/aur/result.go b/aur/result.go deleted file mode 100644 index 03382b3d..00000000 --- a/aur/result.go +++ /dev/null @@ -1,255 +0,0 @@ -package aur - -import ( - "fmt" - "os" - "os/exec" - - vcs "github.com/jguer/yay/aur/vcs" - "github.com/jguer/yay/config" - "github.com/jguer/yay/pacman" - rpc "github.com/mikkeloscar/aur" - gopkg "github.com/mikkeloscar/gopkgbuild" -) - -// PkgDependencies returns package dependencies not installed belonging to AUR -// 0 is Repo, 1 is Foreign. -func PkgDependencies(a *rpc.Pkg) (runDeps [2][]string, makeDeps [2][]string, err error) { - var q Query - if len(a.Depends) == 0 && len(a.MakeDepends) == 0 { - q, err = rpc.Info([]string{a.Name}) - if len(q) == 0 || err != nil { - err = fmt.Errorf("Unable to search dependencies, %s", err) - return - } - } else { - q = append(q, *a) - } - - depSearch := pacman.BuildDependencies(a.Depends) - if len(a.Depends) != 0 { - runDeps[0], runDeps[1] = depSearch(q[0].Depends, true, false) - if len(runDeps[0]) != 0 || len(runDeps[1]) != 0 { - fmt.Println("\x1b[1;32m=>\x1b[1;33m Run Dependencies: \x1b[0m") - printDeps(runDeps[0], runDeps[1]) - } - } - - if len(a.MakeDepends) != 0 { - makeDeps[0], makeDeps[1] = depSearch(q[0].MakeDepends, false, false) - if len(makeDeps[0]) != 0 || len(makeDeps[1]) != 0 { - fmt.Println("\x1b[1;32m=>\x1b[1;33m Make Dependencies: \x1b[0m") - printDeps(makeDeps[0], makeDeps[1]) - } - } - depSearch(a.MakeDepends, false, true) - - err = nil - return -} - -func printDeps(repoDeps []string, aurDeps []string) { - if len(repoDeps) != 0 { - fmt.Print("\x1b[1;32m==> Repository dependencies: \x1b[0m") - for _, repoD := range repoDeps { - fmt.Print("\x1b[33m", repoD, " \x1b[0m") - } - fmt.Print("\n") - - } - if len(aurDeps) != 0 { - fmt.Print("\x1b[1;32m==> AUR dependencies: \x1b[0m") - for _, aurD := range aurDeps { - fmt.Print("\x1b[33m", aurD, " \x1b[0m") - } - fmt.Print("\n") - } -} - -func setupPackageSpace(a *rpc.Pkg) (pkgbuild *gopkg.PKGBUILD, err error) { - dir := config.YayConf.BuildDir + a.PackageBase + "/" - - if _, err = os.Stat(dir); !os.IsNotExist(err) { - if !config.ContinueTask("Directory exists. Clean Build?", "yY") { - _ = os.RemoveAll(config.YayConf.BuildDir + a.PackageBase) - } - } - - if err = config.DownloadAndUnpack(BaseURL+a.URLPath, config.YayConf.BuildDir, false); err != nil { - return - } - - if !config.ContinueTask("Edit PKGBUILD?", "yY") { - editcmd := exec.Command(config.Editor(), dir+"PKGBUILD") - editcmd.Stdin, editcmd.Stdout, editcmd.Stderr = os.Stdin, os.Stdout, os.Stderr - editcmd.Run() - } - - pkgbuild, err = gopkg.ParseSRCINFO(dir + ".SRCINFO") - if err == nil { - for _, pkgsource := range pkgbuild.Source { - owner, repo := vcs.ParseSource(pkgsource) - if owner != "" && repo != "" { - err = vcs.BranchInfo(a.Name, owner, repo) - if err != nil { - fmt.Println(err) - } - } - } - } - - err = os.Chdir(dir) - if err != nil { - return - } - - return -} - -// PkgInstall handles install from Info Result. -func PkgInstall(a *rpc.Pkg, flags []string) (finalmdeps []string, err error) { - fmt.Printf("\x1b[1;32m==> Installing\x1b[33m %s\x1b[0m\n", a.Name) - if a.Maintainer == "" { - fmt.Println("\x1b[1;31;40m==> Warning:\x1b[0;;40m This package is orphaned.\x1b[0m") - } - - _, err = setupPackageSpace(a) - if err != nil { - return - } - - if specialDBsauce { - return - } - - runDeps, makeDeps, err := PkgDependencies(a) - if err != nil { - return - } - - repoDeps := append(runDeps[0], makeDeps[0]...) - aurDeps := append(runDeps[1], makeDeps[1]...) - finalmdeps = append(finalmdeps, makeDeps[0]...) - finalmdeps = append(finalmdeps, makeDeps[1]...) - - if len(aurDeps) != 0 || len(repoDeps) != 0 { - if !config.ContinueTask("Continue?", "nN") { - return finalmdeps, fmt.Errorf("user did not like the dependencies") - } - } - - aurQ, _ := rpc.Info(aurDeps) - if len(aurQ) != len(aurDeps) { - (Query)(aurQ).MissingPackage(aurDeps) - if !config.ContinueTask("Continue?", "nN") { - return finalmdeps, fmt.Errorf("unable to install dependencies") - } - } - - var depArgs []string - if config.YayConf.NoConfirm { - depArgs = []string{"--asdeps", "--noconfirm"} - } else { - depArgs = []string{"--asdeps"} - } - // Repo dependencies - if len(repoDeps) != 0 { - errR := config.PassToPacman("-S", repoDeps, depArgs) - if errR != nil { - return finalmdeps, errR - } - } - - // Handle AUR dependencies - for _, dep := range aurQ { - finalmdepsR, errA := PkgInstall(&dep, depArgs) - finalmdeps = append(finalmdeps, finalmdepsR...) - - if errA != nil { - pacman.CleanRemove(repoDeps) - pacman.CleanRemove(aurDeps) - return finalmdeps, errA - } - } - - args := []string{"-sri"} - args = append(args, flags...) - makepkgcmd := exec.Command(config.YayConf.MakepkgBin, args...) - makepkgcmd.Stdin, makepkgcmd.Stdout, makepkgcmd.Stderr = os.Stdin, os.Stdout, os.Stderr - err = makepkgcmd.Run() - if err == nil { - _ = vcs.SaveBranchInfo() - } - return -} - -// PrintInfo prints package info like pacman -Si. -func PrintInfo(a *rpc.Pkg) { - fmt.Println("\x1b[1;37mRepository :\x1b[0m", "aur") - fmt.Println("\x1b[1;37mName :\x1b[0m", a.Name) - fmt.Println("\x1b[1;37mVersion :\x1b[0m", a.Version) - fmt.Println("\x1b[1;37mDescription :\x1b[0m", a.Description) - if a.URL != "" { - fmt.Println("\x1b[1;37mURL :\x1b[0m", a.URL) - } else { - fmt.Println("\x1b[1;37mURL :\x1b[0m", "None") - } - fmt.Println("\x1b[1;37mLicenses :\x1b[0m", a.License) - - // if len(a.Provides) != 0 { - // fmt.Println("\x1b[1;37mProvides :\x1b[0m", a.Provides) - // } else { - // fmt.Println("\x1b[1;37mProvides :\x1b[0m", "None") - // } - - if len(a.Depends) != 0 { - fmt.Println("\x1b[1;37mDepends On :\x1b[0m", a.Depends) - } else { - fmt.Println("\x1b[1;37mDepends On :\x1b[0m", "None") - } - - if len(a.MakeDepends) != 0 { - fmt.Println("\x1b[1;37mMake depends On :\x1b[0m", a.MakeDepends) - } else { - fmt.Println("\x1b[1;37mMake depends On :\x1b[0m", "None") - } - - if len(a.OptDepends) != 0 { - fmt.Println("\x1b[1;37mOptional Deps :\x1b[0m", a.OptDepends) - } else { - fmt.Println("\x1b[1;37mOptional Deps :\x1b[0m", "None") - } - - if len(a.Conflicts) != 0 { - fmt.Println("\x1b[1;37mConflicts With :\x1b[0m", a.Conflicts) - } else { - fmt.Println("\x1b[1;37mConflicts With :\x1b[0m", "None") - } - - if a.Maintainer != "" { - fmt.Println("\x1b[1;37mMaintainer :\x1b[0m", a.Maintainer) - } else { - fmt.Println("\x1b[1;37mMaintainer :\x1b[0m", "None") - } - fmt.Println("\x1b[1;37mVotes :\x1b[0m", a.NumVotes) - fmt.Println("\x1b[1;37mPopularity :\x1b[0m", a.Popularity) - - if a.OutOfDate != 0 { - fmt.Println("\x1b[1;37mOut-of-date :\x1b[0m", "Yes") - } -} - -// RemoveMakeDeps receives a make dependency list and removes those -// that are no longer necessary. -func RemoveMakeDeps(depS []string) (err error) { - hanging := pacman.SliceHangingPackages(depS) - - if len(hanging) != 0 { - if !config.ContinueTask("Confirm Removal?", "nN") { - return nil - } - err = pacman.CleanRemove(hanging) - } - - return -} diff --git a/clean.go b/clean.go new file mode 100644 index 00000000..96e5a023 --- /dev/null +++ b/clean.go @@ -0,0 +1,60 @@ +package main + +// GetPkgbuild gets the pkgbuild of the package 'pkg' trying the ABS first and then the AUR trying the ABS first and then the AUR. + +// RemoveMakeDeps receives a make dependency list and removes those +// that are no longer necessary. +func removeMakeDeps(depS []string) (err error) { + hanging := sliceHangingPackages(depS) + + if len(hanging) != 0 { + if !continueTask("Confirm Removal?", "nN") { + return nil + } + err = cleanRemove(hanging) + } + + return +} + +// RemovePackage removes package from VCS information +func removeVCSPackage(pkgs []string) { + for _, pkgName := range pkgs { + for i, e := range savedInfo { + if e.Package == pkgName { + savedInfo[i] = savedInfo[len(savedInfo)-1] + savedInfo = savedInfo[:len(savedInfo)-1] + } + } + } + + _ = saveVCSInfo() + return +} + +// CleanDependencies removels all dangling dependencies in system +func cleanDependencies(pkgs []string) error { + hanging, err := hangingPackages() + if err != nil { + return err + } + + if len(hanging) != 0 { + if !continueTask("Confirm Removal?", "nN") { + return nil + } + err = cleanRemove(hanging) + } + + return err +} + +// CleanRemove sends a full removal command to pacman with the pkgName slice +func cleanRemove(pkgName []string) (err error) { + if len(pkgName) == 0 { + return nil + } + + err = passToPacman("-Rsnc", pkgName, []string{"--noconfirm"}) + return err +} diff --git a/cmd.go b/cmd.go index 43436209..183e4e6c 100644 --- a/cmd.go +++ b/cmd.go @@ -2,6 +2,7 @@ package main import ( "bufio" + "encoding/json" "fmt" "io" "os" @@ -9,9 +10,6 @@ import ( "strings" "time" - "github.com/jguer/yay/aur" - vcs "github.com/jguer/yay/aur/vcs" - "github.com/jguer/yay/config" pac "github.com/jguer/yay/pacman" ) @@ -42,7 +40,61 @@ func usage() { `) } -var version = "2.116" +func init() { + defaultSettings(&config) + + var err error + configfile := os.Getenv("HOME") + "/.config/yay/config.json" + + if _, err = os.Stat(configfile); os.IsNotExist(err) { + _ = os.MkdirAll(os.Getenv("HOME")+"/.config/yay", 0755) + // Save the default config if nothing is found + config.saveConfig() + } else { + file, err := os.Open(configfile) + if err != nil { + fmt.Println("Error reading config:", err) + } else { + decoder := json.NewDecoder(file) + err = decoder.Decode(&config) + if err != nil { + fmt.Println("Loading default Settings\nError reading config:", err) + defaultSettings(&config) + } + } + } + + AlpmConf, err = readAlpmConfig(config.PacmanConf) + if err != nil { + fmt.Println("Unable to read Pacman conf", err) + os.Exit(1) + } + + AlpmHandle, err = AlpmConf.CreateHandle() + if err != nil { + fmt.Println("Unable to CreateHandle", err) + os.Exit(1) + } + + updated = false + configfile = os.Getenv("HOME") + "/.config/yay/yay_vcs.json" + + if _, err := os.Stat(configfile); os.IsNotExist(err) { + _ = os.MkdirAll(os.Getenv("HOME")+"/.config/yay", 0755) + return + } + + file, err := os.Open(configfile) + if err != nil { + fmt.Println("error:", err) + return + } + decoder := json.NewDecoder(file) + err = decoder.Decode(&savedInfo) + if err != nil { + fmt.Println("error:", err) + } +} func parser() (op string, options []string, packages []string, changedConfig bool, err error) { if len(os.Args) < 2 { @@ -65,41 +117,41 @@ func parser() (op string, options []string, packages []string, changedConfig boo changedConfig = true switch arg { case "--printconfig": - fmt.Printf("%+v", config.YayConf) + fmt.Printf("%+v", config) os.Exit(0) case "--gendb": - err = aur.CreateDevelDB() + err = createDevelDB() if err != nil { fmt.Println(err) } - err = vcs.SaveBranchInfo() + err = saveVCSInfo() if err != nil { fmt.Println(err) } os.Exit(0) case "--devel": - config.YayConf.Devel = true + config.Devel = true case "--nodevel": - config.YayConf.Devel = false + config.Devel = false case "--timeupdate": - config.YayConf.TimeUpdate = true + config.TimeUpdate = true case "--notimeupdate": - config.YayConf.TimeUpdate = false + config.TimeUpdate = false case "--topdown": - config.YayConf.SortMode = config.TopDown + config.SortMode = TopDown case "--complete": - config.YayConf.Shell = "sh" + config.Shell = "sh" _ = complete() os.Exit(0) case "--fcomplete": - config.YayConf.Shell = "fish" + config.Shell = "fish" _ = complete() os.Exit(0) case "--help": usage() os.Exit(0) case "--noconfirm": - config.YayConf.NoConfirm = true + config.NoConfirm = true fallthrough default: options = append(options, arg) @@ -132,9 +184,9 @@ func main() { err = localStatistics(version) case "-Ss", "-Ssq", "-Sqs": if op == "-Ss" { - config.YayConf.SearchMode = config.Detailed + config.SearchMode = Detailed } else { - config.YayConf.SearchMode = config.Minimal + config.SearchMode = Minimal } if pkgs != nil { @@ -143,14 +195,14 @@ func main() { case "-S": err = install(pkgs, options) case "-Sy": - err = config.PassToPacman("-Sy", nil, nil) + err = passToPacman("-Sy", nil, nil) if err != nil { break } err = install(pkgs, options) case "-Syu", "-Suy", "-Su": if strings.Contains(op, "y") { - err = config.PassToPacman("-Sy", nil, nil) + err = passToPacman("-Sy", nil, nil) if err != nil { break } @@ -159,36 +211,35 @@ func main() { case "-Si": err = syncInfo(pkgs, options) case "yogurt": - config.YayConf.SearchMode = config.NumberMenu + config.SearchMode = NumberMenu if pkgs != nil { err = numberMenu(pkgs, options) } default: if op[0] == 'R' { - vcs.RemovePackage(pkgs) + removeVCSPackage(pkgs) } - err = config.PassToPacman(op, pkgs, options) + err = passToPacman(op, pkgs, options) } var erra error - if vcs.Updated { - erra = vcs.SaveBranchInfo() + if updated { + erra = saveVCSInfo() if erra != nil { fmt.Println(err) } - } if changedConfig { - erra = config.SaveConfig() + erra = config.saveConfig() if erra != nil { fmt.Println(err) } } - erra = config.AlpmHandle.Release() + erra = AlpmHandle.Release() if erra != nil { fmt.Println(err) } @@ -203,12 +254,12 @@ func main() { func numberMenu(pkgS []string, flags []string) (err error) { var num int - aq, err := aur.NarrowSearch(pkgS, true) + aq, err := narrowSearch(pkgS, true) if err != nil { fmt.Println("Error during AUR search:", err) } numaq := len(aq) - pq, numpq, err := pac.Search(pkgS) + pq, numpq, err := searchRepo(pkgS) if err != nil { return } @@ -217,12 +268,12 @@ func numberMenu(pkgS []string, flags []string) (err error) { return fmt.Errorf("no packages match search") } - if config.YayConf.SortMode == config.BottomUp { - printAURSearch(aq, numpq) + if config.SortMode == BottomUp { + aq.printSearch(numpq) pq.PrintSearch() } else { - pq.PrintSearch() - printAURSearch(aq, numpq) + pq.printSearch() + aq.printSearch(numpq) } fmt.Printf("\x1b[32m%s\x1b[0m\nNumbers: ", "Type numbers to install. Separate each number with a space.") @@ -247,13 +298,13 @@ func numberMenu(pkgS []string, flags []string) (err error) { if num > numaq+numpq-1 || num < 0 { continue } else if num > numpq-1 { - if config.YayConf.SortMode == config.BottomUp { + if config.SortMode == BottomUp { aurInstall = append(aurInstall, aq[numaq+numpq-num-1].Name) } else { aurInstall = append(aurInstall, aq[num-numpq].Name) } } else { - if config.YayConf.SortMode == config.BottomUp { + if config.SortMode == BottomUp { repoInstall = append(repoInstall, pq[numpq-num-1].Name()) } else { repoInstall = append(repoInstall, pq[num].Name()) @@ -266,7 +317,7 @@ func numberMenu(pkgS []string, flags []string) (err error) { } if len(aurInstall) != 0 { - err = aur.Install(aurInstall, flags) + err = Install(aurInstall, flags) } return err @@ -274,7 +325,7 @@ func numberMenu(pkgS []string, flags []string) (err error) { // Complete provides completion info for shells func complete() (err error) { - path := os.Getenv("HOME") + "/.cache/yay/aur_" + config.YayConf.Shell + ".cache" + path := os.Getenv("HOME") + "/.cache/yay/aur_" + config.Shell + ".cache" if info, err := os.Stat(path); os.IsNotExist(err) || time.Since(info.ModTime()).Hours() > 48 { os.MkdirAll(os.Getenv("HOME")+"/.cache/yay/", 0755) @@ -284,7 +335,7 @@ func complete() (err error) { return err } - if aur.CreateAURList(out) != nil { + if createAURList(out) != nil { defer os.Remove(path) } err = pac.CreatePackageList(out) diff --git a/completions.go b/completions.go new file mode 100644 index 00000000..69e3df68 --- /dev/null +++ b/completions.go @@ -0,0 +1,60 @@ +package main + +import ( + "bufio" + "fmt" + "net/http" + "os" +) + +//CreateAURList creates a new completion file +func createAURList(out *os.File) (err error) { + resp, err := http.Get("https://aur.archlinux.org/packages.gz") + if err != nil { + return err + } + defer resp.Body.Close() + + scanner := bufio.NewScanner(resp.Body) + + scanner.Scan() + for scanner.Scan() { + fmt.Print(scanner.Text()) + out.WriteString(scanner.Text()) + if config.Shell == "fish" { + fmt.Print("\tAUR\n") + out.WriteString("\tAUR\n") + } else { + fmt.Print("\n") + out.WriteString("\n") + } + } + + return nil +} + + +//CreatePackageList appends Repo packages to completion cache +func CreatePackageList(out *os.File) (err error) { + dbList, err := AlpmHandle.SyncDbs() + if err != nil { + return + } + + _ = dbList.ForEach(func(db alpm.Db) error { + _ = db.PkgCache().ForEach(func(pkg alpm.Package) error { + fmt.Print(pkg.Name()) + out.WriteString(pkg.Name()) + if config.Shell == "fish" { + fmt.Print("\t" + pkg.DB().Name() + "\n") + out.WriteString("\t" + pkg.DB().Name() + "\n") + } else { + fmt.Print("\n") + out.WriteString("\n") + } + return nil + }) + return nil + }) + return nil +} diff --git a/config/config.go b/config.go similarity index 60% rename from config/config.go rename to config.go index 71edebee..f47c3073 100644 --- a/config/config.go +++ b/config.go @@ -1,10 +1,8 @@ -package config +package main import ( "encoding/json" "fmt" - "io" - "net/http" "os" "os/exec" "strings" @@ -42,9 +40,22 @@ type Configuration struct { TimeUpdate bool `json:"timeupdate"` } +var version = "2.116" + +// BaseURL givers the AUR default address. +const BaseURL string = "https://aur.archlinux.org" + +var specialDBsauce = false + +var savedInfo infos + +var configfile string + +// Updated returns if database has been updated +var updated bool // YayConf holds the current config values for yay. -var YayConf Configuration +var config Configuration // AlpmConf holds the current config values for pacman. var AlpmConf alpm.PacmanConfig @@ -52,43 +63,6 @@ var AlpmConf alpm.PacmanConfig // AlpmHandle is the alpm handle used by yay. var AlpmHandle *alpm.Handle -func init() { - defaultSettings(&YayConf) - - var err error - configfile := os.Getenv("HOME") + "/.config/yay/config.json" - - if _, err = os.Stat(configfile); os.IsNotExist(err) { - _ = os.MkdirAll(os.Getenv("HOME")+"/.config/yay", 0755) - // Save the default config if nothing is found - SaveConfig() - } else { - file, err := os.Open(configfile) - if err != nil { - fmt.Println("Error reading config:", err) - } else { - decoder := json.NewDecoder(file) - err = decoder.Decode(&YayConf) - if err != nil { - fmt.Println("Loading default Settings\nError reading config:", err) - defaultSettings(&YayConf) - } - } - } - - AlpmConf, err = readAlpmConfig(YayConf.PacmanConf) - if err != nil { - fmt.Println("Unable to read Pacman conf", err) - os.Exit(1) - } - - AlpmHandle, err = AlpmConf.CreateHandle() - if err != nil { - fmt.Println("Unable to CreateHandle", err) - os.Exit(1) - } -} - func readAlpmConfig(pacmanconf string) (conf alpm.PacmanConfig, err error) { file, err := os.Open(pacmanconf) if err != nil { @@ -102,10 +76,10 @@ func readAlpmConfig(pacmanconf string) (conf alpm.PacmanConfig, err error) { } // SaveConfig writes yay config to file. -func SaveConfig() error { - YayConf.NoConfirm = false +func (config *Configuration) saveConfig() error { + config.NoConfirm = false configfile := os.Getenv("HOME") + "/.config/yay/config.json" - marshalledinfo, _ := json.MarshalIndent(YayConf, "", "\t") + marshalledinfo, _ := json.MarshalIndent(config, "", "\t") in, err := os.OpenFile(configfile, os.O_RDWR|os.O_CREATE, 0755) if err != nil { return err @@ -134,7 +108,7 @@ func defaultSettings(config *Configuration) { } // Editor returns the preferred system editor. -func Editor() string { +func editor() string { switch { case YayConf.Editor != "": editor, err := exec.LookPath(YayConf.Editor) @@ -183,7 +157,7 @@ func Editor() string { // ContinueTask prompts if user wants to continue task. //If NoConfirm is set the action will continue without user input. -func ContinueTask(s string, def string) (cont bool) { +func continueTask(s string, def string) (cont bool) { if YayConf.NoConfirm { return true } @@ -210,60 +184,8 @@ func ContinueTask(s string, def string) (cont bool) { return true } -func downloadFile(path string, url string) (err error) { - // Create the file - out, err := os.Create(path) - if err != nil { - return err - } - defer out.Close() - - // Get the data - resp, err := http.Get(url) - if err != nil { - return err - } - defer resp.Body.Close() - - // Writer the body to file - _, err = io.Copy(out, resp.Body) - return err -} - -// DownloadAndUnpack downloads url tgz and extracts to path. -func DownloadAndUnpack(url string, path string, trim bool) (err error) { - err = os.MkdirAll(path, 0755) - if err != nil { - return - } - - tokens := strings.Split(url, "/") - fileName := tokens[len(tokens)-1] - - tarLocation := path + fileName - defer os.Remove(tarLocation) - - err = downloadFile(tarLocation, url) - if err != nil { - return - } - - if trim { - err = exec.Command("/bin/sh", "-c", - YayConf.TarBin+" --strip-components 2 --include='*/"+fileName[:len(fileName)-7]+"/trunk/' -xf "+tarLocation+" -C "+path).Run() - os.Rename(path+"trunk", path+fileName[:len(fileName)-7]) // kurwa - } else { - err = exec.Command(YayConf.TarBin, "-xf", tarLocation, "-C", path).Run() - } - if err != nil { - return - } - - return -} - // PassToPacman outsorces execution to pacman binary without modifications. -func PassToPacman(op string, pkgs []string, flags []string) error { +func passToPacman(op string, pkgs []string, flags []string) error { var cmd *exec.Cmd var args []string @@ -287,16 +209,3 @@ func PassToPacman(op string, pkgs []string, flags []string) error { err := cmd.Run() return err } - -// Human returns results in Human readable format. -func Human(size int64) string { - floatsize := float32(size) - units := [...]string{"", "Ki", "Mi", "Gi", "Ti", "Pi", "Ei", "Zi", "Yi"} - for _, unit := range units { - if floatsize < 1024 { - return fmt.Sprintf("%.1f %sB", floatsize, unit) - } - floatsize /= 1024 - } - return fmt.Sprintf("%d%s", size, "B") -} diff --git a/depencies.go b/depencies.go new file mode 100644 index 00000000..27fc6e6a --- /dev/null +++ b/depencies.go @@ -0,0 +1,76 @@ +package main + +// BuildDependencies finds packages, on the second run +// compares with a baselist and avoids searching those +func BuildDependencies(baselist []string) func(toCheck []string, isBaseList bool, last bool) (repo []string, notFound []string) { + localDb, err := AlpmHandle.LocalDb() + if err != nil { + panic(err) + } + + dbList, err := AlpmHandle.SyncDbs() + if err != nil { + panic(err) + } + + f := func(c rune) bool { + return c == '>' || c == '<' || c == '=' || c == ' ' + } + + return func(toCheck []string, isBaseList bool, close bool) (repo []string, notFound []string) { + if close { + return + } + + Loop: + for _, dep := range toCheck { + if !isBaseList { + for _, base := range baselist { + if base == dep { + continue Loop + } + } + } + if _, erp := localDb.PkgCache().FindSatisfier(dep); erp == nil { + continue + } else if pkg, erp := dbList.FindSatisfier(dep); erp == nil { + repo = append(repo, pkg.Name()) + } else { + field := strings.FieldsFunc(dep, f) + notFound = append(notFound, field[0]) + } + } + return + } +} + +// DepSatisfier receives a string slice, returns a slice of packages found in +// repos and one of packages not found in repos. Leaves out installed packages. +func DepSatisfier(toCheck []string) (repo []string, notFound []string, err error) { + localDb, err := AlpmHandle.LocalDb() + if err != nil { + return + } + dbList, err := AlpmHandle.SyncDbs() + if err != nil { + return + } + + f := func(c rune) bool { + return c == '>' || c == '<' || c == '=' || c == ' ' + } + + for _, dep := range toCheck { + if _, erp := localDb.PkgCache().FindSatisfier(dep); erp == nil { + continue + } else if pkg, erp := dbList.FindSatisfier(dep); erp == nil { + repo = append(repo, pkg.Name()) + } else { + field := strings.FieldsFunc(dep, f) + notFound = append(notFound, field[0]) + } + } + + err = nil + return +} diff --git a/download.go b/download.go new file mode 100644 index 00000000..24442e21 --- /dev/null +++ b/download.go @@ -0,0 +1,122 @@ +package main + +import ( + "fmt" + "io" + "net/http" + "os" + "os/exec" + "strings" + + rpc "github.com/mikkeloscar/aur" +) + +func downloadFile(path string, url string) (err error) { + // Create the file + out, err := os.Create(path) + if err != nil { + return err + } + defer out.Close() + + // Get the data + resp, err := http.Get(url) + if err != nil { + return err + } + defer resp.Body.Close() + + // Writer the body to file + _, err = io.Copy(out, resp.Body) + return err +} + +// DownloadAndUnpack downloads url tgz and extracts to path. +func downloadAndUnpack(url string, path string, trim bool) (err error) { + err = os.MkdirAll(path, 0755) + if err != nil { + return + } + + tokens := strings.Split(url, "/") + fileName := tokens[len(tokens)-1] + + tarLocation := path + fileName + defer os.Remove(tarLocation) + + err = downloadFile(tarLocation, url) + if err != nil { + return + } + + if trim { + err = exec.Command("/bin/sh", "-c", + YayConf.TarBin+" --strip-components 2 --include='*/"+fileName[:len(fileName)-7]+"/trunk/' -xf "+tarLocation+" -C "+path).Run() + os.Rename(path+"trunk", path+fileName[:len(fileName)-7]) // kurwa + } else { + err = exec.Command(YayConf.TarBin, "-xf", tarLocation, "-C", path).Run() + } + if err != nil { + return + } + + return +} + +func getPkgbuild(pkg string) (err error) { + wd, err := os.Getwd() + if err != nil { + return + } + wd = wd + "/" + + err = getPkgbuildfromABS(pkg, wd) + if err == nil { + return + } + + err = GetPkgbuildfromAUR(pkg, wd) + return +} + +// GetPkgbuild downloads pkgbuild from the ABS. +func getPkgbuildfromABS(pkgN string, path string) (err error) { + dbList, err := AlpmHandle.SyncDbs() + if err != nil { + return + } + + for _, db := range dbList.Slice() { + pkg, err := db.PkgByName(pkgN) + if err == nil { + var url string + if db.Name() == "core" || db.Name() == "extra" { + url = "https://projects.archlinux.org/svntogit/packages.git/snapshot/packages/" + pkg.Name() + ".tar.gz" + } else if db.Name() == "community" { + url = "https://projects.archlinux.org/svntogit/community.git/snapshot/community-packages/" + pkg.Name() + ".tar.gz" + } else { + return fmt.Errorf("Not in standard repositories") + } + fmt.Printf("\x1b[1;32m==>\x1b[1;33m %s \x1b[1;32mfound in ABS.\x1b[0m\n", pkgN) + errD := DownloadAndUnpack(url, path, true) + return errD + } + } + return fmt.Errorf("package not found") +} + +// GetPkgbuild downloads pkgbuild from the AUR. +func getPkgbuildfromAUR(pkgN string, dir string) (err error) { + aq, err := rpc.Info([]string{pkgN}) + if err != nil { + return err + } + + if len(aq) == 0 { + return fmt.Errorf("no results") + } + + fmt.Printf("\x1b[1;32m==>\x1b[1;33m %s \x1b[1;32mfound in AUR.\x1b[0m\n", pkgN) + DownloadAndUnpack(BaseURL+aq[0].URLPath, dir, false) + return +} diff --git a/install.go b/install.go new file mode 100644 index 00000000..355caa5e --- /dev/null +++ b/install.go @@ -0,0 +1,175 @@ +package main + +import ( + "fmt" + "os" + "os/exec" + + "github.com/jguer/yay/pacman" + rpc "github.com/mikkeloscar/aur" +) + +// Install handles package installs +func install(pkgs []string, flags []string) error { + aurs, repos, _ := pac.PackageSlices(pkgs) + + if len(repos) != 0 { + err := PassToPacman("-S", repos, flags) + if err != nil { + fmt.Println("Error installing repo packages.") + } + } + + if len(aurs) != 0 { + err := Install(aurs, flags) + if err != nil { + fmt.Println("Error installing aur packages.") + } + } + return nil +} + +// Install sends system commands to make and install a package from pkgName +func Install(pkgName []string, flags []string) (err error) { + q, err := rpc.Info(pkgName) + if err != nil { + return + } + + if len(q) != len(pkgName) { + fmt.Printf("Some package from list\n%+v\ndoes not exist", pkgName) + } + + var finalrm []string + for _, i := range q { + mrm, err := PkgInstall(&i, flags) + if err != nil { + fmt.Println("Error installing", i.Name, ":", err) + } + finalrm = append(finalrm, mrm...) + } + + if len(finalrm) != 0 { + err = removeMakeDeps(finalrm) + } + + return err +} + + +func setupPackageSpace(a *rpc.Pkg) (pkgbuild *gopkg.PKGBUILD, err error) { + dir := config.BuildDir + a.PackageBase + "/" + + if _, err = os.Stat(dir); !os.IsNotExist(err) { + if !ContinueTask("Directory exists. Clean Build?", "yY") { + _ = os.RemoveAll(config.BuildDir + a.PackageBase) + } + } + + if err = DownloadAndUnpack(BaseURL+a.URLPath, config.BuildDir, false); err != nil { + return + } + + if !ContinueTask("Edit PKGBUILD?", "yY") { + editcmd := exec.Command(Editor(), dir+"PKGBUILD") + editcmd.Stdin, editcmd.Stdout, editcmd.Stderr = os.Stdin, os.Stdout, os.Stderr + editcmd.Run() + } + + pkgbuild, err = gopkg.ParseSRCINFO(dir + ".SRCINFO") + if err == nil { + for _, pkgsource := range pkgbuild.Source { + owner, repo := vcs.ParseSource(pkgsource) + if owner != "" && repo != "" { + err = vcs.BranchInfo(a.Name, owner, repo) + if err != nil { + fmt.Println(err) + } + } + } + } + + err = os.Chdir(dir) + if err != nil { + return + } + + return +} + +// PkgInstall handles install from Info Result. +func PkgInstall(a *rpc.Pkg, flags []string) (finalmdeps []string, err error) { + fmt.Printf("\x1b[1;32m==> Installing\x1b[33m %s\x1b[0m\n", a.Name) + if a.Maintainer == "" { + fmt.Println("\x1b[1;31;40m==> Warning:\x1b[0;;40m This package is orphaned.\x1b[0m") + } + + _, err = setupPackageSpace(a) + if err != nil { + return + } + + if specialDBsauce { + return + } + + runDeps, makeDeps, err := PkgDependencies(a) + if err != nil { + return + } + + repoDeps := append(runDeps[0], makeDeps[0]...) + aurDeps := append(runDeps[1], makeDeps[1]...) + finalmdeps = append(finalmdeps, makeDeps[0]...) + finalmdeps = append(finalmdeps, makeDeps[1]...) + + if len(aurDeps) != 0 || len(repoDeps) != 0 { + if !ContinueTask("Continue?", "nN") { + return finalmdeps, fmt.Errorf("user did not like the dependencies") + } + } + + aurQ, _ := rpc.Info(aurDeps) + if len(aurQ) != len(aurDeps) { + (Query)(aurQ).MissingPackage(aurDeps) + if !ContinueTask("Continue?", "nN") { + return finalmdeps, fmt.Errorf("unable to install dependencies") + } + } + + var depArgs []string + if config.NoConfirm { + depArgs = []string{"--asdeps", "--noconfirm"} + } else { + depArgs = []string{"--asdeps"} + } + // Repo dependencies + if len(repoDeps) != 0 { + errR := PassToPacman("-S", repoDeps, depArgs) + if errR != nil { + return finalmdeps, errR + } + } + + // Handle AUR dependencies + for _, dep := range aurQ { + finalmdepsR, errA := PkgInstall(&dep, depArgs) + finalmdeps = append(finalmdeps, finalmdepsR...) + + if errA != nil { + pacman.CleanRemove(repoDeps) + pacman.CleanRemove(aurDeps) + return finalmdeps, errA + } + } + + args := []string{"-sri"} + args = append(args, flags...) + makepkgcmd := exec.Command(config.MakepkgBin, args...) + makepkgcmd.Stdin, makepkgcmd.Stdout, makepkgcmd.Stderr = os.Stdin, os.Stdout, os.Stderr + err = makepkgcmd.Run() + if err == nil { + _ = vcs.SaveBranchInfo() + } + return +} diff --git a/install/i.go b/install/i.go deleted file mode 100644 index 59f7c028..00000000 --- a/install/i.go +++ /dev/null @@ -1,39 +0,0 @@ -package install - -import "fmt" - -// Install sends system commands to make and install a package from pkgName -func Install(pkgName []string, flags []string) (err error) { - q, err := rpc.Info(pkgName) - if err != nil { - return - } - - if len(q) != len(pkgName) { - fmt.Printf("Some package from list\n%+v\ndoes not exist", pkgName) - } - - var finalrm []string - for _, i := range q { - mrm, err := PkgInstall(&i, flags) - if err != nil { - fmt.Println("Error installing", i.Name, ":", err) - } - finalrm = append(finalrm, mrm...) - } - - if len(finalrm) != 0 { - err = RemoveMakeDeps(finalrm) - } - - return err -} - -// PkgInstall handles install from Info Result. -func PkgInstall(a []*rpc.Pkg, flags []string) (finalmdeps []string, err error) { - for _, pkg := range a { - if pkg.Maintainer == "" { - fmt.Println("\x1b[1;31;40m==> Warning:\x1b[0;;40m This package is orphaned.\x1b[0m") - } - } -} diff --git a/pacman/pacman.go b/pacman/pacman.go index fd271644..d723fdb8 100644 --- a/pacman/pacman.go +++ b/pacman/pacman.go @@ -1,428 +1 @@ package pacman - -import ( - "fmt" - "os" - "strings" - - "github.com/jguer/go-alpm" - "github.com/jguer/yay/config" -) - -// Query holds the results of a repository search. -type Query []alpm.Package - -// Search handles repo searches. Creates a RepoSearch struct. -func Search(pkgInputN []string) (s Query, n int, err error) { - dbList, err := config.AlpmHandle.SyncDbs() - if err != nil { - return - } - - // BottomUp functions - initL := func(len int) int { - if config.YayConf.SortMode == config.TopDown { - return 0 - } else { - return len - 1 - } - } - compL := func(len int, i int) bool { - if config.YayConf.SortMode == config.TopDown { - return i < len - } else { - return i > -1 - } - } - finalL := func(i int) int { - if config.YayConf.SortMode == config.TopDown { - return i + 1 - } else { - return i - 1 - } - } - - dbS := dbList.Slice() - lenDbs := len(dbS) - for f := initL(lenDbs); compL(lenDbs, f); f = finalL(f) { - pkgS := dbS[f].PkgCache().Slice() - lenPkgs := len(pkgS) - for i := initL(lenPkgs); compL(lenPkgs, i); i = finalL(i) { - match := true - for _, pkgN := range pkgInputN { - if !(strings.Contains(pkgS[i].Name(), pkgN) || strings.Contains(strings.ToLower(pkgS[i].Description()), pkgN)) { - match = false - break - } - } - - if match { - n++ - s = append(s, pkgS[i]) - } - } - } - return -} - -//PrintSearch receives a RepoSearch type and outputs pretty text. -func (s Query) PrintSearch() { - for i, res := range s { - var toprint string - if config.YayConf.SearchMode == config.NumberMenu { - if config.YayConf.SortMode == config.BottomUp { - toprint += fmt.Sprintf("\x1b[33m%d\x1b[0m ", len(s)-i-1) - } else { - toprint += fmt.Sprintf("\x1b[33m%d\x1b[0m ", i) - } - } else if config.YayConf.SearchMode == config.Minimal { - fmt.Println(res.Name()) - continue - } - toprint += fmt.Sprintf("\x1b[1m%s/\x1b[33m%s \x1b[36m%s \x1b[0m", - res.DB().Name(), res.Name(), res.Version()) - - if len(res.Groups().Slice()) != 0 { - toprint += fmt.Sprint(res.Groups().Slice(), " ") - } - - localDb, err := config.AlpmHandle.LocalDb() - if err == nil { - if _, err = localDb.PkgByName(res.Name()); err == nil { - toprint += fmt.Sprintf("\x1b[32;40mInstalled\x1b[0m") - } - } - - toprint += "\n " + res.Description() - fmt.Println(toprint) - } -} - -// PackageSlices separates an input slice into aur and repo slices -func PackageSlices(toCheck []string) (aur []string, repo []string, err error) { - dbList, err := config.AlpmHandle.SyncDbs() - if err != nil { - return - } - - for _, pkg := range toCheck { - found := false - - _ = dbList.ForEach(func(db alpm.Db) error { - if found { - return nil - } - - _, err = db.PkgByName(pkg) - if err == nil { - found = true - repo = append(repo, pkg) - } - return nil - }) - - if !found { - if _, errdb := dbList.PkgCachebyGroup(pkg); errdb == nil { - repo = append(repo, pkg) - } else { - aur = append(aur, pkg) - } - } - } - - err = nil - return -} - -// BuildDependencies finds packages, on the second run -// compares with a baselist and avoids searching those -func BuildDependencies(baselist []string) func(toCheck []string, isBaseList bool, last bool) (repo []string, notFound []string) { - localDb, err := config.AlpmHandle.LocalDb() - if err != nil { - panic(err) - } - - dbList, err := config.AlpmHandle.SyncDbs() - if err != nil { - panic(err) - } - - f := func(c rune) bool { - return c == '>' || c == '<' || c == '=' || c == ' ' - } - - return func(toCheck []string, isBaseList bool, close bool) (repo []string, notFound []string) { - if close { - return - } - - Loop: - for _, dep := range toCheck { - if !isBaseList { - for _, base := range baselist { - if base == dep { - continue Loop - } - } - } - if _, erp := localDb.PkgCache().FindSatisfier(dep); erp == nil { - continue - } else if pkg, erp := dbList.FindSatisfier(dep); erp == nil { - repo = append(repo, pkg.Name()) - } else { - field := strings.FieldsFunc(dep, f) - notFound = append(notFound, field[0]) - } - } - return - } -} - -// DepSatisfier receives a string slice, returns a slice of packages found in -// repos and one of packages not found in repos. Leaves out installed packages. -func DepSatisfier(toCheck []string) (repo []string, notFound []string, err error) { - localDb, err := config.AlpmHandle.LocalDb() - if err != nil { - return - } - dbList, err := config.AlpmHandle.SyncDbs() - if err != nil { - return - } - - f := func(c rune) bool { - return c == '>' || c == '<' || c == '=' || c == ' ' - } - - for _, dep := range toCheck { - if _, erp := localDb.PkgCache().FindSatisfier(dep); erp == nil { - continue - } else if pkg, erp := dbList.FindSatisfier(dep); erp == nil { - repo = append(repo, pkg.Name()) - } else { - field := strings.FieldsFunc(dep, f) - notFound = append(notFound, field[0]) - } - } - - err = nil - return -} - -// PkgNameSlice returns a slice of package names -// func (s Query) PkgNameSlice() (pkgNames []string) { -// for _, e := range s { -// pkgNames = append(pkgNames, e.Name()) -// } -// return -// } - -// CleanRemove sends a full removal command to pacman with the pkgName slice -func CleanRemove(pkgName []string) (err error) { - if len(pkgName) == 0 { - return nil - } - - err = config.PassToPacman("-Rsnc", pkgName, []string{"--noconfirm"}) - return err -} - -// ForeignPackages returns a map of foreign packages, with their version and date as values. -func ForeignPackages() (foreign map[string]alpm.Package, err error) { - localDb, err := config.AlpmHandle.LocalDb() - if err != nil { - return - } - dbList, err := config.AlpmHandle.SyncDbs() - if err != nil { - return - } - - foreign = make(map[string]alpm.Package) - - f := func(k alpm.Package) error { - found := false - _ = dbList.ForEach(func(d alpm.Db) error { - if found { - return nil - } - _, err = d.PkgByName(k.Name()) - if err == nil { - found = true - } - return nil - }) - - if !found { - foreign[k.Name()] = k - } - return nil - } - - err = localDb.PkgCache().ForEach(f) - return -} - - -// Statistics returns statistics about packages installed in system -func Statistics() (info struct { - Totaln int - Expln int - TotalSize int64 -}, err error) { - var tS int64 // TotalSize - var nPkg int - var ePkg int - - localDb, err := config.AlpmHandle.LocalDb() - if err != nil { - return - } - - for _, pkg := range localDb.PkgCache().Slice() { - tS += pkg.ISize() - nPkg++ - if pkg.Reason() == 0 { - ePkg++ - } - } - - info = struct { - Totaln int - Expln int - TotalSize int64 - }{ - nPkg, ePkg, tS, - } - - return -} - -// BiggestPackages prints the name of the ten biggest packages in the system. -func BiggestPackages() { - - localDb, err := config.AlpmHandle.LocalDb() - if err != nil { - return - } - - pkgCache := localDb.PkgCache() - pkgS := pkgCache.SortBySize().Slice() - - if len(pkgS) < 10 { - return - } - - for i := 0; i < 10; i++ { - fmt.Printf("%s: \x1B[0;33m%s\x1B[0m\n", pkgS[i].Name(), config.Human(pkgS[i].ISize())) - } - // Could implement size here as well, but we just want the general idea -} - -// HangingPackages returns a list of packages installed as deps -// and unneeded by the system -func HangingPackages() (hanging []string, err error) { - localDb, err := config.AlpmHandle.LocalDb() - if err != nil { - return - } - - f := func(pkg alpm.Package) error { - if pkg.Reason() != alpm.PkgReasonDepend { - return nil - } - requiredby := pkg.ComputeRequiredBy() - if len(requiredby) == 0 { - hanging = append(hanging, pkg.Name()) - fmt.Printf("%s: \x1B[0;33m%s\x1B[0m\n", pkg.Name(), config.Human(pkg.ISize())) - - } - return nil - } - - err = localDb.PkgCache().ForEach(f) - return -} - -// SliceHangingPackages returns a list of packages installed as deps -// and unneeded by the system from a provided list of package names. -func SliceHangingPackages(pkgS []string) (hanging []string) { - localDb, err := config.AlpmHandle.LocalDb() - if err != nil { - return - } - -big: - for _, pkgName := range pkgS { - for _, hangN := range hanging { - if hangN == pkgName { - continue big - } - } - - pkg, err := localDb.PkgByName(pkgName) - if err == nil { - if pkg.Reason() != alpm.PkgReasonDepend { - continue - } - - requiredby := pkg.ComputeRequiredBy() - if len(requiredby) == 0 { - hanging = append(hanging, pkgName) - fmt.Printf("%s: \x1B[0;33m%s\x1B[0m\n", pkg.Name(), config.Human(pkg.ISize())) - } - } - } - return -} - -// GetPkgbuild downloads pkgbuild from the ABS. -func GetPkgbuild(pkgN string, path string) (err error) { - dbList, err := config.AlpmHandle.SyncDbs() - if err != nil { - return - } - - for _, db := range dbList.Slice() { - pkg, err := db.PkgByName(pkgN) - if err == nil { - var url string - if db.Name() == "core" || db.Name() == "extra" { - url = "https://projects.archlinux.org/svntogit/packages.git/snapshot/packages/" + pkg.Name() + ".tar.gz" - } else if db.Name() == "community" { - url = "https://projects.archlinux.org/svntogit/community.git/snapshot/community-packages/" + pkg.Name() + ".tar.gz" - } else { - return fmt.Errorf("Not in standard repositories") - } - fmt.Printf("\x1b[1;32m==>\x1b[1;33m %s \x1b[1;32mfound in ABS.\x1b[0m\n", pkgN) - errD := config.DownloadAndUnpack(url, path, true) - return errD - } - } - return fmt.Errorf("package not found") -} - -//CreatePackageList appends Repo packages to completion cache -func CreatePackageList(out *os.File) (err error) { - dbList, err := config.AlpmHandle.SyncDbs() - if err != nil { - return - } - - _ = dbList.ForEach(func(db alpm.Db) error { - _ = db.PkgCache().ForEach(func(pkg alpm.Package) error { - fmt.Print(pkg.Name()) - out.WriteString(pkg.Name()) - if config.YayConf.Shell == "fish" { - fmt.Print("\t" + pkg.DB().Name() + "\n") - out.WriteString("\t" + pkg.DB().Name() + "\n") - } else { - fmt.Print("\n") - out.WriteString("\n") - } - return nil - }) - return nil - }) - return nil -} diff --git a/pacman/pacman_test.go b/pacman_test.go similarity index 98% rename from pacman/pacman_test.go rename to pacman_test.go index 9a7ff12b..a8852a4c 100644 --- a/pacman/pacman_test.go +++ b/pacman_test.go @@ -1,4 +1,4 @@ -package pacman +package main import ( "os" diff --git a/print.go b/print.go new file mode 100644 index 00000000..8836aab5 --- /dev/null +++ b/print.go @@ -0,0 +1,183 @@ +package main + +import ( + "fmt" + + rpc "github.com/mikkeloscar/aur" +) + +// Human returns results in Human readable format. +func human(size int64) string { + floatsize := float32(size) + units := [...]string{"", "Ki", "Mi", "Gi", "Ti", "Pi", "Ei", "Zi", "Yi"} + for _, unit := range units { + if floatsize < 1024 { + return fmt.Sprintf("%.1f %sB", floatsize, unit) + } + floatsize /= 1024 + } + return fmt.Sprintf("%d%s", size, "B") +} + +// PrintSearch handles printing search results in a given format +func (q aurQuery) printSearch(start int) { + localDb, _ := config.AlpmHandle.LocalDb() + + for i, res := range q { + var toprint string + if config.YayConf.SearchMode == config.NumberMenu { + if config.YayConf.SortMode == config.BottomUp { + toprint += fmt.Sprintf("\x1b[33m%d\x1b[0m ", len(q)+start-i-1) + } else { + toprint += fmt.Sprintf("\x1b[33m%d\x1b[0m ", start+i) + } + } else if config.YayConf.SearchMode == config.Minimal { + fmt.Println(res.Name) + continue + } + toprint += fmt.Sprintf("\x1b[1m%s/\x1b[33m%s \x1b[36m%s \x1b[0m(%d) ", "aur", res.Name, res.Version, res.NumVotes) + if res.Maintainer == "" { + toprint += fmt.Sprintf("\x1b[31;40m(Orphaned)\x1b[0m ") + } + + if res.OutOfDate != 0 { + toprint += fmt.Sprintf("\x1b[31;40m(Out-of-date)\x1b[0m ") + } + + if _, err := localDb.PkgByName(res.Name); err == nil { + toprint += fmt.Sprintf("\x1b[32;40mInstalled\x1b[0m") + } + toprint += "\n " + res.Description + fmt.Println(toprint) + } + + return +} + +//PrintSearch receives a RepoSearch type and outputs pretty text. +func (s repoQuery) printSearch() { + for i, res := range s { + var toprint string + if config.SearchMode == NumberMenu { + if config.SortMode == BottomUp { + toprint += fmt.Sprintf("\x1b[33m%d\x1b[0m ", len(s)-i-1) + } else { + toprint += fmt.Sprintf("\x1b[33m%d\x1b[0m ", i) + } + } else if config.SearchMode == Minimal { + fmt.Println(res.Name()) + continue + } + toprint += fmt.Sprintf("\x1b[1m%s/\x1b[33m%s \x1b[36m%s \x1b[0m", + res.DB().Name(), res.Name(), res.Version()) + + if len(res.Groups().Slice()) != 0 { + toprint += fmt.Sprint(res.Groups().Slice(), " ") + } + + localDb, err := AlpmHandle.LocalDb() + if err == nil { + if _, err = localDb.PkgByName(res.Name()); err == nil { + toprint += fmt.Sprintf("\x1b[32;40mInstalled\x1b[0m") + } + } + + toprint += "\n " + res.Description() + fmt.Println(toprint) + } +} + +func printDeps(repoDeps []string, aurDeps []string) { + if len(repoDeps) != 0 { + fmt.Print("\x1b[1;32m==> Repository dependencies: \x1b[0m") + for _, repoD := range repoDeps { + fmt.Print("\x1b[33m", repoD, " \x1b[0m") + } + fmt.Print("\n") + + } + if len(aurDeps) != 0 { + fmt.Print("\x1b[1;32m==> AUR dependencies: \x1b[0m") + for _, aurD := range aurDeps { + fmt.Print("\x1b[33m", aurD, " \x1b[0m") + } + fmt.Print("\n") + } +} + +// PrintInfo prints package info like pacman -Si. +func PrintInfo(a *rpc.Pkg) { + fmt.Println("\x1b[1;37mRepository :\x1b[0m", "aur") + fmt.Println("\x1b[1;37mName :\x1b[0m", a.Name) + fmt.Println("\x1b[1;37mVersion :\x1b[0m", a.Version) + fmt.Println("\x1b[1;37mDescription :\x1b[0m", a.Description) + if a.URL != "" { + fmt.Println("\x1b[1;37mURL :\x1b[0m", a.URL) + } else { + fmt.Println("\x1b[1;37mURL :\x1b[0m", "None") + } + fmt.Println("\x1b[1;37mLicenses :\x1b[0m", a.License) + + // if len(a.Provides) != 0 { + // fmt.Println("\x1b[1;37mProvides :\x1b[0m", a.Provides) + // } else { + // fmt.Println("\x1b[1;37mProvides :\x1b[0m", "None") + // } + + if len(a.Depends) != 0 { + fmt.Println("\x1b[1;37mDepends On :\x1b[0m", a.Depends) + } else { + fmt.Println("\x1b[1;37mDepends On :\x1b[0m", "None") + } + + if len(a.MakeDepends) != 0 { + fmt.Println("\x1b[1;37mMake depends On :\x1b[0m", a.MakeDepends) + } else { + fmt.Println("\x1b[1;37mMake depends On :\x1b[0m", "None") + } + + if len(a.OptDepends) != 0 { + fmt.Println("\x1b[1;37mOptional Deps :\x1b[0m", a.OptDepends) + } else { + fmt.Println("\x1b[1;37mOptional Deps :\x1b[0m", "None") + } + + if len(a.Conflicts) != 0 { + fmt.Println("\x1b[1;37mConflicts With :\x1b[0m", a.Conflicts) + } else { + fmt.Println("\x1b[1;37mConflicts With :\x1b[0m", "None") + } + + if a.Maintainer != "" { + fmt.Println("\x1b[1;37mMaintainer :\x1b[0m", a.Maintainer) + } else { + fmt.Println("\x1b[1;37mMaintainer :\x1b[0m", "None") + } + fmt.Println("\x1b[1;37mVotes :\x1b[0m", a.NumVotes) + fmt.Println("\x1b[1;37mPopularity :\x1b[0m", a.Popularity) + + if a.OutOfDate != 0 { + fmt.Println("\x1b[1;37mOut-of-date :\x1b[0m", "Yes") + } +} + +// BiggestPackages prints the name of the ten biggest packages in the system. +func biggestPackages() { + + localDb, err := AlpmHandle.LocalDb() + if err != nil { + return + } + + pkgCache := localDb.PkgCache() + pkgS := pkgCache.SortBySize().Slice() + + if len(pkgS) < 10 { + return + } + + for i := 0; i < 10; i++ { + fmt.Printf("%s: \x1B[0;33m%s\x1B[0m\n", pkgS[i].Name(), Human(pkgS[i].ISize())) + } + // Could implement size here as well, but we just want the general idea +} diff --git a/query.go b/query.go index 29104822..88d44839 100644 --- a/query.go +++ b/query.go @@ -2,51 +2,99 @@ package main import ( "fmt" + "sort" + "strings" - "github.com/jguer/yay/aur" - "github.com/jguer/yay/config" + alpm "github.com/jguer/go-alpm" pac "github.com/jguer/yay/pacman" rpc "github.com/mikkeloscar/aur" ) -// PrintSearch handles printing search results in a given format -func printAURSearch(q aur.Query, start int) { - localDb, _ := config.AlpmHandle.LocalDb() +// Query is a collection of Results +type aurQuery []rpc.Pkg - for i, res := range q { - var toprint string - if config.YayConf.SearchMode == config.NumberMenu { - if config.YayConf.SortMode == config.BottomUp { - toprint += fmt.Sprintf("\x1b[33m%d\x1b[0m ", len(q)+start-i-1) - } else { - toprint += fmt.Sprintf("\x1b[33m%d\x1b[0m ", start+i) +// Query holds the results of a repository search. +type repoQuery []alpm.Package + +func (q aurQuery) Len() int { + return len(q) +} + +func (q aurQuery) Less(i, j int) bool { + if config.SortMode == BottomUp { + return q[i].NumVotes < q[j].NumVotes + } + return q[i].NumVotes > q[j].NumVotes +} + +func (q aurQuery) Swap(i, j int) { + q[i], q[j] = q[j], q[i] +} + +// MissingPackage warns if the Query was unable to find a package +func (q aurQuery) missingPackage(pkgS []string) { + for _, depName := range pkgS { + found := false + for _, dep := range q { + if dep.Name == depName { + found = true + break } - } else if config.YayConf.SearchMode == config.Minimal { - fmt.Println(res.Name) - continue - } - toprint += fmt.Sprintf("\x1b[1m%s/\x1b[33m%s \x1b[36m%s \x1b[0m(%d) ", "aur", res.Name, res.Version, res.NumVotes) - if res.Maintainer == "" { - toprint += fmt.Sprintf("\x1b[31;40m(Orphaned)\x1b[0m ") } - if res.OutOfDate != 0 { - toprint += fmt.Sprintf("\x1b[31;40m(Out-of-date)\x1b[0m ") + if !found { + fmt.Println("\x1b[31mUnable to find", depName, "in AUR\x1b[0m") } + } + return +} - if _, err := localDb.PkgByName(res.Name); err == nil { - toprint += fmt.Sprintf("\x1b[32;40mInstalled\x1b[0m") - } - toprint += "\n " + res.Description - fmt.Println(toprint) +// NarrowSearch searches AUR and narrows based on subarguments +func narrowSearch(pkgS []string, sortS bool) (aurQuery, error) { + if len(pkgS) == 0 { + return nil, nil } - return + r, err := rpc.Search(pkgS[0]) + if err != nil { + return nil, err + } + + if len(pkgS) == 1 { + if sortS { + sort.Sort(Query(r)) + } + return r, err + } + + var aq aurQuery + var n int + + for _, res := range r { + match := true + for _, pkgN := range pkgS[1:] { + if !(strings.Contains(res.Name, pkgN) || strings.Contains(strings.ToLower(res.Description), pkgN)) { + match = false + break + } + } + + if match { + n++ + aq = append(aq, res) + } + } + + if sortS { + sort.Sort(aq) + } + + return aq, err } // SyncSearch presents a query to the local repos and to the AUR. func syncSearch(pkgS []string) (err error) { - aq, err := aur.NarrowSearch(pkgS, true) + aq, err := narrowSearch(pkgS, true) if err != nil { return err } @@ -55,12 +103,12 @@ func syncSearch(pkgS []string) (err error) { return err } - if config.YayConf.SortMode == config.BottomUp { - printAURSearch(aq, 0) + if config.SortMode == BottomUp { + aq.printAURSearch(0) pq.PrintSearch() } else { pq.PrintSearch() - printAURSearch(aq, 0) + aq.printAURSearch(0) } return nil @@ -79,12 +127,12 @@ func syncInfo(pkgS []string, flags []string) (err error) { fmt.Println(err) } for _, aurP := range q { - aur.PrintInfo(&aurP) + PrintInfo(&aurP) } } if len(repoS) != 0 { - err = config.PassToPacman("-Si", repoS, flags) + err = PassToPacman("-Si", repoS, flags) } return @@ -107,7 +155,7 @@ func localStatistics(version string) error { fmt.Printf("\x1B[1;32mTotal installed packages: \x1B[0;33m%d\x1B[0m\n", info.Totaln) fmt.Printf("\x1B[1;32mTotal foreign installed packages: \x1B[0;33m%d\x1B[0m\n", len(foreignS)) fmt.Printf("\x1B[1;32mExplicitly installed packages: \x1B[0;33m%d\x1B[0m\n", info.Expln) - fmt.Printf("\x1B[1;32mTotal Size occupied by packages: \x1B[0;33m%s\x1B[0m\n", config.Human(info.TotalSize)) + fmt.Printf("\x1B[1;32mTotal Size occupied by packages: \x1B[0;33m%s\x1B[0m\n", Human(info.TotalSize)) fmt.Println("\x1B[1;34m===========================================\x1B[0m") fmt.Println("\x1B[1;32mTen biggest packages\x1B[0m") pac.BiggestPackages() @@ -120,10 +168,10 @@ func localStatistics(version string) error { i++ } - var q aur.Query + var q aurQuery var j int for i = len(keys); i != 0; i = j { - j = i - config.YayConf.RequestSplitN + j = i - config.RequestSplitN if j < 0 { j = 0 } @@ -167,3 +215,252 @@ func localStatistics(version string) error { return nil } + +// Search handles repo searches. Creates a RepoSearch struct. +func queryRepo(pkgInputN []string) (s repoQuery, n int, err error) { + dbList, err := AlpmHandle.SyncDbs() + if err != nil { + return + } + + // BottomUp functions + initL := func(len int) int { + if config.SortMode == TopDown { + return 0 + } + return len - 1 + } + compL := func(len int, i int) bool { + if config.SortMode == TopDown { + return i < len + } + return i > -1 + } + finalL := func(i int) int { + if config.SortMode == TopDown { + return i + 1 + } + return i - 1 + } + + dbS := dbList.Slice() + lenDbs := len(dbS) + for f := initL(lenDbs); compL(lenDbs, f); f = finalL(f) { + pkgS := dbS[f].PkgCache().Slice() + lenPkgs := len(pkgS) + for i := initL(lenPkgs); compL(lenPkgs, i); i = finalL(i) { + match := true + for _, pkgN := range pkgInputN { + if !(strings.Contains(pkgS[i].Name(), pkgN) || strings.Contains(strings.ToLower(pkgS[i].Description()), pkgN)) { + match = false + break + } + } + + if match { + n++ + s = append(s, pkgS[i]) + } + } + } + return +} + +// PkgDependencies returns package dependencies not installed belonging to AUR +// 0 is Repo, 1 is Foreign. +func pkgDependencies(a *rpc.Pkg) (runDeps [2][]string, makeDeps [2][]string, err error) { + var q aurQuery + if len(a.Depends) == 0 && len(a.MakeDepends) == 0 { + q, err = rpc.Info([]string{a.Name}) + if len(q) == 0 || err != nil { + err = fmt.Errorf("Unable to search dependencies, %s", err) + return + } + } else { + q = append(q, *a) + } + + depSearch := pacman.BuildDependencies(a.Depends) + if len(a.Depends) != 0 { + runDeps[0], runDeps[1] = depSearch(q[0].Depends, true, false) + if len(runDeps[0]) != 0 || len(runDeps[1]) != 0 { + fmt.Println("\x1b[1;32m=>\x1b[1;33m Run Dependencies: \x1b[0m") + printDeps(runDeps[0], runDeps[1]) + } + } + + if len(a.MakeDepends) != 0 { + makeDeps[0], makeDeps[1] = depSearch(q[0].MakeDepends, false, false) + if len(makeDeps[0]) != 0 || len(makeDeps[1]) != 0 { + fmt.Println("\x1b[1;32m=>\x1b[1;33m Make Dependencies: \x1b[0m") + printDeps(makeDeps[0], makeDeps[1]) + } + } + depSearch(a.MakeDepends, false, true) + + err = nil + return +} + +// PackageSlices separates an input slice into aur and repo slices +func packageSlices(toCheck []string) (aur []string, repo []string, err error) { + dbList, err := AlpmHandle.SyncDbs() + if err != nil { + return + } + + for _, pkg := range toCheck { + found := false + + _ = dbList.ForEach(func(db alpm.Db) error { + if found { + return nil + } + + _, err = db.PkgByName(pkg) + if err == nil { + found = true + repo = append(repo, pkg) + } + return nil + }) + + if !found { + if _, errdb := dbList.PkgCachebyGroup(pkg); errdb == nil { + repo = append(repo, pkg) + } else { + aur = append(aur, pkg) + } + } + } + + err = nil + return +} + +// ForeignPackages returns a map of foreign packages, with their version and date as values. +func foreignPackages() (foreign map[string]alpm.Package, err error) { + localDb, err := AlpmHandle.LocalDb() + if err != nil { + return + } + dbList, err := AlpmHandle.SyncDbs() + if err != nil { + return + } + + foreign = make(map[string]alpm.Package) + + f := func(k alpm.Package) error { + found := false + _ = dbList.ForEach(func(d alpm.Db) error { + if found { + return nil + } + _, err = d.PkgByName(k.Name()) + if err == nil { + found = true + } + return nil + }) + + if !found { + foreign[k.Name()] = k + } + return nil + } + + err = localDb.PkgCache().ForEach(f) + return +} + +// HangingPackages returns a list of packages installed as deps +// and unneeded by the system +func hangingPackages() (hanging []string, err error) { + localDb, err := AlpmHandle.LocalDb() + if err != nil { + return + } + + f := func(pkg alpm.Package) error { + if pkg.Reason() != alpm.PkgReasonDepend { + return nil + } + requiredby := pkg.ComputeRequiredBy() + if len(requiredby) == 0 { + hanging = append(hanging, pkg.Name()) + fmt.Printf("%s: \x1B[0;33m%s\x1B[0m\n", pkg.Name(), Human(pkg.ISize())) + + } + return nil + } + + err = localDb.PkgCache().ForEach(f) + return +} + +// Statistics returns statistics about packages installed in system +func statistics() (info struct { + Totaln int + Expln int + TotalSize int64 +}, err error) { + var tS int64 // TotalSize + var nPkg int + var ePkg int + + localDb, err := AlpmHandle.LocalDb() + if err != nil { + return + } + + for _, pkg := range localDb.PkgCache().Slice() { + tS += pkg.ISize() + nPkg++ + if pkg.Reason() == 0 { + ePkg++ + } + } + + info = struct { + Totaln int + Expln int + TotalSize int64 + }{ + nPkg, ePkg, tS, + } + + return +} + +// SliceHangingPackages returns a list of packages installed as deps +// and unneeded by the system from a provided list of package names. +func sliceHangingPackages(pkgS []string) (hanging []string) { + localDb, err := AlpmHandle.LocalDb() + if err != nil { + return + } + +big: + for _, pkgName := range pkgS { + for _, hangN := range hanging { + if hangN == pkgName { + continue big + } + } + + pkg, err := localDb.PkgByName(pkgName) + if err == nil { + if pkg.Reason() != alpm.PkgReasonDepend { + continue + } + + requiredby := pkg.ComputeRequiredBy() + if len(requiredby) == 0 { + hanging = append(hanging, pkgName) + fmt.Printf("%s: \x1B[0;33m%s\x1B[0m\n", pkg.Name(), Human(pkg.ISize())) + } + } + } + return +} diff --git a/upgrade.go b/upgrade.go index 2b3b1b72..745f71d9 100644 --- a/upgrade.go +++ b/upgrade.go @@ -10,8 +10,6 @@ import ( "unicode" alpm "github.com/jguer/go-alpm" - "github.com/jguer/yay/aur" - "github.com/jguer/yay/config" rpc "github.com/mikkeloscar/aur" pkgb "github.com/mikkeloscar/gopkgbuild" ) @@ -62,11 +60,11 @@ func (u upSlice) Less(i, j int) bool { // FilterPackages filters packages based on source and type. func FilterPackages() (local []alpm.Package, remote []alpm.Package, localNames []string, remoteNames []string, err error) { - localDb, err := config.AlpmHandle.LocalDb() + localDb, err := AlpmHandle.LocalDb() if err != nil { return } - dbList, err := config.AlpmHandle.SyncDbs() + dbList, err := AlpmHandle.SyncDbs() if err != nil { return } @@ -194,7 +192,7 @@ func upAUR(remote []alpm.Package, remoteNames []string) (toUpgrade upSlice, err for i := len(remote); i != 0; i = j { //Split requests so AUR RPC doesn't get mad at us. - j = i - config.YayConf.RequestSplitN + j = i - config.RequestSplitN if j < 0 { j = 0 } @@ -218,7 +216,7 @@ func upAUR(remote []alpm.Package, remoteNames []string) (toUpgrade upSlice, err if x > max { break } else if qtemp[x].Name == local[i].Name() { - if (config.YayConf.TimeUpdate && (int64(qtemp[x].LastModified) > local[i].BuildDate().Unix())) || + if (config.TimeUpdate && (int64(qtemp[x].LastModified) > local[i].BuildDate().Unix())) || (alpm.VerCmp(local[i].Version(), qtemp[x].Version) < 0) { packageC <- upgrade{qtemp[x].Name, "aur", local[i].Version(), qtemp[x].Version} } @@ -248,7 +246,7 @@ func upAUR(remote []alpm.Package, remoteNames []string) (toUpgrade upSlice, err // repo gathers local packages and checks if they have new versions. // Output: Upgrade type package list. func upRepo(local []alpm.Package) (upSlice, error) { - dbList, err := config.AlpmHandle.SyncDbs() + dbList, err := AlpmHandle.SyncDbs() if err != nil { return nil, err } @@ -259,14 +257,14 @@ primeloop: newPkg := pkg.NewVersion(dbList) if newPkg != nil { - for _, ignorePkg := range config.AlpmConf.IgnorePkg { + for _, ignorePkg := range AlpmConf.IgnorePkg { if pkg.Name() == ignorePkg { fmt.Printf("\x1b[33mwarning:\x1b[0m %s (ignored pkg) ignoring upgrade (%s -> %s)\n", pkg.Name(), pkg.Version(), newPkg.Version()) continue primeloop } } - for _, ignoreGroup := range config.AlpmConf.IgnoreGroup { + for _, ignoreGroup := range AlpmConf.IgnoreGroup { for _, group := range pkg.Groups().Slice() { if group == ignoreGroup { fmt.Printf("\x1b[33mwarning:\x1b[0m %s (ignored group) ignoring upgrade (%s -> %s)\n", pkg.Name(), pkg.Version(), newPkg.Version()) @@ -336,7 +334,7 @@ func upgradePkgs(flags []string) error { repoNames = append(repoNames, k.Name) } - err := config.PassToPacman("-S", repoNames, flags) + err := PassToPacman("-S", repoNames, flags) if err != nil { fmt.Println("Error upgrading repo packages.") } @@ -353,7 +351,28 @@ func upgradePkgs(flags []string) error { } aurNames = append(aurNames, k.Name) } - aur.Install(aurNames, flags) + Install(aurNames, flags) } return nil } + +func develUpgrade(foreign map[string]alpm.Package, flags []string) error { + fmt.Println(" Checking development packages...") + develUpdates := vcs.CheckUpdates(foreign) + if len(develUpdates) != 0 { + for _, q := range develUpdates { + fmt.Printf("\x1b[1m\x1b[32m==>\x1b[33;1m %s\x1b[0m\n", q) + } + // Install updated packages + if !ContinueTask("Proceed with upgrade?", "nN") { + return nil + } + + err := Install(develUpdates, flags) + if err != nil { + fmt.Println(err) + } + } + + return nil +} diff --git a/aur/vcs/github.go b/vcs.go similarity index 70% rename from aur/vcs/github.go rename to vcs.go index e4d58751..323c0fb8 100644 --- a/aur/vcs/github.go +++ b/vcs.go @@ -1,4 +1,4 @@ -package github +package main import ( "encoding/json" @@ -8,6 +8,7 @@ import ( "strings" alpm "github.com/jguer/go-alpm" + "github.com/jguer/yay/pacman" ) // branch contains the information of a repository branch @@ -30,35 +31,28 @@ type Info struct { type infos []Info -var savedInfo infos -var configfile string - -// Updated returns if database has been updated -var Updated bool - -func init() { - Updated = false - configfile = os.Getenv("HOME") + "/.config/yay/yay_vcs.json" - - if _, err := os.Stat(configfile); os.IsNotExist(err) { - _ = os.MkdirAll(os.Getenv("HOME")+"/.config/yay", 0755) - return - } - - file, err := os.Open(configfile) +// CreateDevelDB forces yay to create a DB of the existing development packages +func createDevelDB() error { + foreign, err := pacman.ForeignPackages() if err != nil { - fmt.Println("error:", err) - return + return err } - decoder := json.NewDecoder(file) - err = decoder.Decode(&savedInfo) - if err != nil { - fmt.Println("error:", err) + + keys := make([]string, len(foreign)) + i := 0 + for k := range foreign { + keys[i] = k + i++ } + + config.NoConfirm = true + specialDBsauce = true + err = Install(keys, nil) + return err } // ParseSource returns owner and repo from source -func ParseSource(source string) (owner string, repo string) { +func parseSource(source string) (owner string, repo string) { if !(strings.Contains(source, "git://") || strings.Contains(source, ".git") || strings.Contains(source, "git+https://")) { @@ -97,16 +91,15 @@ func (info *Info) needsUpdate() bool { if e.Name == "master" { if e.Commit.SHA != info.SHA { return true - } else { - return false } + return false } } return false } // CheckUpdates returns list of outdated packages -func CheckUpdates(foreign map[string]alpm.Package) (toUpdate []string) { +func checkUpdates(foreign map[string]alpm.Package) (toUpdate []string) { for _, e := range savedInfo { if e.needsUpdate() { if _, ok := foreign[e.Package]; ok { @@ -128,23 +121,8 @@ func inStore(pkgName string) *Info { return nil } -// RemovePackage removes package from VCS information -func RemovePackage(pkgs []string) { - for _, pkgName := range pkgs { - for i, e := range savedInfo { - if e.Package == pkgName { - savedInfo[i] = savedInfo[len(savedInfo)-1] - savedInfo = savedInfo[:len(savedInfo)-1] - } - } - } - - _ = SaveBranchInfo() - return -} - // BranchInfo updates saved information -func BranchInfo(pkgName string, owner string, repo string) (err error) { +func branchInfo(pkgName string, owner string, repo string) (err error) { Updated = true var newRepo branches url := "https://api.github.com/repos/" + owner + "/" + repo + "/branches" @@ -173,8 +151,8 @@ func BranchInfo(pkgName string, owner string, repo string) (err error) { return } -func SaveBranchInfo() error { - marshalledinfo, err := json.Marshal(savedInfo) +func saveVCSInfo() error { + marshalledinfo, err := json.MarshalIndent(savedInfo) if err != nil || string(marshalledinfo) == "null" { return err } diff --git a/aur/vcs/github_test.go b/vcs_test.go similarity index 98% rename from aur/vcs/github_test.go rename to vcs_test.go index 6f6fefec..d72044df 100644 --- a/aur/vcs/github_test.go +++ b/vcs_test.go @@ -1,4 +1,4 @@ -package github +package main import ( "testing"