diff --git a/cmd.go b/cmd.go index f3043d20..2a54afed 100644 --- a/cmd.go +++ b/cmd.go @@ -448,16 +448,7 @@ func handleYay() (err error) { } func handleGetpkgbuild() (err error) { - for pkg := range cmdArgs.targets { - err = getPkgbuild(pkg) - if err != nil { - //we print the error instead of returning it - //seems as we can handle multiple errors without stoping - //theres no easy way around this right now - fmt.Println(pkg+":", err) - } - } - + err = getPkgbuilds(cmdArgs.formatTargets()) return } @@ -497,10 +488,10 @@ func handleSync() (err error) { err = syncSearch(targets) } else if cmdArgs.existsArg("c", "clean") { err = passToPacman(cmdArgs) - } else if cmdArgs.existsArg("u", "sysupgrade") { - err = upgradePkgs(make([]string, 0)) } else if cmdArgs.existsArg("i", "info") { err = syncInfo(targets) + } else if cmdArgs.existsArg("u", "sysupgrade") { + err = install(cmdArgs) } else if len(cmdArgs.targets) > 0 { err = install(cmdArgs) } @@ -602,9 +593,8 @@ func numberMenu(pkgS []string, flags []string) (err error) { aurQ.printSearch(numpq + 1) } - fmt.Println(greenFg("Type the numbers or ranges (e.g. 1-10) you want to install. " + - "Separate each one of them with a space.")) - fmt.Print("Numbers: ") + fmt.Println(boldGreenFg(arrow) + boldGreenFg(" Packages to not upgrade (eg: 1 2 3, 1-3 or ^4)")) + fmt.Print(boldGreenFg(arrow + " ")) reader := bufio.NewReader(os.Stdin) numberBuf, overflow, err := reader.ReadLine() if err != nil || overflow { diff --git a/dependencies.go b/dependencies.go index 75aa7992..67e32057 100644 --- a/dependencies.go +++ b/dependencies.go @@ -1,14 +1,13 @@ package main import ( - "strings" - alpm "github.com/jguer/go-alpm" rpc "github.com/mikkeloscar/aur" + "strings" ) type depTree struct { - ToProcess []string + ToProcess stringSet Repo map[string]*alpm.Package Aur map[string]*rpc.Pkg Missing stringSet @@ -23,7 +22,7 @@ type depCatagories struct { func makeDepTree() *depTree { dt := depTree{ - make([]string, 0), + make(stringSet), make(map[string]*alpm.Package), make(map[string]*rpc.Pkg), make(stringSet), @@ -119,7 +118,7 @@ func repoDepCatagoriesRecursive(pkg *alpm.Package, dc *depCatagories, dt *depTre } func depCatagoriesRecursive(pkg *rpc.Pkg, dc *depCatagories, dt *depTree, isMake bool, seen stringSet) { - for _, deps := range [2][]string{pkg.Depends, pkg.MakeDepends} { + for _, deps := range [3][]string{pkg.Depends, pkg.MakeDepends, pkg.CheckDepends} { for _, _dep := range deps { dep := getNameFromDep(_dep) @@ -188,12 +187,10 @@ func getDepTree(pkgs []string) (*depTree, error) { continue } - dt.ToProcess = append(dt.ToProcess, pkg) + dt.ToProcess.set(pkg) } - if len(dt.ToProcess) > 0 { - err = depTreeRecursive(dt, localDb, syncDb, false) - } + err = depTreeRecursive(dt, localDb, syncDb, false) return dt, err } @@ -239,16 +236,20 @@ func repoTreeRecursive(pkg *alpm.Package, dt *depTree, localDb *alpm.Db, syncDb } func depTreeRecursive(dt *depTree, localDb *alpm.Db, syncDb alpm.DbList, isMake bool) (err error) { - nextProcess := make([]string, 0) - currentProcess := make([]string, 0, len(dt.ToProcess)) + if len(dt.ToProcess) == 0 { + return + } + nextProcess := make(stringSet) + currentProcess := make(stringSet) //strip version conditions - for _, dep := range dt.ToProcess { - currentProcess = append(currentProcess, getNameFromDep(dep)) + for dep := range dt.ToProcess { + currentProcess.set(getNameFromDep(dep)) } //assume toprocess only contains aur stuff we have not seen - info, err := rpc.Info(currentProcess) + info, err := aurInfo(currentProcess.toSlice()) + if err != nil { return } @@ -265,17 +266,17 @@ func depTreeRecursive(dt *depTree, localDb *alpm.Db, syncDb alpm.DbList, isMake //loop through to process and check if we now have //each packaged cached //if its not cached we assume its missing - for k, pkgName := range currentProcess { + for pkgName := range currentProcess { pkg, exists := dt.Aur[pkgName] //did not get it in the request if !exists { - dt.Missing.set(dt.ToProcess[k]) + dt.Missing.set(pkgName) continue } - //for reach dep and makedep - for _, deps := range [2][]string{pkg.Depends, pkg.MakeDepends} { + //for each dep and makedep + for _, deps := range [3][]string{pkg.Depends, pkg.MakeDepends, pkg.CheckDepends} { for _, versionedDep := range deps { dep := getNameFromDep(versionedDep) @@ -311,7 +312,7 @@ func depTreeRecursive(dt *depTree, localDb *alpm.Db, syncDb alpm.DbList, isMake } //if all else fails add it to next search - nextProcess = append(nextProcess, versionedDep) + nextProcess.set(versionedDep) } } } diff --git a/download.go b/download.go index af2b479f..090f7330 100644 --- a/download.go +++ b/download.go @@ -7,8 +7,6 @@ import ( "os" "os/exec" "strings" - - rpc "github.com/mikkeloscar/aur" ) func downloadFile(path string, url string) (err error) { @@ -63,60 +61,71 @@ func downloadAndUnpack(url string, path string, trim bool) (err error) { return } -func getPkgbuild(pkg string) (err error) { +func getPkgbuilds(pkgs []string) error { + //possibleAurs := make([]string, 0, 0) wd, err := os.Getwd() if err != nil { - return + return err } wd = wd + "/" - err = getPkgbuildfromABS(pkg, wd) - if err == nil { - return + missing, err := getPkgbuildsfromABS(pkgs, wd) + if err != nil { + return err } - err = getPkgbuildfromAUR(pkg, wd) - return + err = getPkgbuildsfromAUR(missing, wd) + return err } // GetPkgbuild downloads pkgbuild from the ABS. -func getPkgbuildfromABS(pkgN string, path string) (err error) { +func getPkgbuildsfromABS(pkgs []string, path string) (missing []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.Base() + ".tar.gz" - } else if db.Name() == "community" { - url = "https://projects.archlinux.org/svntogit/community.git/snapshot/community-packages/" + pkg.Base() + ".tar.gz" - } else { - return fmt.Errorf("Not in standard repositories") +nextPkg: + for _, pkgN := range pkgs { + 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.Base() + ".tar.gz" + } else if db.Name() == "community" { + url = "https://projects.archlinux.org/svntogit/community.git/snapshot/community-packages/" + pkg.Base() + ".tar.gz" + } else { + fmt.Println(pkgN + " not in standard repositories") + } + + errD := downloadAndUnpack(url, path, true) + if errD != nil { + fmt.Println(boldYellowFg(pkg.Name()), boldGreenFg(errD.Error())) + } + + fmt.Println(boldGreenFg(arrow), boldGreenFg("Downloaded"), boldYellowFg(pkg.Name()), boldGreenFg("from ABS")) + continue nextPkg } - fmt.Println(boldGreenFg(arrow), boldYellowFg(pkgN), boldGreenFg("found in ABS.")) - errD := downloadAndUnpack(url, path, true) - return errD } + + missing = append(missing, pkgN) } - return fmt.Errorf("package not found") + + return } // GetPkgbuild downloads pkgbuild from the AUR. -func getPkgbuildfromAUR(pkgN string, dir string) (err error) { - aq, err := rpc.Info([]string{pkgN}) +func getPkgbuildsfromAUR(pkgs []string, dir string) (err error) { + aq, err := aurInfo(pkgs) if err != nil { return err } - if len(aq) == 0 { - return fmt.Errorf("no results") + for _, pkg := range aq { + downloadAndUnpack(baseURL+aq[0].URLPath, dir, false) + fmt.Println(boldGreenFg(arrow), boldGreenFg("Downloaded"), boldYellowFg(pkg.Name), boldGreenFg("from AUR")) } - fmt.Println(boldGreenFg(arrow), boldYellowFg(pkgN), boldGreenFg("found in AUR.")) - downloadAndUnpack(baseURL+aq[0].URLPath, dir, false) return } diff --git a/install.go b/install.go index 25178b41..45f78ba9 100644 --- a/install.go +++ b/install.go @@ -5,8 +5,8 @@ import ( "io/ioutil" "os" "os/exec" - "strings" "strconv" + "strings" alpm "github.com/jguer/go-alpm" rpc "github.com/mikkeloscar/aur" @@ -15,87 +15,136 @@ import ( // Install handles package installs func install(parser *arguments) error { - aurs, repos, missing, err := packageSlices(parser.targets.toSlice()) - srcinfos := make(map[string]*gopkg.PKGBUILD) + removeMake := false + aur, repo, err := packageSlices(parser.targets.toSlice()) if err != nil { return err } - if len(missing) > 0 { - fmt.Println(missing) - fmt.Println("Could not find all Targets") + srcinfos := make(map[string]*gopkg.PKGBUILD) + var dc *depCatagories + + //fmt.Println(greenFg(arrow), greenFg("Resolving Dependencies")) + requestTargets := append(aur, repo...) + + //remotenames: names of all non repo packages on the system + _, _, _, remoteNames, err := filterPackages() + if err != nil { + return err } + //cache as a stringset. maybe make it return a string set in the first + //place + remoteNamesCache := make(stringSet) + for _, name := range remoteNames { + remoteNamesCache.set(name) + } + + //if we are doing -u also request every non repo package on the system + if parser.existsArg("u", "sysupgrade") { + requestTargets = append(requestTargets, remoteNames...) + } + + if len(aur) > 0 || parser.existsArg("u", "sysupgrade") && len(remoteNames) > 0 { + fmt.Println(boldCyanFg("::"), boldFg("Querying AUR...")) + } + dt, err := getDepTree(requestTargets) + if err != nil { + return err + } + + //only error if direct targets or deps are missing + for missingName := range dt.Missing { + if !remoteNamesCache.get(missingName) { + return fmt.Errorf(boldRedFgBlackBg(arrow+" Error: ") + + blackBg("Could not find all required package")) + } + } + + //create the arguments to pass for the repo install 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 parser.existsArg("u", "sysupgrade") { + repoUp, aurUp, err := upgradePkgs(dt) if err != nil { - fmt.Println("Error installing repo packages.") + return err + } + + fmt.Println() + + for pkg := range aurUp { + parser.addTarget(pkg) + } + + for pkg := range repoUp { + arguments.addTarget(pkg) + } + + //discard stuff thats + //not a target and + //not an upgrade and + //is installed + for pkg := range dt.Aur { + if !parser.targets.get(pkg) && remoteNamesCache.get(pkg) { + delete(dt.Aur, pkg) + } } } - if len(aurs) != 0 { - //todo mamakeke pretty - fmt.Println(greenFg(arrow), greenFg("Resolving Dependencies")) + hasAur := len(dt.Aur) != 0 + dc, err = getDepCatagories(parser.formatTargets(), dt) + if err != nil { + return err + } - dt, err := getDepTree(aurs) - if err != nil { - return err - } + for _, pkg := range dc.Repo { + arguments.addTarget(pkg.Name()) + } - if len(dt.Missing) > 0 { - fmt.Println(dt.Missing) - return fmt.Errorf("Could not find all Deps") - } + for _, pkg := range repo { + arguments.addTarget(pkg) + } - 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) + if len(dc.Aur) == 0 && len(arguments.targets) == 0 { + fmt.Println("There is nothing to do") + return nil + } + if hasAur { printDepCatagories(dc) fmt.Println() + } - if !arguments.existsArg("gendb") { + if !parser.existsArg("gendb") && len(arguments.targets) > 0 { + err := passToPacman(arguments) + if err != nil { + return fmt.Errorf("Error installing repo packages.") + } + } + + if hasAur { + if !parser.existsArg("gendb") { err = checkForConflicts(dc) if err != nil { return err } } - askCleanBuilds(dc.Aur, dc.Bases) - fmt.Println() - - if !continueTask("Proceed with install?", "nN") { - return fmt.Errorf("Aborting due to user") + if len(dc.MakeOnly) > 0 { + if !continueTask("Remove make dependencies after install?", "yY") { + removeMake = true + } } - // if !continueTask("Proceed with download?", "nN") { - // return fmt.Errorf("Aborting due to user") - // } + askCleanBuilds(dc.Aur, dc.Bases) + + if !continueTask("Proceed with Download?", "nN") { + return fmt.Errorf("Aborting due to user") + } err = dowloadPkgBuilds(dc.Aur, dc.Bases) if err != nil { @@ -107,41 +156,35 @@ func install(parser *arguments) error { return err } - 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()) - } + if !continueTask("Proceed with install?", "nN") { + return fmt.Errorf("Aborting due to user") + } - oldConfirm := config.NoConfirm - config.NoConfirm = true - passToPacman(arguments) - config.NoConfirm = oldConfirm + //conflicts have been checked so answer y for them + ask, _ := strconv.Atoi(cmdArgs.globals["ask"]) + uask := alpm.Question(ask) | alpm.QuestionConflictPkg + cmdArgs.globals["ask"] = fmt.Sprint(uask) + + //this downloads the package build sources but also causes + //a version bumb for vsc packages + //that should not edit the sources so we should be safe to skip + //it and parse the srcinfo at the current version + if arguments.existsArg("gendb") { + err = parsesrcinfosFile(dc.Aur, srcinfos, dc.Bases) if err != nil { return err } - } - if arguments.existsArg("gendb") { - fmt.Println("GenDB finished. No packages were installed") + fmt.Println(boldGreenFg(arrow + " 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) + err = parsesrcinfosGenerate(dc.Aur, srcinfos, dc.Bases) if err != nil { return err } @@ -152,7 +195,7 @@ func install(parser *arguments) error { } if len(dc.MakeOnly) > 0 { - if continueTask("Remove make dependencies?", "yY") { + if !removeMake { return nil } @@ -236,21 +279,13 @@ func checkForConflicts(dc *depCatagories) error { fmt.Println( redFg("Package conflicts found:")) for name, pkgs := range toRemove { - str := yellowFg("\t" + name) + " Replaces" + str := "\tInstalling " + yellowFg(name) + " will remove" for pkg := range pkgs { str += " " + yellowFg(pkg) } fmt.Println(str) } - - if !continueTask("Continue with install?", "nN") { - return fmt.Errorf("Aborting due to user") - } - - ask, _ := strconv.Atoi(cmdArgs.globals["ask"]) - uask := alpm.Question(ask) | alpm.QuestionConflictPkg - cmdArgs.globals["ask"] = fmt.Sprint(uask) } return nil @@ -279,10 +314,44 @@ func askEditPkgBuilds(pkgs []*rpc.Pkg, bases map[string][]*rpc.Pkg) error { return nil } -func parsesrcinfos(pkgs []*rpc.Pkg, srcinfos map[string]*gopkg.PKGBUILD) error { - for _, pkg := range pkgs { +func updateVSCdb(pkgbuild *gopkg.PKGBUILD) { + for _, pkgsource := range pkgbuild.Source { + owner, repo := parseSource(pkgsource) + if owner != "" && repo != "" { + err := branchInfo(pkgbuild.Pkgbase, owner, repo) + if err != nil { + fmt.Println(err) + } + } + } +} + +func parsesrcinfosFile(pkgs []*rpc.Pkg, srcinfos map[string]*gopkg.PKGBUILD, bases map[string][]*rpc.Pkg) error { + for k, pkg := range pkgs { dir := config.BuildDir + pkg.PackageBase + "/" + str := boldCyanFg("::") + boldFg(" Parsing SRCINFO (%d/%d): %s\n") + fmt.Printf(str, k+1, len(pkgs), formatPkgbase(pkg, bases)) + + pkgbuild, err := gopkg.ParseSRCINFO(dir + ".SRCINFO") + if err != nil { + return fmt.Errorf("%s: %s", pkg.Name, err) + } + + srcinfos[pkg.PackageBase] = pkgbuild + updateVSCdb(pkgbuild) + } + + return nil +} + +func parsesrcinfosGenerate(pkgs []*rpc.Pkg, srcinfos map[string]*gopkg.PKGBUILD, bases map[string][]*rpc.Pkg) error { + for k, pkg := range pkgs { + dir := config.BuildDir + pkg.PackageBase + "/" + + str := boldCyanFg("::") + boldFg(" Parsing SRCINFO (%d/%d): %s\n") + fmt.Printf(str, k+1, len(pkgs), formatPkgbase(pkg, bases)) + cmd := exec.Command(config.MakepkgBin, "--printsrcinfo") cmd.Stderr = os.Stderr cmd.Dir = dir @@ -298,33 +367,18 @@ func parsesrcinfos(pkgs []*rpc.Pkg, srcinfos map[string]*gopkg.PKGBUILD) error { } 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 - } - } - } + updateVSCdb(pkgbuild) } return nil } func dowloadPkgBuilds(pkgs []*rpc.Pkg, bases map[string][]*rpc.Pkg) (err error) { - for _, pkg := range pkgs { + for k, 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) + str := boldCyanFg("::") + boldFg(" Downloading (%d/%d): %s\n") + + fmt.Printf(str, k+1, len(pkgs), formatPkgbase(pkg, bases)) err = downloadAndUnpack(baseURL+pkg.URLPath, config.BuildDir, false) if err != nil { @@ -340,7 +394,7 @@ func downloadPkgBuildsSources(pkgs []*rpc.Pkg) (err error) { dir := config.BuildDir + pkg.PackageBase + "/" err = passToMakepkg(dir, "--nobuild", "--nocheck", "--noprepare", "--nodeps") if err != nil { - return + return fmt.Errorf("Error downloading sources: %s", pkg) } } @@ -373,9 +427,9 @@ func buildInstallPkgBuilds(pkgs []*rpc.Pkg, srcinfos map[string]*gopkg.PKGBUILD, fmt.Println(boldRedFgBlackBg(arrow+" Warning:"), blackBg(pkg.Name+"-"+pkg.Version+" Already made -- skipping build")) } else { - err := passToMakepkg(dir, "-Cscf", "--noconfirm") + err := passToMakepkg(dir, "-Ccf", "--noconfirm") if err != nil { - return err + return fmt.Errorf("Error making: %s", pkg.Name) } } diff --git a/print.go b/print.go index 381071a4..4c8f11c2 100644 --- a/print.go +++ b/print.go @@ -94,6 +94,21 @@ func (s repoQuery) printSearch() { } } +func formatPkgbase(pkg *rpc.Pkg, bases map[string][]*rpc.Pkg) string { + str := pkg.PackageBase + if len(bases[pkg.PackageBase]) > 1 || pkg.PackageBase != pkg.Name { + str2 := " (" + for _, split := range bases[pkg.PackageBase] { + str2 += split.Name + " " + } + str2 = str2[:len(str2)-1] + ")" + + str += str2 + } + + return str +} + // printDownloadsFromRepo prints repository packages to be downloaded func printDepCatagories(dc *depCatagories) { repo := "" @@ -201,6 +216,7 @@ func PrintInfo(a *rpc.Pkg) { fmt.Println(boldWhiteFg("Licenses :"), strings.Join(a.License, " ")) fmt.Println(boldWhiteFg("Depends On :"), strings.Join(a.Depends, " ")) fmt.Println(boldWhiteFg("Make Deps :"), strings.Join(a.MakeDepends, " ")) + fmt.Println(boldWhiteFg("Check Deps :"), strings.Join(a.CheckDepends, " ")) fmt.Println(boldWhiteFg("Optional Deps :"), strings.Join(a.OptDepends, " ")) fmt.Println(boldWhiteFg("Conflicts With :"), strings.Join(a.Conflicts, " ")) fmt.Println(boldWhiteFg("Maintainer :"), a.Maintainer) @@ -256,53 +272,7 @@ func localStatistics() error { biggestPackages() fmt.Println(boldCyanFg("===========================================")) - var q aurQuery - var j int - for i := len(remoteNames); i != 0; i = j { - j = i - config.RequestSplitN - if j < 0 { - j = 0 - } - qtemp, err := rpc.Info(remoteNames[j:i]) - q = append(q, qtemp...) - if err != nil { - return err - } - } - - var outcast []string - for _, s := range remoteNames { - found := false - for _, i := range q { - if s == i.Name { - found = true - break - } - } - if !found { - outcast = append(outcast, s) - } - } - - if err != nil { - return err - } - - for _, res := range q { - if res.Maintainer == "" { - fmt.Println(boldRedFgBlackBg(arrow+"Warning:"), - boldYellowFgBlackBg(res.Name), whiteFgBlackBg("is orphaned")) - } - if res.OutOfDate != 0 { - fmt.Println(boldRedFgBlackBg(arrow+"Warning:"), - boldYellowFgBlackBg(res.Name), whiteFgBlackBg("is out-of-date in AUR")) - } - } - - for _, res := range outcast { - fmt.Println(boldRedFgBlackBg(arrow+"Warning:"), - boldYellowFgBlackBg(res), whiteFgBlackBg("is not available in AUR")) - } + aurInfo(remoteNames) return nil } @@ -318,14 +288,18 @@ func printMissing(missing stringSet) { //todo make it less hacky func printNumberOfUpdates() error { + //todo old := os.Stdout // keep backup of the real stdout os.Stdout = nil - aurUp, repoUp, err := upList() + _, _, localNames, remoteNames, err := filterPackages() + dt, _ := getDepTree(append(localNames, remoteNames...)) + aurUp, repoUp, err := upList(dt) os.Stdout = old // restoring the real stdout if err != nil { return err } fmt.Println(len(aurUp) + len(repoUp)) + return nil } @@ -333,7 +307,10 @@ func printNumberOfUpdates() error { func printUpdateList() error { old := os.Stdout // keep backup of the real stdout os.Stdout = nil - aurUp, repoUp, err := upList() + _, _, localNames, remoteNames, err := filterPackages() + dt, _ := getDepTree(append(localNames, remoteNames...)) + aurUp, repoUp, err := upList(dt) + os.Stdout = old // restoring the real stdout if err != nil { return err diff --git a/query.go b/query.go index ed0a30b6..0cc0f892 100644 --- a/query.go +++ b/query.go @@ -4,6 +4,7 @@ import ( "fmt" "sort" "strings" + "sync" alpm "github.com/jguer/go-alpm" rpc "github.com/mikkeloscar/aur" @@ -153,16 +154,23 @@ func syncSearch(pkgS []string) (err error) { // SyncInfo serves as a pacman -Si for repo packages and AUR packages. func syncInfo(pkgS []string) (err error) { - aurS, repoS, missing, err := packageSlices(pkgS) + var info []rpc.Pkg + aurS, repoS, err := packageSlices(pkgS) if err != nil { return } + if len(aurS) != 0 { + info, err = aurInfo(aurS) + if err != nil { + fmt.Println(err) + } + } + //repo always goes first if len(repoS) != 0 { arguments := cmdArgs.copy() arguments.delTarget(aurS...) - arguments.delTarget(missing...) err = passToPacman(arguments) if err != nil { @@ -171,20 +179,11 @@ func syncInfo(pkgS []string) (err error) { } if len(aurS) != 0 { - q, err := rpc.Info(aurS) - if err != nil { - fmt.Println(err) - } - for _, aurP := range q { - PrintInfo(&aurP) + for _, pkg := range info { + PrintInfo(&pkg) } } - //todo - //if len(missing) != 0 { - // printMissing(missing) - //} - return } @@ -239,8 +238,7 @@ func queryRepo(pkgInputN []string) (s repoQuery, n int, err error) { } // PackageSlices separates an input slice into aur and repo slices -func packageSlices(toCheck []string) (aur []string, repo []string, missing []string, err error) { - possibleAur := make([]string, 0) +func packageSlices(toCheck []string) (aur []string, repo []string, err error) { dbList, err := alpmHandle.SyncDbs() if err != nil { return @@ -263,30 +261,10 @@ func packageSlices(toCheck []string) (aur []string, repo []string, missing []str if found { repo = append(repo, pkg) } else { - possibleAur = append(possibleAur, pkg) + aur = append(aur, pkg) } } - if len(possibleAur) == 0 { - return - } - - info, err := rpc.Info(possibleAur) - if err != nil { - fmt.Println(err) - } - -outer: - for _, pkg := range possibleAur { - for _, rpcpkg := range info { - if rpcpkg.Name == pkg { - aur = append(aur, pkg) - continue outer - } - } - missing = append(missing, pkg) - } - return } @@ -380,3 +358,97 @@ big: } return } + +func min(a, b int) int { + if a < b { + return a + } + return a +} + +func aurInfo(names []string) ([]rpc.Pkg, error) { + info := make([]rpc.Pkg, 0, len(names)) + seen := make(map[string]int) + var mux sync.Mutex + var wg sync.WaitGroup + var err error + + missing := make([]string, 0, len(names)) + orphans := make([]string, 0, len(names)) + outOfDate := make([]string, 0, len(names)) + + makeRequest := func(n, max int) { + tempInfo, requestErr := rpc.Info(names[n:max]) + if err != nil { + return + } + if requestErr != nil { + //return info, err + err = requestErr + return + } + mux.Lock() + info = append(info, tempInfo...) + mux.Unlock() + wg.Done() + } + + for n := 0; n < len(names); n += config.RequestSplitN { + max := min(len(names), n+config.RequestSplitN) + wg.Add(1) + go makeRequest(n, max) + } + + wg.Wait() + + if err != nil { + return info, err + } + + for k, pkg := range info { + seen[pkg.Name] = k + } + + for _, name := range names { + i, ok := seen[name] + if !ok { + missing = append(missing, name) + continue + } + + pkg := info[i] + + if pkg.Maintainer == "" { + orphans = append(orphans, name) + } + if pkg.OutOfDate != 0 { + outOfDate = append(outOfDate, name) + } + } + + if len(missing) > 0 { + fmt.Print(boldRedFgBlackBg(arrow + " Missing AUR Packages:")) + for _, name := range missing { + fmt.Print(" " + boldYellowFgBlackBg(name)) + } + fmt.Println() + } + + if len(orphans) > 0 { + fmt.Print(boldRedFgBlackBg(arrow + " Orphaned AUR Packages:")) + for _, name := range orphans { + fmt.Print(" " + boldYellowFgBlackBg(name)) + } + fmt.Println() + } + + if len(outOfDate) > 0 { + fmt.Print(boldRedFgBlackBg(arrow + " Out Of Date AUR Packages:")) + for _, name := range outOfDate { + fmt.Print(" " + boldYellowFgBlackBg(name)) + } + fmt.Println() + } + + return info, nil +} diff --git a/upgrade.go b/upgrade.go index fd2712d5..eeafd8d7 100644 --- a/upgrade.go +++ b/upgrade.go @@ -10,7 +10,6 @@ import ( "unicode" alpm "github.com/jguer/go-alpm" - rpc "github.com/mikkeloscar/aur" pkgb "github.com/mikkeloscar/gopkgbuild" ) @@ -57,12 +56,34 @@ func (u upSlice) Less(i, j int) bool { return false } +func getVersionDiff(oldVersion, newversion string) (left, right string) { + old, errOld := pkgb.NewCompleteVersion(oldVersion) + new, errNew := pkgb.NewCompleteVersion(newversion) + + if errOld != nil { + left = redFg("Invalid Version") + } + if errNew != nil { + right = redFg("Invalid Version") + } + + if errOld == nil && errNew == nil { + if old.Version == new.Version { + left = string(old.Version) + "-" + redFg(string(old.Pkgrel)) + right = string(new.Version) + "-" + greenFg(string(new.Pkgrel)) + } else { + left = redFg(string(old.Version)) + "-" + string(old.Pkgrel) + right = boldGreenFg(string(new.Version)) + "-" + string(new.Pkgrel) + } + } + + return +} + // Print prints the details of the packages to upgrade. func (u upSlice) Print(start int) { for k, i := range u { - old, errOld := pkgb.NewCompleteVersion(i.LocalVersion) - new, errNew := pkgb.NewCompleteVersion(i.RemoteVersion) - var left, right string + left, right := getVersionDiff(i.LocalVersion, i.RemoteVersion) f := func(name string) (output string) { if alpmConf.Options&alpm.ConfColor == 0 { @@ -77,26 +98,6 @@ func (u upSlice) Print(start int) { fmt.Print(yellowFg(fmt.Sprintf("%2d ", len(u)+start-k-1))) fmt.Print(f(i.Repository), "/", boldWhiteFg(i.Name)) - if errOld != nil { - left = redFg("Invalid Version") - } else { - if old.Version == new.Version { - left = string(old.Version) + "-" + redFg(string(old.Pkgrel)) - } else { - left = redFg(string(old.Version)) + "-" + string(old.Pkgrel) - } - } - - if errNew != nil { - right = redFg("Invalid Version") - } else { - if old.Version == new.Version { - right = string(new.Version) + "-" + greenFg(string(new.Pkgrel)) - } else { - right = boldGreenFg(string(new.Version)) + "-" + string(new.Pkgrel) - } - } - w := 70 - len(i.Repository) - len(i.Name) + len(left) fmt.Printf(fmt.Sprintf("%%%ds", w), fmt.Sprintf("%s -> %s\n", left, right)) @@ -104,7 +105,7 @@ func (u upSlice) Print(start int) { } // upList returns lists of packages to upgrade from each source. -func upList() (aurUp upSlice, repoUp upSlice, err error) { +func upList(dt *depTree) (aurUp upSlice, repoUp upSlice, err error) { local, remote, _, remoteNames, err := filterPackages() if err != nil { return @@ -123,7 +124,7 @@ func upList() (aurUp upSlice, repoUp upSlice, err error) { fmt.Println(boldCyanFg("::"), boldFg("Searching AUR for updates...")) go func() { - aurUpList, err := upAUR(remote, remoteNames) + aurUpList, err := upAUR(remote, remoteNames, dt) errC <- err aurC <- aurUpList }() @@ -168,7 +169,7 @@ func upDevel(remote []alpm.Package, packageC chan upgrade, done chan bool) { fmt.Print(yellowFg("Warning: ")) fmt.Printf("%s ignoring package upgrade (%s => %s)\n", pkg.Name(), pkg.Version(), "git") } else { - packageC <- upgrade{e.Package, "devel", e.SHA[0:6], "git"} + packageC <- upgrade{e.Package, "devel", pkg.Version(), "commit-" + e.SHA[0:6]} } } else { removeVCSPackage([]string{e.Package}) @@ -180,8 +181,7 @@ func upDevel(remote []alpm.Package, packageC chan upgrade, done chan bool) { // upAUR gathers foreign packages and checks if they have new versions. // Output: Upgrade type package list. -func upAUR(remote []alpm.Package, remoteNames []string) (toUpgrade upSlice, err error) { - var j int +func upAUR(remote []alpm.Package, remoteNames []string, dt *depTree) (toUpgrade upSlice, err error) { var routines int var routineDone int @@ -194,48 +194,32 @@ func upAUR(remote []alpm.Package, remoteNames []string) (toUpgrade upSlice, err fmt.Println(boldCyanFg("::"), boldFg("Checking development packages...")) } - for i := len(remote); i != 0; i = j { - //Split requests so AUR RPC doesn't get mad at us. - j = i - config.RequestSplitN - if j < 0 { - j = 0 - } - - routines++ - go func(local []alpm.Package, remote []string) { - qtemp, err := rpc.Info(remote) - if err != nil { - fmt.Println(err) - done <- true - return + routines++ + go func(remote []alpm.Package, remoteNames []string, dt *depTree) { + for _, pkg := range remote { + aurPkg, ok := dt.Aur[pkg.Name()] + if !ok { + continue } - // For each item in query: Search equivalent in foreign. - // We assume they're ordered and are returned ordered - // and will only be missing if they don't exist in AUR. - max := len(qtemp) - 1 - var missing, x int - for i := range local { - x = i - missing - if x > max { - break - } else if qtemp[x].Name == local[i].Name() { - if (config.TimeUpdate && (int64(qtemp[x].LastModified) > local[i].BuildDate().Unix())) || - (alpm.VerCmp(local[i].Version(), qtemp[x].Version) < 0) { - if local[i].ShouldIgnore() { - fmt.Print(yellowFg("Warning: ")) - fmt.Printf("%s ignoring package upgrade (%s => %s)\n", local[i].Name(), local[i].Version(), qtemp[x].Version) - } else { - packageC <- upgrade{qtemp[x].Name, "aur", local[i].Version(), qtemp[x].Version} - } - } - continue + if (config.TimeUpdate && (int64(aurPkg.LastModified) > pkg.BuildDate().Unix())) || + (alpm.VerCmp(pkg.Version(), aurPkg.Version) < 0) { + if pkg.ShouldIgnore() { + left, right := getVersionDiff(pkg.Version(), aurPkg.Version) + fmt.Print(yellowFg("Warning: ")) + fmt.Printf("%s ignoring package upgrade (%s => %s)\n", pkg.Name(), left, right) } else { - missing++ + packageC <- upgrade{aurPkg.Name, "aur", pkg.Version(), aurPkg.Version} } } - done <- true - }(remote[j:i], remoteNames[j:i]) + } + + done <- true + }(remote, remoteNames, dt) + + if routineDone == routines { + err = nil + return } for { @@ -305,31 +289,33 @@ func removeIntListFromList(src, target []int) []int { } // upgradePkgs handles updating the cache and installing updates. -func upgradePkgs(flags []string) error { - aurUp, repoUp, err := upList() - if err != nil { - return err - } else if len(aurUp)+len(repoUp) == 0 { - fmt.Println("\nThere is nothing to do") - return err - } - +func upgradePkgs(dt *depTree) (stringSet, stringSet, error) { var repoNums []int var aurNums []int + repoNames := make(stringSet) + aurNames := make(stringSet) + + aurUp, repoUp, err := upList(dt) + if err != nil { + return repoNames, aurNames, err + } else if len(aurUp)+len(repoUp) == 0 { + return repoNames, aurNames, err + } + sort.Sort(repoUp) fmt.Println(boldBlueFg("::"), len(aurUp)+len(repoUp), boldWhiteFg("Packages to upgrade.")) repoUp.Print(len(aurUp) + 1) aurUp.Print(1) if !config.NoConfirm { - fmt.Println(greenFg("Enter packages you don't want to upgrade.")) - fmt.Print("Numbers: ") + fmt.Println(boldGreenFg(arrow) + greenFg(" Packages to not upgrade (eg: 1 2 3, 1-3 or ^4)")) + fmt.Print(boldGreenFg(arrow + " ")) reader := bufio.NewReader(os.Stdin) numberBuf, overflow, err := reader.ReadLine() if err != nil || overflow { fmt.Println(err) - return err + return repoNames, aurNames, err } result := strings.Fields(string(numberBuf)) @@ -383,13 +369,6 @@ func upgradePkgs(flags []string) error { repoNums = removeIntListFromList(excludeRepo, repoNums) } - arguments := cmdArgs.copy() - arguments.delArg("u", "sysupgrade") - arguments.delArg("y", "refresh") - - var repoNames []string - var aurNames []string - if len(repoUp) != 0 { repoloop: for i, k := range repoUp { @@ -398,7 +377,7 @@ func upgradePkgs(flags []string) error { continue repoloop } } - repoNames = append(repoNames, k.Name) + repoNames.set(k.Name) } } @@ -410,12 +389,9 @@ func upgradePkgs(flags []string) error { continue aurloop } } - aurNames = append(aurNames, k.Name) + aurNames.set(k.Name) } } - arguments.addTarget(repoNames...) - arguments.addTarget(aurNames...) - err = install(arguments) - return err + return repoNames, aurNames, err }