From f0f20269a06fead75a0cf0ace0e556704053bff8 Mon Sep 17 00:00:00 2001 From: morganamilo Date: Thu, 8 Mar 2018 23:54:18 +0000 Subject: [PATCH 1/6] Show versions when printing Packages to install --- print.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/print.go b/print.go index 50db85ec..307f5ad1 100644 --- a/print.go +++ b/print.go @@ -132,16 +132,16 @@ func printDepCatagories(dc *depCatagories) { for _, pkg := range dc.Repo { if dc.MakeOnly.get(pkg.Name()) { - repoMake += " " + pkg.Name() + repoMake += " " + pkg.Name() + "-" + pkg.Version() repoMakeLen++ } else { - repo += " " + pkg.Name() + repo += " " + pkg.Name() + "-" + pkg.Version() repoLen++ } } for _, pkg := range dc.Aur { - pkgStr := " " + pkg.PackageBase + pkgStr := " " + pkg.PackageBase + "-" + pkg.Version pkgStrMake := pkgStr push := false From 69885375524c2f6550def22fdd3edd25f3657bc6 Mon Sep 17 00:00:00 2001 From: morganamilo Date: Fri, 9 Mar 2018 02:03:04 +0000 Subject: [PATCH 2/6] Add parseNumberMenu() This function is designed to replace the existing number menu in upcoming commits. --- parser.go | 105 +++++++++++++++++++++++++++++++++++++++++++++++++ parser_test.go | 99 ++++++++++++++++++++++++++++++++++++++++++++++ query.go | 7 ++++ vcs_test.go | 2 +- 4 files changed, 212 insertions(+), 1 deletion(-) create mode 100644 parser_test.go diff --git a/parser.go b/parser.go index 6c421b49..d824d545 100644 --- a/parser.go +++ b/parser.go @@ -4,6 +4,7 @@ import ( "fmt" "io" "os" + "strconv" "strings" ) @@ -38,6 +39,20 @@ func (set stringSet) toSlice() []string { return slice } +func SliceToStringSet(in []string) stringSet { + set := make(stringSet) + + for _, v := range in { + set.set(v) + } + + return set +} + +func makeStringSet(in ...string) stringSet { + return SliceToStringSet(in) +} + // Parses command line arguments in a way we can interact with programmatically but // also in a way that can easily be passed to pacman later on. type arguments struct { @@ -554,3 +569,93 @@ func (parser *arguments) parseCommandLine() (err error) { return } + +type intRange struct { + min int + max int +} + +func makeIntRange(min, max int) intRange { + return intRange{ + min, + max, + } +} + +func (r intRange) get(n int) bool { + return n >= r.min && n <= r.max +} + +type intRanges []intRange + +func (rs intRanges) get(n int) bool { + for _, r := range rs { + if r.get(n) { + return true + } + } + + return false +} + +//parses input for number menus +//supports individual selection: 1 2 3 4 +//supports range selections: 1-4 10-20 +//supports negation: ^1 ^1-4 +// +//include and excule holds numbers that should be added and should not be added +//respectively. other holds anythign that can't be parsed as an int. This is +//intended to allow words inside of number menus. e.g. 'all' 'none' 'abort' +//of course the implementation is up to the caller, this function mearley parses +//the input and organizes it +func parseNumberMenu(input string) (intRanges, intRanges, stringSet, stringSet) { + include := make(intRanges, 0, 0) + exclude := make(intRanges, 0, 0) + otherInclude := make(stringSet) + otherExclude := make(stringSet) + + words := strings.Fields(input) + + for _, word := range words { + var num1 int + var num2 int + var err error + invert := false + other := otherInclude + + if word[0] == '^' { + invert = true + other = otherExclude + word = word[1:] + } + + ranges := strings.SplitN(word, "-", 2) + + num1, err = strconv.Atoi(ranges[0]) + if err != nil { + other.set(strings.ToLower(word)) + continue + } + + if len(ranges) == 2 { + num2, err = strconv.Atoi(ranges[1]) + if err != nil { + other.set(strings.ToLower(word)) + continue + } + } else { + num2 = num1 + } + + mi := min(num1, num2) + ma := max(num1, num2) + + if !invert { + include = append(include, makeIntRange(mi, ma)) + } else { + exclude = append(exclude, makeIntRange(mi, ma)) + } + } + + return include, exclude, otherInclude, otherExclude +} diff --git a/parser_test.go b/parser_test.go new file mode 100644 index 00000000..47c05177 --- /dev/null +++ b/parser_test.go @@ -0,0 +1,99 @@ +package main + +import "testing" + +func intRangesEqual(a, b intRanges) bool { + if a == nil && b == nil { + return true + } + + if a == nil || b == nil { + return false + } + + if len(a) != len(b) { + return false + } + + for n := range a { + r1 := a[n] + r2 := b[n] + + if r1.min != r1.min || r1.max != r2.max { + return false + } + } + + return true +} + +func stringSetEqual(a, b stringSet) bool { + if a == nil && b == nil { + return true + } + + if a == nil || b == nil { + return false + } + + if len(a) != len(b) { + return false + } + + for n := range a { + if !b.get(n) { + return false + } + } + + return true +} + +func TestParseNumberMenu(t *testing.T) { + type result struct { + Include intRanges + Exclude intRanges + OtherInclude stringSet + OtherExclude stringSet + } + + inputs := []string{ + "1 2 3 4 5", + "1-10 5-15", + "10-5 90-85", + "1 ^2 ^10-5 99 ^40-38 ^123 60-62", + "abort all none", + "a-b ^a-b ^abort", + "1\t2 3 4\t\t \t 5", + "", + " \t ", + "A B C D E", + } + + expected := []result{ + {intRanges{makeIntRange(1, 1), makeIntRange(2, 2), makeIntRange(3, 3), makeIntRange(4, 4), makeIntRange(5, 5)}, intRanges{}, make(stringSet), make(stringSet)}, + {intRanges{makeIntRange(1, 10), makeIntRange(5, 15)}, intRanges{}, make(stringSet), make(stringSet)}, + {intRanges{makeIntRange(5, 10), makeIntRange(85, 90)}, intRanges{}, make(stringSet), make(stringSet)}, + {intRanges{makeIntRange(1, 1), makeIntRange(99, 99), makeIntRange(60, 62)}, intRanges{makeIntRange(2, 2), makeIntRange(5, 10), makeIntRange(38, 40), makeIntRange(123, 123)}, make(stringSet), make(stringSet)}, + {intRanges{}, intRanges{}, makeStringSet("abort", "all", "none"), make(stringSet)}, + {intRanges{}, intRanges{}, makeStringSet("a-b"), makeStringSet("abort", "a-b")}, + {intRanges{makeIntRange(1, 1), makeIntRange(2, 2), makeIntRange(3, 3), makeIntRange(4, 4), makeIntRange(5, 5)}, intRanges{}, make(stringSet), make(stringSet)}, + {intRanges{}, intRanges{}, make(stringSet), make(stringSet)}, + {intRanges{}, intRanges{}, make(stringSet), make(stringSet)}, + {intRanges{}, intRanges{}, makeStringSet("a", "b", "c", "d", "e"), make(stringSet)}, + } + + for n, in := range inputs { + res := expected[n] + include, exclude, otherInclude, otherExclude := parseNumberMenu(in) + + if !intRangesEqual(include, res.Include) || + !intRangesEqual(exclude, res.Exclude) || + !stringSetEqual(otherInclude, res.OtherInclude) || + !stringSetEqual(otherExclude, res.OtherExclude) { + + t.Fatalf("Test %d Failed: Expected: include=%+v exclude=%+v otherInclude=%+v otherExclude=%+v got include=%+v excluive=%+v otherInclude=%+v otherExclude=%+v", + n+1, res.Include, res.Exclude, res.OtherInclude, res.OtherExclude, include, exclude, otherInclude, otherExclude) + } + } +} diff --git a/query.go b/query.go index 85e182ad..31f7f4b3 100644 --- a/query.go +++ b/query.go @@ -317,6 +317,13 @@ func min(a, b int) int { return b } +func max(a, b int) int { + if a < b { + return b + } + return a +} + // Queries the aur for information about specified packages. // All packages should be queried in a single rpc request except when the number // of packages exceeds the number set in config.RequestSplitN. diff --git a/vcs_test.go b/vcs_test.go index afe401be..5354b40b 100644 --- a/vcs_test.go +++ b/vcs_test.go @@ -60,7 +60,7 @@ func TestParsing(t *testing.T) { branch != compare.Branch || !isEqual(protocols, compare.Protocols) { - t.Fatalf("Expected url=%+v branch=%+v protocols=%+v\ngot url=%+v branch=%+v protocols=%+v", url, branch, protocols, compare.URL, compare.Branch, compare.Protocols) + t.Fatalf("Test %d failed: Expected: url=%+v branch=%+v protocols=%+v\ngot url=%+v branch=%+v protocols=%+v", n+1, url, branch, protocols, compare.URL, compare.Branch, compare.Protocols) } } From 2aadd1931cbccb471455a4402a2ac4ed2a72d427 Mon Sep 17 00:00:00 2001 From: morganamilo Date: Fri, 9 Mar 2018 03:41:45 +0000 Subject: [PATCH 3/6] Refactor and improve the upgrade menu With the planned move to number menus for askcleanbuilds and askeditpkgbuilds a consistant way is needed to make number menus in a clean way without rewriting the same code over and over. The prevous commit introduced `parseNumerMenu()` to create a standard way to handle number menus. This commit implements the new function for the upgrade menu both as a test and to bring some new features. Entering 1-9999999 will no longer cause ram usage to spike to 100% (before yay would try to build an []int containing the numbers 1 to 9999999). Suport for discarding/including entire repos by name > "54 aur extra" would skip the package numbered 54 and all packages that are listed as aur and extra. > "^devel ^20" would only install packages listed under devel and the package numbered 20 --- upgrade.go | 128 ++++++++++++++++++++--------------------------------- 1 file changed, 48 insertions(+), 80 deletions(-) diff --git a/upgrade.go b/upgrade.go index e4006327..bf0f83b6 100644 --- a/upgrade.go +++ b/upgrade.go @@ -5,8 +5,6 @@ import ( "fmt" "os" "sort" - "strconv" - "strings" "unicode" alpm "github.com/jguer/go-alpm" @@ -280,8 +278,6 @@ func removeIntListFromList(src, target []int) []int { // upgradePkgs handles updating the cache and installing updates. func upgradePkgs(dt *depTree) (stringSet, stringSet, error) { - var repoNums []int - var aurNums []int repoNames := make(stringSet) aurNames := make(stringSet) @@ -297,89 +293,61 @@ func upgradePkgs(dt *depTree) (stringSet, stringSet, error) { repoUp.Print(len(aurUp) + 1) aurUp.Print(1) - if !config.NoConfirm { - fmt.Println(bold(green(arrow + " Packages to not upgrade (eg: 1 2 3, 1-3 or ^4)"))) - fmt.Print(bold(green(arrow + " "))) - reader := bufio.NewReader(os.Stdin) - - numberBuf, overflow, err := reader.ReadLine() - if err != nil || overflow { - fmt.Println(err) - return repoNames, aurNames, err + if config.NoConfirm { + for _, up := range repoUp { + repoNames.set(up.Name) } - - result := strings.Fields(string(numberBuf)) - excludeAur := make([]int, 0) - excludeRepo := make([]int, 0) - for _, numS := range result { - negate := numS[0] == '^' - if negate { - numS = numS[1:] - } - var numbers []int - num, err := strconv.Atoi(numS) - if err != nil { - numbers, err = BuildRange(numS) - if err != nil { - continue - } - } else { - numbers = []int{num} - } - for _, target := range numbers { - if target > len(aurUp)+len(repoUp) || target <= 0 { - continue - } else if target <= len(aurUp) { - target = len(aurUp) - target - if negate { - excludeAur = append(excludeAur, target) - } else { - aurNums = append(aurNums, target) - } - } else { - target = len(aurUp) + len(repoUp) - target - if negate { - excludeRepo = append(excludeRepo, target) - } else { - repoNums = append(repoNums, target) - } - } - } + for _, up := range aurUp { + aurNames.set(up.Name) } - if len(repoNums) == 0 && len(aurNums) == 0 && - (len(excludeRepo) > 0 || len(excludeAur) > 0) { - if len(repoUp) > 0 { - repoNums = BuildIntRange(0, len(repoUp)-1) - } - if len(aurUp) > 0 { - aurNums = BuildIntRange(0, len(aurUp)-1) - } - } - aurNums = removeIntListFromList(excludeAur, aurNums) - repoNums = removeIntListFromList(excludeRepo, repoNums) + return repoNames, aurNames, nil } - if len(repoUp) != 0 { - repoloop: - for i, k := range repoUp { - for _, j := range repoNums { - if j == i { - continue repoloop - } - } - repoNames.set(k.Name) + fmt.Println(bold(green(arrow + " Packages to not upgrade (eg: 1 2 3, 1-3 or ^4)"))) + fmt.Print(bold(green(arrow + " "))) + reader := bufio.NewReader(os.Stdin) + + numberBuf, overflow, err := reader.ReadLine() + if err != nil { + return nil, nil, err + } + + if overflow { + return nil, nil, fmt.Errorf("Input too long") + } + + //upgrade menu asks you which packages to NOT upgrade so in this case + //include and exclude are kind of swaped + //include, exclude, other := parseNumberMenu(string(numberBuf)) + include, exclude, otherInclude, otherExclude := parseNumberMenu(string(numberBuf)) + + isInclude := len(exclude) == 0 && len(otherExclude) == 0 + + for i, pkg := range repoUp { + if isInclude && otherInclude.get(pkg.Repository) { + continue + } + + if isInclude && !include.get(len(repoUp)-i+len(aurUp)) { + repoNames.set(pkg.Name) + } + + if !isInclude && (exclude.get(len(repoUp)-i+len(aurUp)) || otherExclude.get(pkg.Repository)) { + repoNames.set(pkg.Name) } } - if len(aurUp) != 0 { - aurloop: - for i, k := range aurUp { - for _, j := range aurNums { - if j == i { - continue aurloop - } - } - aurNames.set(k.Name) + for i, pkg := range aurUp { + if isInclude && otherInclude.get(pkg.Repository) { + continue + } + + if isInclude && !include.get(len(aurUp)-i) { + aurNames.set(pkg.Name) + } + + if !isInclude && (exclude.get(len(aurUp)-i) || otherExclude.get(pkg.Repository)) { + aurNames.set(pkg.Name) } } From 287bac04c993351dbefc421c29272cb6ef7f0554 Mon Sep 17 00:00:00 2001 From: morganamilo Date: Fri, 9 Mar 2018 05:25:05 +0000 Subject: [PATCH 4/6] Use parseNumberMenu() for yogurt mode --- cmd.go | 97 ++++++++++++++++++++-------------------------------------- 1 file changed, 33 insertions(+), 64 deletions(-) diff --git a/cmd.go b/cmd.go index ef963863..ab9132fd 100644 --- a/cmd.go +++ b/cmd.go @@ -588,9 +588,6 @@ func removeListFromList(src, target []string) []string { // NumberMenu presents a CLI for selecting packages to install. func numberMenu(pkgS []string, flags []string) (err error) { - //func numberMenu(cmdArgs *arguments) (err error) { - var num int - aurQ, err := narrowSearch(pkgS, true) if err != nil { fmt.Println("Error during AUR search:", err) @@ -615,83 +612,55 @@ func numberMenu(pkgS []string, flags []string) (err error) { fmt.Println(bold(green(arrow + " Packages to install (eg: 1 2 3, 1-3 or ^4)"))) fmt.Print(bold(green(arrow + " "))) + reader := bufio.NewReader(os.Stdin) numberBuf, overflow, err := reader.ReadLine() - if err != nil || overflow { - fmt.Println(err) - return + + if err != nil { + return err } - numberString := string(numberBuf) - var aurI, aurNI, repoNI, repoI []string - result := strings.Fields(numberString) - for _, numS := range result { - negate := numS[0] == '^' - if negate { - numS = numS[1:] - } - var numbers []int - num, err = strconv.Atoi(numS) - if err != nil { - numbers, err = BuildRange(numS) - if err != nil { - continue - } - } else { - numbers = []int{num} + if overflow { + return fmt.Errorf("Input too long") + } + + include, exclude, _, otherExclude := parseNumberMenu(string(numberBuf)) + arguments := makeArguments() + + isInclude := len(exclude) == 0 && len(otherExclude) == 0 + + for i, pkg := range repoQ { + target := len(repoQ) - i + if config.SortMode == TopDown { + target = i + 1 } - // Install package - for _, x := range numbers { - var target string - if x > numaq+numpq || x <= 0 { - continue - } else if x > numpq { - if config.SortMode == BottomUp { - target = aurQ[numaq+numpq-x].Name - } else { - target = aurQ[x-numpq-1].Name - } - if negate { - aurNI = append(aurNI, target) - } else { - aurI = append(aurI, target) - } - } else { - if config.SortMode == BottomUp { - target = repoQ[numpq-x].Name() - } else { - target = repoQ[x-1].Name() - } - if negate { - repoNI = append(repoNI, target) - } else { - repoI = append(repoI, target) - } - } + if isInclude && include.get(target) { + arguments.addTarget(pkg.Name()) + } + if !isInclude && !exclude.get(target) { + arguments.addTarget(pkg.Name()) } } - if len(repoI) == 0 && len(aurI) == 0 && - (len(aurNI) > 0 || len(repoNI) > 0) { - // If no package was specified, only exclusions, exclude from all the - // packages - for _, pack := range aurQ { - aurI = append(aurI, pack.Name) + for i, pkg := range aurQ { + target := len(aurQ) - i + len(repoQ) + if config.SortMode == TopDown { + target = i + 1 + len(repoQ) } - for _, pack := range repoQ { - repoI = append(repoI, pack.Name()) + + if isInclude && include.get(target) { + arguments.addTarget(pkg.Name) + } + if !isInclude && !exclude.get(target) { + arguments.addTarget(pkg.Name) } } - aurI = removeListFromList(aurNI, aurI) - repoI = removeListFromList(repoNI, repoI) if config.SudoLoop { sudoLoopBackground() } - arguments := makeArguments() - arguments.addTarget(repoI...) - arguments.addTarget(aurI...) + err = install(arguments) return err From d03890a3c46c4675c6670c4519def1d3b0aa885f Mon Sep 17 00:00:00 2001 From: morganamilo Date: Fri, 9 Mar 2018 05:47:10 +0000 Subject: [PATCH 5/6] Remove unneeded functions --- cmd.go | 64 +--------------------------------------------------------- 1 file changed, 1 insertion(+), 63 deletions(-) diff --git a/cmd.go b/cmd.go index ab9132fd..0095e01e 100644 --- a/cmd.go +++ b/cmd.go @@ -4,7 +4,6 @@ import ( "bufio" "bytes" "encoding/json" - "errors" "fmt" "os" "os/exec" @@ -525,67 +524,6 @@ func handleRemove() (err error) { return } -// BuildIntRange build the range from start to end -func BuildIntRange(rangeStart, rangeEnd int) []int { - if rangeEnd-rangeStart == 0 { - // rangeEnd == rangeStart, which means no range - return []int{rangeStart} - } - if rangeEnd < rangeStart { - swap := rangeEnd - rangeEnd = rangeStart - rangeStart = swap - } - - final := make([]int, 0) - for i := rangeStart; i <= rangeEnd; i++ { - final = append(final, i) - } - return final -} - -// BuildRange construct a range of ints from the format 1-10 -func BuildRange(input string) ([]int, error) { - multipleNums := strings.Split(input, "-") - if len(multipleNums) != 2 { - return nil, errors.New("Invalid range") - } - - rangeStart, err := strconv.Atoi(multipleNums[0]) - if err != nil { - return nil, err - } - rangeEnd, err := strconv.Atoi(multipleNums[1]) - if err != nil { - return nil, err - } - - return BuildIntRange(rangeStart, rangeEnd), err -} - -// Contains returns whether e is present in s -func contains(s []string, e string) bool { - for _, a := range s { - if a == e { - return true - } - } - return false -} - -// RemoveIntListFromList removes all src's elements that are present in target -func removeListFromList(src, target []string) []string { - max := len(target) - for i := 0; i < max; i++ { - if contains(src, target[i]) { - target = append(target[:i], target[i+1:]...) - max-- - i-- - } - } - return target -} - // NumberMenu presents a CLI for selecting packages to install. func numberMenu(pkgS []string, flags []string) (err error) { aurQ, err := narrowSearch(pkgS, true) @@ -653,7 +591,7 @@ func numberMenu(pkgS []string, flags []string) (err error) { arguments.addTarget(pkg.Name) } if !isInclude && !exclude.get(target) { - arguments.addTarget(pkg.Name) + arguments.addTarget(pkg.Name) } } From f7abb1b0acb947b80e6eda3ca0c443f744ea62c6 Mon Sep 17 00:00:00 2001 From: morganamilo Date: Fri, 9 Mar 2018 22:11:30 +0000 Subject: [PATCH 6/6] Use numbermenu for cleanBuilds and editPkgbuilds --- install.go | 208 +++++++++++++++++++++++++++++++++++++++++++++++++---- upgrade.go | 2 +- 2 files changed, 194 insertions(+), 16 deletions(-) diff --git a/install.go b/install.go index 0a8b831a..d9ca3eb4 100644 --- a/install.go +++ b/install.go @@ -1,6 +1,7 @@ package main import ( + "bufio" "fmt" "io/ioutil" "os" @@ -118,6 +119,13 @@ func install(parser *arguments) error { printDepCatagories(dc) hasAur = len(dc.Aur) != 0 fmt.Println() + + if !parser.existsArg("gendb") { + err = checkForConflicts(dc) + if err != nil { + return err + } + } } if !parser.existsArg("gendb") && len(arguments.targets) > 0 { @@ -145,36 +153,31 @@ func install(parser *arguments) error { } if hasAur { - if !parser.existsArg("gendb") { - err = checkForConflicts(dc) - if err != nil { - return err - } - } - if len(dc.MakeOnly) > 0 { if !continueTask("Remove make dependencies after install?", "yY") { removeMake = true } } - askCleanBuilds(dc.Aur, dc.Bases) - - if !continueTask("Proceed with Download?", "nN") { - return fmt.Errorf("Aborting due to user") + toClean, toEdit, err := cleanEditNumberMenu(dc.Aur, dc.Bases, remoteNamesCache) + if err != nil { + return err } + cleanBuilds(toClean) err = downloadPkgBuilds(dc.Aur, parser.targets, dc.Bases) if err != nil { return err } - err = askEditPkgBuilds(dc.Aur, dc.Bases) - if err != nil { - return err + if len(toEdit) > 0 { + err = editPkgBuilds(toEdit) + if err != nil { + return err + } } - if !continueTask("Proceed with install?", "nN") { + if len(toEdit) > 0 && !continueTask("Proceed with install?", "nN") { return fmt.Errorf("Aborting due to user") } @@ -244,6 +247,154 @@ func install(parser *arguments) error { return nil } +func cleanEditNumberMenu(pkgs []*rpc.Pkg, bases map[string][]*rpc.Pkg, installed stringSet) ([]*rpc.Pkg, []*rpc.Pkg, error) { + toPrint := "" + askClean := false + + toClean := make([]*rpc.Pkg, 0) + toEdit := make([]*rpc.Pkg, 0) + + if config.NoConfirm { + return toClean, toEdit, nil + } + + for n, pkg := range pkgs { + dir := config.BuildDir + pkg.PackageBase + "/" + + toPrint += magenta(strconv.Itoa(len(pkgs)-n)) + " " + bold(formatPkgbase(pkg, bases)) + if installed.get(pkg.Name) { + toPrint += bold(green(" (Installed)")) + } + + if _, err := os.Stat(dir); !os.IsNotExist(err) { + toPrint += bold(green(" (Build Files Exist)")) + askClean = true + } + + toPrint += "\n" + } + + fmt.Print(toPrint) + + if askClean { + fmt.Println(bold(green(arrow+" Packages to cleanBuild?"))) + fmt.Println(bold(green(arrow) + cyan(" [N]one ") + green("[A]ll [Ab]ort [I]nstalled [No]tInstalled or (1 2 3, 1-3, ^4)"))) + fmt.Print(bold(green(arrow + " "))) + reader := bufio.NewReader(os.Stdin) + + numberBuf, overflow, err := reader.ReadLine() + if err != nil { + return nil, nil, err + } + + if overflow { + return nil, nil, fmt.Errorf("Input too long") + } + + cleanInput := string(numberBuf) + + cInclude, cExclude, cOtherInclude, cOtherExclude := parseNumberMenu(cleanInput) + cIsInclude := len(cExclude) == 0 && len(cOtherExclude) == 0 + + if cOtherInclude.get("abort") || cOtherInclude.get("ab") { + return nil, nil, fmt.Errorf("Aborting due to user") + } + + if !cOtherInclude.get("n") && !cOtherInclude.get("none") { + for i, pkg := range pkgs { + dir := config.BuildDir + pkg.PackageBase + "/" + if _, err := os.Stat(dir); os.IsNotExist(err) { + continue + } + + if !cIsInclude && cExclude.get(len(pkgs)-i) { + continue + } + + if installed.get(pkg.Name) && (cOtherInclude.get("i") || cOtherInclude.get("installed")) { + toClean = append(toClean, pkg) + continue + } + + if !installed.get(pkg.Name) && (cOtherInclude.get("no") || cOtherInclude.get("notinstalled")) { + toClean = append(toClean, pkg) + continue + } + + if cOtherInclude.get("a") || cOtherInclude.get("all") { + toClean = append(toClean, pkg) + continue + } + + if cIsInclude && cInclude.get(len(pkgs)-i) { + toClean = append(toClean, pkg) + } + + if !cIsInclude && !cExclude.get(len(pkgs)-i) { + toClean = append(toClean, pkg) + } + } + } + } + + fmt.Println(bold(green(arrow+" PKGBUILDs to edit?"))) + fmt.Println(bold(green(arrow) +cyan(" [N]one ") + green("[A]ll [Ab]ort [I]nstalled [No]tInstalled or (1 2 3, 1-3, ^4)"))) + + fmt.Print(bold(green(arrow + " "))) + reader := bufio.NewReader(os.Stdin) + + numberBuf, overflow, err := reader.ReadLine() + if err != nil { + return nil, nil, err + } + + if overflow { + return nil, nil, fmt.Errorf("Input too long") + } + + editInput := string(numberBuf) + + eInclude, eExclude, eOtherInclude, eOtherExclude := parseNumberMenu(editInput) + eIsInclude := len(eExclude) == 0 && len(eOtherExclude) == 0 + + if eOtherInclude.get("abort") || eOtherInclude.get("ab") { + return nil, nil, fmt.Errorf("Aborting due to user") + } + + if !eOtherInclude.get("n") && !eOtherInclude.get("none") { + for i, pkg := range pkgs { + if !eIsInclude && eExclude.get(len(pkgs)-i) { + continue + } + + if installed.get(pkg.Name) && (eOtherInclude.get("i") || eOtherInclude.get("installed")) { + toEdit = append(toEdit, pkg) + continue + } + + if !installed.get(pkg.Name) && (eOtherInclude.get("no") || eOtherInclude.get("notinstalled")) { + toEdit = append(toEdit, pkg) + continue + } + + if eOtherInclude.get("a") || eOtherInclude.get("all") { + toEdit = append(toEdit, pkg) + continue + } + + if eIsInclude && eInclude.get(len(pkgs)-i) { + toEdit = append(toEdit, pkg) + } + + if !eIsInclude && !eExclude.get(len(pkgs)-i) { + toEdit = append(toEdit, pkg) + } + } + } + + return toClean, toEdit, nil +} + func askCleanBuilds(pkgs []*rpc.Pkg, bases map[string][]*rpc.Pkg) { for _, pkg := range pkgs { dir := config.BuildDir + pkg.PackageBase + "/" @@ -265,6 +416,14 @@ func askCleanBuilds(pkgs []*rpc.Pkg, bases map[string][]*rpc.Pkg) { } } +func cleanBuilds(pkgs []*rpc.Pkg) { + for i, pkg := range pkgs { + dir := config.BuildDir + pkg.PackageBase + fmt.Printf(bold(cyan("::")+" Deleting (%d/%d): %s\n"), i+1, len(pkgs), dir) + os.RemoveAll(dir) + } +} + func checkForConflicts(dc *depCatagories) error { localDb, err := alpmHandle.LocalDb() if err != nil { @@ -308,6 +467,8 @@ func checkForConflicts(dc *depCatagories) error { fmt.Println(str) } + + fmt.Println() } return nil @@ -339,6 +500,23 @@ func askEditPkgBuilds(pkgs []*rpc.Pkg, bases map[string][]*rpc.Pkg) error { return nil } +func editPkgBuilds(pkgs []*rpc.Pkg) error { + pkgbuilds := make([]string, 0, len(pkgs)) + for _, pkg := range pkgs { + dir := config.BuildDir + pkg.PackageBase + "/" + pkgbuilds = append(pkgbuilds, dir+"PKGBUILD") + } + + editcmd := exec.Command(editor(), pkgbuilds...) + editcmd.Stdin, editcmd.Stdout, editcmd.Stderr = os.Stdin, os.Stdout, os.Stderr + err := editcmd.Run() + if err != nil { + return fmt.Errorf("Editor did not exit successfully, Abotring: %s", err) + } + + return nil +} + 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 + "/" diff --git a/upgrade.go b/upgrade.go index bf0f83b6..4407d84d 100644 --- a/upgrade.go +++ b/upgrade.go @@ -303,7 +303,7 @@ func upgradePkgs(dt *depTree) (stringSet, stringSet, error) { return repoNames, aurNames, nil } - fmt.Println(bold(green(arrow + " Packages to not upgrade (eg: 1 2 3, 1-3 or ^4)"))) + fmt.Println(bold(green(arrow + " Packages to not upgrade (eg: 1 2 3, 1-3, ^4 or repo name)"))) fmt.Print(bold(green(arrow + " "))) reader := bufio.NewReader(os.Stdin)