diff --git a/Gopkg.lock b/Gopkg.lock index ca500686..dd5f5044 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -5,7 +5,7 @@ branch = "master" name = "github.com/jguer/go-alpm" packages = ["."] - revision = "f82ad11b38f675991ef2425dbeff03ef346bc113" + revision = "542c122094f863fd9f5d412ab7c0bb57474e08ef" [[projects]] branch = "master" @@ -17,7 +17,7 @@ branch = "master" name = "github.com/mikkeloscar/gopkgbuild" packages = ["."] - revision = "a185f55210904932d0a58aaf30890f2c17218604" + revision = "a8070a8ab45a0f8cd4201ca7ed0f3efe4897bd2f" [solve-meta] analyzer-name = "dep" diff --git a/clean.go b/clean.go index 1877fbab..65f07193 100644 --- a/clean.go +++ b/clean.go @@ -32,7 +32,7 @@ func removeVCSPackage(pkgs []string) { } // CleanDependencies removes all dangling dependencies in system -func cleanDependencies(pkgs []string) error { +func cleanDependencies() error { hanging, err := hangingPackages() if err != nil { return err @@ -49,11 +49,15 @@ func cleanDependencies(pkgs []string) error { } // CleanRemove sends a full removal command to pacman with the pkgName slice -func cleanRemove(pkgName []string) (err error) { - if len(pkgName) == 0 { +func cleanRemove(pkgNames []string) (err error) { + if len(pkgNames) == 0 { return nil } + + arguments := makeArguments() + arguments.addArg("R", "noconfirm") + arguments.addTarget(pkgNames...) - err = passToPacman("-Rsnc", pkgName, []string{"--noconfirm"}) + err = passToPacman(arguments) return err } diff --git a/cmd.go b/cmd.go index 8f6990ca..ed09c9e8 100644 --- a/cmd.go +++ b/cmd.go @@ -7,51 +7,58 @@ import ( "fmt" "io" "os" + "os/exec" "path/filepath" "strconv" "strings" "time" ) +var cmdArgs = makeArguments() + func usage() { - fmt.Println(`usage: yay [...] - operations: - yay {-h --help} - yay {-V --version} - yay {-D --database} - yay {-F --files} [options] [package(s)] - yay {-Q --query} [options] [package(s)] - yay {-R --remove} [options] - yay {-S --sync} [options] [package(s)] - yay {-T --deptest} [options] [package(s)] - yay {-U --upgrade} [options] + fmt.Println(`Usage: + yay [...] + yay - New operations: - yay -Qstats displays system information - yay -Cd remove unneeded dependencies - yay -G [package(s)] get pkgbuild from ABS or AUR - yay --gendb generates development package DB used for updating. +operations: + yay {-h --help} + yay {-V --version} + yay {-D --database} + yay {-F --files} [options] [package(s)] + yay {-Q --query} [options] [package(s)] + yay {-R --remove} [options] + yay {-S --sync} [options] [package(s)] + yay {-T --deptest} [options] [package(s)] + yay {-U --upgrade} [options] - Permanent configuration options: - --topdown shows repository's packages first and then aur's - --bottomup shows aur's packages first and then repository's - --devel Check -git/-svn/-hg development version - --nodevel Disable development version checking - --afterclean Clean package sources after successful build - --noafterclean Disable package sources cleaning after successful build - --timeupdate Check package's modification date and version - --notimeupdate Check only package version change +New operations: + yay {-Y --yay} [options] [package(s)] + yay {-G --getpkgbuild} [package(s)] - New options: - --noconfirm skip user input on package install - --printconfig Prints current yay configuration - `) +Permanent configuration options: + --topdown Shows repository's packages first and then aur's + --bottomup Shows aur's packages first and then repository's + --devel Check -git/-svn/-hg development version + --nodevel Disable development version checking + --afterclean Clean package sources after successful build + --noafterclean Disable package sources cleaning after successful build + --timeupdate Check package's modification date and version + --notimeupdate Check only package version change + +Yay specific options: + --printconfig Prints current yay configuration + --stats Displays system information + --cleandeps Remove unneeded dependencies + --gendb Generates development package DB used for updating. + +If no operation is provided -Y will be assumed +`) } -func init() { +func initYay() (err error) { var configHome string // configHome handles config directory home var cacheHome string // cacheHome handles cache home - var err error if 0 == os.Geteuid() { fmt.Println("Please avoid running yay as root/sudo.") @@ -89,16 +96,16 @@ func init() { if _, err = os.Stat(configFile); os.IsNotExist(err) { err = os.MkdirAll(filepath.Dir(configFile), 0755) if err != nil { - fmt.Println("Unable to create config directory:", - filepath.Dir(configFile), err) - os.Exit(2) + err = fmt.Errorf("Unable to create config directory:\n%s\n"+ + "The error was:\n%s", filepath.Dir(configFile), err) + return } // Save the default config if nothing is found config.saveConfig() } else { cfile, errf := os.OpenFile(configFile, os.O_RDWR|os.O_CREATE, 0644) if errf != nil { - fmt.Println("Error reading config:", err) + fmt.Printf("Error reading config: %s\n", err) } else { defer cfile.Close() decoder := json.NewDecoder(cfile) @@ -123,190 +130,338 @@ func init() { _ = decoder.Decode(&savedInfo) } + return +} + +func initAlpm() (err error) { ///////////////// // alpm config // ///////////////// + + var value string + var exists bool + //var double bool + + value, _, exists = cmdArgs.getArg("config") + if exists { + config.PacmanConf = value + } + alpmConf, err = readAlpmConfig(config.PacmanConf) if err != nil { - fmt.Println("Unable to read Pacman conf", err) - os.Exit(1) + err = fmt.Errorf("Unable to read Pacman conf: %s", err) + return + } + + value, _, exists = cmdArgs.getArg("dbpath", "b") + if exists { + alpmConf.DBPath = value + } + + value, _, exists = cmdArgs.getArg("root", "r") + if exists { + alpmConf.RootDir = value + } + + value, _, exists = cmdArgs.getArg("arch") + if exists { + alpmConf.Architecture = value + } + + //TODO + //current system does not allow duplicate arguments + //but pacman allows multiple cachdirs to be passed + //for now only hanle one cache dir + value, _, exists = cmdArgs.getArg("cachdir") + if exists { + alpmConf.CacheDir = []string{value} + } + + value, _, exists = cmdArgs.getArg("gpgdir") + if exists { + alpmConf.GPGDir = value } alpmHandle, err = alpmConf.CreateHandle() if err != nil { - fmt.Println("Unable to CreateHandle", err) - os.Exit(1) - } -} - -func parser() (op string, options, packages []string, changedConfig bool, err error) { - if len(os.Args) < 2 { - err = fmt.Errorf("no operation specified") + err = fmt.Errorf("Unable to CreateHandle: %s", err) return } - changedConfig = false - op = "yogurt" - for _, arg := range os.Args[1:] { - if len(arg) < 2 { - continue - } - if arg[0] == '-' && arg[1] != '-' { - switch arg { - case "-V": - arg = "--version" - case "-h": - arg = "--help" - default: - op = arg - continue - } - } - - if strings.HasPrefix(arg, "--") { - changedConfig = true - switch arg { - case "--afterclean": - config.CleanAfter = true - case "--noafterclean": - config.CleanAfter = false - case "--printconfig": - fmt.Printf("%#v", config) - os.Exit(0) - case "--gendb": - err = createDevelDB() - if err != nil { - fmt.Println(err) - } - err = saveVCSInfo() - if err != nil { - fmt.Println(err) - } - os.Exit(0) - case "--devel": - config.Devel = true - case "--nodevel": - config.Devel = false - case "--timeupdate": - config.TimeUpdate = true - case "--notimeupdate": - config.TimeUpdate = false - case "--topdown": - config.SortMode = TopDown - case "--bottomup": - config.SortMode = BottomUp - case "--complete": - config.Shell = "sh" - _ = complete() - os.Exit(0) - case "--fcomplete": - config.Shell = fishShell - _ = complete() - os.Exit(0) - case "--help": - usage() - os.Exit(0) - case "--version": - fmt.Printf("yay v%s\n", version) - os.Exit(0) - case "--noconfirm": - config.NoConfirm = true - fallthrough - default: - options = append(options, arg) - } - continue - } - packages = append(packages, arg) - } return } func main() { - op, options, pkgs, changedConfig, err := parser() + var status int + var err error + var changedConfig bool + + err = cmdArgs.parseCommandLine() if err != nil { fmt.Println(err) - os.Exit(1) + status = 1 + goto cleanup } - switch op { - case "-Cd": - err = cleanDependencies(pkgs) - case "-G": - for _, pkg := range pkgs { - err = getPkgbuild(pkg) - if err != nil { - fmt.Println(pkg+":", err) - } - } - case "-Qstats": - err = localStatistics() - case "-Ss", "-Ssq", "-Sqs": - if op == "-Ss" { - config.SearchMode = Detailed - } else { - config.SearchMode = Minimal - } - - if pkgs != nil { - err = syncSearch(pkgs) - } - case "-S": - err = install(pkgs, options) - case "-Sy": - err = passToPacman("-Sy", nil, nil) - if err != nil { - break - } - err = install(pkgs, options) - case "-Syu", "-Suy", "-Su": - if strings.Contains(op, "y") { - err = passToPacman("-Sy", nil, nil) - if err != nil { - break - } - } - err = upgradePkgs(options) - case "-Si": - err = syncInfo(pkgs, options) - case "yogurt": - config.SearchMode = NumberMenu - - if pkgs != nil { - err = numberMenu(pkgs, options) - } - default: - if op[0] == 'R' { - removeVCSPackage(pkgs) - } - err = passToPacman(op, pkgs, options) + err = initYay() + if err != nil { + fmt.Println(err) + status = 1 + goto cleanup } - var erra error + err = initAlpm() + if err != nil { + fmt.Println(err) + status = 1 + goto cleanup + } + + changedConfig, err = handleCmd() + if err != nil { + fmt.Println(err) + status = 1 + goto cleanup + } + + //ive used a goto here + //i think its the best way to do this sort of thing +cleanup: + //cleanup + //from here on out dont exit if an error occurs + //if we fail to save the configuration + //atleast continue on and try clean up other parts + if updated { - erra = saveVCSInfo() - if erra != nil { + err = saveVCSInfo() + + if err != nil { fmt.Println(err) + status = 1 } } if changedConfig { - erra = config.saveConfig() - if erra != nil { + err = config.saveConfig() + + if err != nil { fmt.Println(err) + status = 1 + } + } + + if alpmHandle != nil { + err = alpmHandle.Release() + if err != nil { + fmt.Println(err) + status = 1 + } + } + + os.Exit(status) +} + +func handleCmd() (changedConfig bool, err error) { + changedConfig = false + + for option := range cmdArgs.options { + changedConfig = changedConfig || handleConfig(option) + } + + for option := range cmdArgs.globals { + changedConfig = changedConfig || handleConfig(option) + } + + switch cmdArgs.op { + case "V", "version": + handleVersion() + case "D", "database": + passToPacman(cmdArgs) + case "F", "files": + passToPacman(cmdArgs) + case "Q", "query": + passToPacman(cmdArgs) + case "R", "remove": + handleRemove() + case "S", "sync": + err = handleSync() + case "T", "deptest": + passToPacman(cmdArgs) + case "U", "upgrade": + passToPacman(cmdArgs) + case "G", "getpkgbuild": + err = handleGetpkgbuild() + case "Y", "--yay": + err = handleYay() + default: + //this means we allowed an op but not implement it + //if this happens it an error in the code and not the usage + err = fmt.Errorf("unhandled operation") + } + + return +} + +//this function should only set config options +//but currently still uses the switch left over from old code +//eventuall this should be refactored out futher +//my current plan is to have yay specific operations in its own operator +//e.g. yay -Y --gendb +//e.g yay -Yg +func handleConfig(option string) (changedConfig bool) { + switch option { + case "afterclean": + config.CleanAfter = true + case "noafterclean": + config.CleanAfter = false + // case "printconfig": + // fmt.Printf("%#v", config) + // os.Exit(0) + // case "gendb": + // err = createDevelDB() + // if err != nil { + // fmt.Println(err) + // } + // err = saveVCSInfo() + // if err != nil { + // fmt.Println(err) + // } + // os.Exit(0) + case "devel": + config.Devel = true + case "nodevel": + config.Devel = false + case "timeupdate": + config.TimeUpdate = true + case "notimeupdate": + config.TimeUpdate = false + case "topdown": + config.SortMode = TopDown + case "--bottomup": + config.SortMode = BottomUp + // case "complete": + // config.Shell = "sh" + // complete() + // os.Exit(0) + // case "fcomplete": + // config.Shell = fishShell + // complete() + // os.Exit(0) + // case "help": + // usage() + // os.Exit(0) + // case "version": + // fmt.Printf("yay v%s\n", version) + // os.Exit(0) + case "noconfirm": + config.NoConfirm = true + default: + return + } + + changedConfig = true + return +} + +func handleVersion() { + fmt.Printf("yay v%s\n", version) +} + +func handleYay() (err error) { + //_, options, targets := cmdArgs.formatArgs() + if cmdArgs.existsArg("h", "help") { + usage() + } else if cmdArgs.existsArg("printconfig") { + fmt.Printf("%#v", config) + } else if cmdArgs.existsArg("gendb") { + err = createDevelDB() + if err != nil { + return + } + err = saveVCSInfo() + if err != nil { + return + } + } else if cmdArgs.existsArg("complete") { + config.Shell = "sh" + complete() + } else if cmdArgs.existsArg("fcomplete") { + config.Shell = "fish" + complete() + } else if cmdArgs.existsArg("stats") { + err = localStatistics() + } else if cmdArgs.existsArg("cleandeps") { + err = cleanDependencies() + } else if len(cmdArgs.targets) > 0 { + err = handleYogurt() + } + + return +} + +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 arround this right now + fmt.Println(pkg+":", err) + } + } + + return +} + +func handleYogurt() (err error) { + options := cmdArgs.formatArgs() + targets := cmdArgs.formatTargets() + + config.SearchMode = NumberMenu + err = numberMenu(targets, options) + + return +} + +func handleSync() (err error) { + targets := cmdArgs.formatTargets() + options := cmdArgs.formatArgs() + + if cmdArgs.existsArg("y", "refresh") { + arguments := cmdArgs.copy() + arguments.delArg("u", "sysupgrade") + arguments.targets = make(stringSet) + err = passToPacman(arguments) + if err != nil { + return + } + } + + if cmdArgs.existsArg("s", "search") { + if cmdArgs.existsArg("q", "quiet") { + config.SearchMode = Minimal + } else { + config.SearchMode = Detailed } + 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, options) + } else if len(cmdArgs.targets) > 0 { + err = install(cmdArgs) } - erra = alpmHandle.Release() - if erra != nil { - fmt.Println(err) - } + return +} - if err != nil { - fmt.Println(err) - os.Exit(1) - } +func handleRemove() (err error) { + removeVCSPackage(cmdArgs.formatTargets()) + err = passToPacman(cmdArgs) + return } // BuildIntRange build the range from start to end @@ -372,6 +527,7 @@ 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) @@ -471,11 +627,14 @@ func numberMenu(pkgS []string, flags []string) (err error) { repoI = removeListFromList(repoNI, repoI) if len(repoI) != 0 { - err = passToPacman("-S", repoI, flags) + arguments := makeArguments() + arguments.addArg("S") + arguments.addTarget(repoI...) + err = passToPacman(arguments) } if len(aurI) != 0 { - err = aurInstall(aurI, flags) + err = aurInstall(aurI, nil) } return err @@ -510,3 +669,40 @@ func complete() error { _, err = io.Copy(os.Stdout, in) return err } + +// passToPacman outsorces execution to pacman binary without modifications. +func passToPacman(args *arguments) error { + var cmd *exec.Cmd + argArr := make([]string, 0) + + if args.needRoot() { + argArr = append(argArr, "sudo") + } + + argArr = append(argArr, "pacman") + argArr = append(argArr, cmdArgs.formatGlobals()...) + argArr = append(argArr, args.formatArgs()...) + argArr = append(argArr, args.formatTargets()...) + + cmd = exec.Command(argArr[0], argArr[1:]...) + + cmd.Stdin, cmd.Stdout, cmd.Stderr = os.Stdin, os.Stdout, os.Stderr + err := cmd.Run() + return err +} + +// passToMakepkg outsorces execution to makepkg binary without modifications. +func passToMakepkg(dir string, args ...string) (err error) { + cmd := exec.Command(config.MakepkgBin, args...) + cmd.Stdin, cmd.Stdout, cmd.Stderr = os.Stdin, os.Stdout, os.Stderr + cmd.Dir = dir + err = cmd.Run() + if err == nil { + _ = saveVCSInfo() + if config.CleanAfter { + fmt.Println("\x1b[1;32m==> CleanAfter enabled. Deleting source folder.\x1b[0m") + os.RemoveAll(dir) + } + } + return +} diff --git a/config.go b/config.go index db182548..ffe69328 100644 --- a/config.go +++ b/config.go @@ -6,7 +6,6 @@ import ( "os" "os/exec" "os/user" - "strings" alpm "github.com/jguer/go-alpm" ) @@ -195,30 +194,4 @@ func continueTask(s string, def string) (cont bool) { } return true -} - -// PassToPacman outsorces execution to pacman binary without modifications. -func passToPacman(op string, pkgs []string, flags []string) error { - var cmd *exec.Cmd - var args []string - - args = append(args, op) - if len(pkgs) != 0 { - args = append(args, pkgs...) - } - - if len(flags) != 0 { - args = append(args, flags...) - } - - if strings.Contains(op, "-Q") || op == "Si" { - cmd = exec.Command(config.PacmanBin, args...) - } else { - args = append([]string{config.PacmanBin}, args...) - cmd = exec.Command("sudo", args...) - } - - cmd.Stdin, cmd.Stdout, cmd.Stderr = os.Stdin, os.Stdout, os.Stderr - err := cmd.Run() - return err -} +} \ No newline at end of file diff --git a/install.go b/install.go index 23ff8039..61935576 100644 --- a/install.go +++ b/install.go @@ -10,18 +10,24 @@ import ( ) // Install handles package installs -func install(pkgs []string, flags []string) error { - aurs, repos, _ := packageSlices(pkgs) +func install(parser *arguments) error { + aurs, repos, _ := packageSlices(parser.targets.toSlice()) + + arguments := parser.copy() + arguments.delArg("u", "sysupgrade") + arguments.delArg("y", "refresh") + arguments.targets = make(stringSet) + arguments.addTarget(repos...) if len(repos) != 0 { - err := passToPacman("-S", repos, flags) + err := passToPacman(arguments) if err != nil { fmt.Println("Error installing repo packages.") } } if len(aurs) != 0 { - err := aurInstall(aurs, flags) + err := aurInstall(aurs, []string{"-S"}) if err != nil { fmt.Println("Error installing aur packages.") } @@ -130,15 +136,20 @@ func PkgInstall(a *rpc.Pkg, flags []string) (finalmdeps []string, err error) { } } + arguments := makeArguments() + arguments.addArg("S", "asdeps", "noconfirm") + arguments.addTarget(repoDeps...) + var depArgs []string if config.NoConfirm { - depArgs = []string{"--asdeps", "--noconfirm"} + depArgs = []string{"asdeps", "noconfirm"} } else { - depArgs = []string{"--asdeps"} + depArgs = []string{"asdeps"} } + // Repo dependencies if len(repoDeps) != 0 { - errR := passToPacman("-S", repoDeps, depArgs) + errR := passToPacman(arguments) if errR != nil { return finalmdeps, errR } @@ -156,18 +167,7 @@ func PkgInstall(a *rpc.Pkg, flags []string) (finalmdeps []string, err error) { } } - 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 - makepkgcmd.Dir = dir - err = makepkgcmd.Run() - if err == nil { - _ = saveVCSInfo() - if config.CleanAfter { - fmt.Println("\x1b[1;32m==> CleanAfter enabled. Deleting source folder.\x1b[0m") - os.RemoveAll(dir) - } - } + flags = append(flags, "-sri") + err = passToMakepkg(dir, flags...) return } diff --git a/parser.go b/parser.go new file mode 100644 index 00000000..3c945093 --- /dev/null +++ b/parser.go @@ -0,0 +1,542 @@ +package main + +import ( + "os" + "fmt" + "strings" + "io" +) + +type stringSet map[string]struct{} + +func (set stringSet) getAny() string { + for v := range set { + return v + } + + //maybe should return error instrad + return "" +} + +func (set stringSet) toSlice() []string { + slice := make([]string, 0, len(set)) + + for v := range set { + slice = append(slice, v) + } + + return slice +} + +func (set stringSet) removeAny() string { + v := set.getAny() + delete(set, v) + return v +} + + +type arguments struct { + op string + options map[string]string + globals map[string]string + doubles stringSet //tracks args passed twice such as -yy and -dd + targets stringSet +} + +func makeArguments() *arguments { + return &arguments { + "", + make(map[string]string), + make(map[string]string), + make(stringSet), + make(stringSet), + } +} + +func (parser *arguments) copy() (cp *arguments) { + cp = makeArguments() + + cp.op = parser.op + + for k,v := range parser.options { + cp.options[k] = v + } + + for k,v := range parser.globals { + cp.globals[k] = v + } + + for k,v := range parser.targets { + cp.targets[k] = v + } + + for k,v := range parser.doubles { + cp.doubles[k] = v + } + + return +} + + +func (parser *arguments) delArg(options ...string) { + for _, option := range options { + delete(parser.options, option) + delete(parser.globals, option) + delete(parser.doubles, option) + } +} + +func (parser *arguments) needRoot() bool { + if parser.existsArg("h", "help") { + return false + } + + if parser.existsArg("p", "print") { + return false + } + + switch parser.op { + case "V", "version": + return false + case "D", "database": + return true + case "F", "files": + if parser.existsArg("y", "refresh") { + return true + } + return false + case "Q", "query": + return false + case "R", "remove": + return true + case "S", "sync": + if parser.existsArg("y", "refresh") { + return true + } + if parser.existsArg("u", "sysupgrade") { + return true + } + if parser.existsArg("s", "search") { + return false + } + if parser.existsArg("l", "list") { + return false + } + if parser.existsArg("i", "info") { + return false + } + return true + case "T", "deptest": + return false + case "U", "upgrade": + return true + + //yay specific + case "Y", "yay": + return false + case "G", "getpkgbuild": + return false + default: + return false + } +} + +func (parser *arguments) addOP(op string) (err error) { + if parser.op != "" { + err = fmt.Errorf("only one operation may be used at a time") + return + } + + parser.op = op + return +} + +func (parser *arguments) addParam(option string, arg string) (err error) { + if isOp(option) { + err = parser.addOP(option) + return + } + + if parser.existsArg(option) { + parser.doubles[option] = struct{}{} + } else if isGlobal(option) { + parser.globals[option] = arg + } else { + parser.options[option] = arg + } + + return +} + +func (parser *arguments) addArg(options ...string) (err error) { + for _, option := range options { + err = parser.addParam(option, "") + if err != nil { + return + } + } + + return +} + +//multiple args acts as an OR operator +func (parser *arguments) existsArg(options ...string) bool { + for _, option := range options { + _, exists := parser.options[option] + if exists { + return true + } + + _, exists = parser.globals[option] + if exists { + return true + } + } + return false +} + +func (parser *arguments) getArg(options ...string) (arg string, double bool, exists bool) { + for _, option := range options { + arg, exists = parser.options[option] + + if exists { + _, double = parser.doubles[option] + return + } + + arg, exists = parser.globals[option] + + if exists { + _, double = parser.doubles[option] + return + } + } + + return +} + +func (parser *arguments) addTarget(targets ...string) { + for _, target := range targets { + parser.targets[target] = struct{}{} + } +} + +func (parser *arguments) delTarget(targets ...string) { + for _, target := range targets { + delete(parser.targets, target) + } +} + +//multiple args acts as an OR operator +func (parser *arguments) existsDouble(options ...string) bool { + for _, option := range options { + _, exists := parser.doubles[option] + if exists { + return true + } + } + + return false +} + +func (parser *arguments) formatTargets() (args []string) { + for target := range parser.targets { + args = append(args, target) + } + + return +} + +func (parser *arguments) formatArgs() (args []string) { + op := formatArg(parser.op) + args = append(args, op) + + for option, arg := range parser.options { + formatedOption := formatArg(option) + args = append(args, formatedOption) + + if hasParam(option) { + args = append(args, arg) + } + + if parser.existsDouble(option) { + args = append(args, formatedOption) + } + } + + return +} + +func (parser *arguments) formatGlobals() (args []string) { + for option, arg := range parser.globals { + formatedOption := formatArg(option) + args = append(args, formatedOption) + + if hasParam(option) { + args = append(args, arg) + } + + if parser.existsDouble(option) { + args = append(args, formatedOption) + } + } + + return + +} + +func formatArg(arg string) string { + if len(arg) > 1 { + arg = "--" + arg + } else { + arg = "-" + arg + } + + return arg +} + +func isOp(op string) bool { + switch op { + case "V", "version": + return true + case "D", "database": + return true + case "F", "files": + return true + case "Q", "query": + return true + case "R", "remove": + return true + case "S", "sync": + return true + case "T", "deptest": + return true + case "U", "upgrade": + return true + + //yay specific + case "Y", "yay": + return true + case "G", "getpkgbuild": + return true + default: + return false + } +} + +func isGlobal(op string) bool { + switch op { + case "b", "dbpath": + return true + case "r", "root": + return true + case "v", "verbose": + return true + case "arch": + return true + case "cachedir": + return true + case "color": + return true + case "config": + return true + case "debug": + return true + case "gpgdir": + return true + case "hookdir": + return true + case "logfile": + return true + case "noconfirm": + return true + case "confirm": + return true + default: + return false + } +} + +func isYayParam(arg string) bool { + switch arg { + case "afterclean": + return true + case "noafterclean": + return true + case "devel": + return true + case "nodevel": + return true + case "timeupdate": + return true + case "notimeupdate": + return true + case "topdown": + return true + default: + return false + } +} + +func hasParam(arg string) bool { + switch arg { + case "dbpath", "b": + return true + case "root", "r": + return true + case "sysroot": + return true + case "config": + return true + case "ignore": + return true + case "assume-installed": + return true + case "overwrite": + return true + case "ask": + return true + case "cachedir": + return true + case "hookdir": + return true + case "logfile": + return true + case "ignoregroup": + return true + case "arch": + return true + case "print-format": + return true + case "gpgdir": + return true + case "color": + return true + default: + return false + } +} + +//parses short hand options such as: +//-Syu -b/some/path - +func (parser *arguments) parseShortOption(arg string, param string) (usedNext bool, err error) { + if arg == "-" { + err = parser.addArg("-") + return + } + + arg = arg[1:] + + for k, _char := range arg { + char := string(_char) + + if hasParam(char) { + if k < len(arg) - 2 { + err = parser.addParam(char, arg[k+2:]) + } else { + usedNext = true + err = parser.addParam(char, param) + } + + break + } else { + err = parser.addArg(char) + + if err != nil { + return + } + } + } + + return +} + +//parses full length options such as: +//--sync --refresh --sysupgrade --dbpath /some/path -- +func (parser *arguments) parseLongOption(arg string, param string) (usedNext bool, err error){ + if arg == "--" { + err = parser.addArg(arg) + return + } + + arg = arg[2:] + + if hasParam(arg) { + err = parser.addParam(arg, param) + usedNext = true + } else { + err = parser.addArg(arg) + } + + return +} + +func (parser *arguments) parseStdin() (err error) { + for true { + var target string + _, err = fmt.Scan(&target) + + if err != nil { + if err == io.EOF { + err = nil + } + + return + } + + parser.addTarget(target) + } + + return +} + +func (parser *arguments)parseCommandLine() (err error) { + args := os.Args[1:] + usedNext := false + + if len(args) < 1 { + err = fmt.Errorf("no operation specified (use -h for help)") + return + } + + for k, arg := range args { + var nextArg string + + if usedNext { + usedNext = false + continue + } + + if k + 1 < len(args) { + nextArg = args[k + 1] + } + + if parser.existsArg("--") { + parser.addTarget(arg) + } else if strings.HasPrefix(arg, "--") { + usedNext, err = parser.parseLongOption(arg, nextArg) + } else if strings.HasPrefix(arg, "-") { + usedNext, err = parser.parseShortOption(arg, nextArg) + } else { + parser.addTarget(arg) + } + + if err != nil { + return + } + } + + if parser.op == "" { + parser.op = "Y" + } + + if cmdArgs.existsArg("-") { + err = cmdArgs.parseStdin(); + + if err != nil { + return + } + } + + return +} \ No newline at end of file diff --git a/query.go b/query.go index 63fba6e2..aa289678 100644 --- a/query.go +++ b/query.go @@ -169,7 +169,11 @@ func syncInfo(pkgS []string, flags []string) (err error) { } if len(repoS) != 0 { - err = passToPacman("-Si", repoS, flags) + arguments := makeArguments() + arguments.addArg("S", "i") + //arguments.addArg(flags...) + arguments.addTarget(repoS...) + err = passToPacman(arguments) } return diff --git a/upgrade.go b/upgrade.go index d13d0ee1..e6714608 100644 --- a/upgrade.go +++ b/upgrade.go @@ -138,37 +138,23 @@ loop: return } -func isIgnored(name string, groups []string, oldVersion string, newVersion string) bool { - for _, p := range alpmConf.IgnorePkg { - if p == name { - fmt.Printf("\x1b[33mwarning:\x1b[0m %s (ignored pkg) ignoring upgrade (%s -> %s)\n", name, oldVersion, newVersion) - return true - } - } - - for _, g := range alpmConf.IgnoreGroup { - for _, pg := range groups { - if g == pg { - fmt.Printf("\x1b[33mwarning:\x1b[0m %s (ignored pkg) ignoring upgrade (%s -> %s)\n", name, oldVersion, newVersion) - return true - } - } - - } - return false -} - -func upDevel(remoteNames []string, packageC chan upgrade, done chan bool) { +func upDevel(remote []alpm.Package, packageC chan upgrade, done chan bool) { for _, e := range savedInfo { if e.needsUpdate() { found := false - for _, r := range remoteNames { - if r == e.Package { + var pkg alpm.Package + for _, r := range remote { + if r.Name() == e.Package { found = true + pkg = r } } - if found && !isIgnored(e.Package, nil, e.SHA[0:6], "git") { - packageC <- upgrade{e.Package, "devel", e.SHA[0:6], "git"} + if found { + if pkg.ShouldIgnore() { + fmt.Printf("\x1b[33mwarning:\x1b[0m %s ignoring package upgrade (%s => %s)\n", pkg.Name(), pkg.Version(), "git") + } else { + packageC <- upgrade{e.Package, "devel", e.SHA[0:6], "git"} + } } else { removeVCSPackage([]string{e.Package}) } @@ -189,7 +175,7 @@ func upAUR(remote []alpm.Package, remoteNames []string) (toUpgrade upSlice, err if config.Devel { routines++ - go upDevel(remoteNames, packageC, done) + go upDevel(remote, packageC, done) fmt.Println("\x1b[1;36;1m::\x1b[0m\x1b[1m Checking development packages...\x1b[0m") } @@ -221,7 +207,9 @@ func upAUR(remote []alpm.Package, remoteNames []string) (toUpgrade upSlice, err } 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 !isIgnored(local[i].Name(), local[i].Groups().Slice(), local[i].Version(), qtemp[x].Version) { + if local[i].ShouldIgnore() { + fmt.Printf("\x1b[33mwarning:\x1b[0m %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} } } @@ -265,9 +253,12 @@ func upRepo(local []alpm.Package) (upSlice, error) { for _, pkg := range local { newPkg := pkg.NewVersion(dbList) - - if newPkg != nil && !isIgnored(pkg.Name(), pkg.Groups().Slice(), pkg.Version(), newPkg.Version()) { - slice = append(slice, upgrade{pkg.Name(), newPkg.DB().Name(), pkg.Version(), newPkg.Version()}) + if newPkg != nil { + if pkg.ShouldIgnore() { + fmt.Printf("\x1b[33mwarning:\x1b[0m %s ignoring package upgrade (%s => %s)\n", pkg.Name(), pkg.Version(), newPkg.Version()) + } else { + slice = append(slice, upgrade{pkg.Name(), newPkg.DB().Name(), pkg.Version(), newPkg.Version()}) + } } } return slice, nil @@ -386,7 +377,12 @@ func upgradePkgs(flags []string) error { repoNames = append(repoNames, k.Name) } - err := passToPacman("-S", repoNames, append(flags, "--noconfirm")) + arguments := makeArguments() + arguments.addArg("S", "noconfirm") + arguments.addArg(flags...) + arguments.addTarget(repoNames...) + + err := passToPacman(arguments) if err != nil { fmt.Println("Error upgrading repo packages.") } diff --git a/vendor/github.com/jguer/go-alpm/alpm_test.go b/vendor/github.com/jguer/go-alpm/alpm_test.go index 29ad7013..16f9470e 100644 --- a/vendor/github.com/jguer/go-alpm/alpm_test.go +++ b/vendor/github.com/jguer/go-alpm/alpm_test.go @@ -31,7 +31,7 @@ func init() { func ExampleVersion() { fmt.Println(Version()) // output: - // 8.0.2 + // 10.0.2 } func ExampleVerCmp() { diff --git a/vendor/github.com/jguer/go-alpm/conf.go b/vendor/github.com/jguer/go-alpm/conf.go index ed721fa1..7e351e85 100644 --- a/vendor/github.com/jguer/go-alpm/conf.go +++ b/vendor/github.com/jguer/go-alpm/conf.go @@ -13,6 +13,7 @@ import ( "io" "os" "reflect" + "strconv" "strings" "syscall" ) @@ -43,6 +44,7 @@ type PacmanConfig struct { RootDir string DBPath string CacheDir []string + HookDir []string GPGDir string LogFile string HoldPkg []string @@ -57,7 +59,7 @@ type PacmanConfig struct { SigLevel SigLevel LocalFileSigLevel SigLevel RemoteFileSigLevel SigLevel - UseDelta string + UseDelta float64 Options PacmanOption Repos []RepoConfig } @@ -112,14 +114,18 @@ func (rdr *confReader) ParseLine() (tok iniToken, err error) { rdr.Lineno++ line = bytes.TrimSpace(line) + + comment := bytes.IndexByte(line, '#') + if comment >= 0 { + line = line[:comment] + } + if len(line) == 0 { tok.Type = tokenComment return } + switch line[0] { - case '#': - tok.Type = tokenComment - return case '[': closing := bytes.IndexByte(line, ']') if closing < 0 { @@ -208,6 +214,17 @@ lineloop: rdr = newConfReader(f) rdrStack = append(rdrStack, rdr) continue lineloop + case "UseDelta": + if len(line.Values) > 0 { + deltaRatio, err := strconv.ParseFloat(line.Values[0], 64) + + if err != nil { + return conf, err + } + + conf.UseDelta = deltaRatio + } + continue lineloop } if currentSection != "options" { @@ -233,7 +250,7 @@ lineloop: *fieldP = strings.Join(line.Values, " ") case *[]string: //many valued option. - *fieldP = append(*fieldP, line.Values...) + *fieldP = line.Values } } } @@ -243,6 +260,17 @@ lineloop: func (conf *PacmanConfig) SetDefaults() { conf.RootDir = "/" conf.DBPath = "/var/lib/pacman" + conf.DBPath = "/var/lib/pacman/" + conf.CacheDir = []string{"/var/cache/pacman/pkg/"} + conf.HookDir = []string{"/etc/pacman.d/hooks/"} + conf.GPGDir = "/etc/pacman.d/gnupg/" + conf.LogFile = "/var/log/pacman.log" + conf.UseDelta = 0.7 + conf.CleanMethod = "KeepInstalled" + + conf.SigLevel = SigPackage | SigPackageOptional | SigDatabase | SigDatabaseOptional + conf.LocalFileSigLevel = SigUseDefault + conf.RemoteFileSigLevel = SigUseDefault } func getArch() (string, error) { @@ -272,6 +300,7 @@ func (conf *PacmanConfig) CreateHandle() (*Handle, error) { return nil, fmt.Errorf("architecture is 'auto' but couldn't uname()") } } + for _, repoconf := range conf.Repos { // TODO: set SigLevel db, err := h.RegisterSyncDb(repoconf.Name, 0) @@ -284,5 +313,85 @@ func (conf *PacmanConfig) CreateHandle() (*Handle, error) { db.SetServers(repoconf.Servers) } } + + err = h.SetCacheDirs(conf.CacheDir...) + if err != nil { + return nil, err + } + + // add hook directories 1-by-1 to avoid overwriting the system directory + for _,dir := range conf.HookDir { + err = h.AddHookDir(dir) + if err != nil { + return nil, err + } + } + + err = h.SetGPGDir(conf.GPGDir) + if err != nil { + return nil, err + } + + err = h.SetLogFile(conf.LogFile) + if err != nil { + return nil, err + } + + err = h.SetIgnorePkgs(conf.IgnorePkg...) + if err != nil { + return nil, err + } + + err = h.SetIgnoreGroups(conf.IgnoreGroup...) + if err != nil { + return nil, err + } + + err = h.SetArch(conf.Architecture) + if err != nil { + return nil, err + } + + h.SetNoUpgrades(conf.NoUpgrade...) + if err != nil { + return nil, err + } + + h.SetNoExtracts(conf.NoExtract...) + if err != nil { + return nil, err + } + + err = h.SetDefaultSigLevel(conf.SigLevel) + if err != nil { + return nil, err + } + + err = h.SetLocalFileSigLevel(conf.LocalFileSigLevel) + if err != nil { + return nil, err + } + + + err = h.SetRemoteFileSigLevel(conf.RemoteFileSigLevel) + if err != nil { + return nil, err + } + + err = h.SetDeltaRatio(conf.UseDelta) + if err != nil { + return nil, err + } + + err = h.SetUseSyslog(conf.Options & ConfUseSyslog > 0) + if err != nil { + return nil, err + } + + err = h.SetCheckSpace(conf.Options & ConfCheckSpace > 0) + if err != nil { + return nil, err + } + return h, nil } diff --git a/vendor/github.com/jguer/go-alpm/conf_test.go b/vendor/github.com/jguer/go-alpm/conf_test.go index 4750464b..e93c16fb 100644 --- a/vendor/github.com/jguer/go-alpm/conf_test.go +++ b/vendor/github.com/jguer/go-alpm/conf_test.go @@ -22,7 +22,7 @@ var pacmanConfRef = PacmanConfig{ XferCommand: "/usr/bin/wget --passive-ftp -c -O %o %u", Architecture: "auto", CleanMethod: "KeepInstalled", - UseDelta: "0.7", + UseDelta: 0.7, IgnorePkg: []string{"hello", "world"}, IgnoreGroup: []string{"kde"}, NoUpgrade: nil, diff --git a/vendor/github.com/jguer/go-alpm/handle.go b/vendor/github.com/jguer/go-alpm/handle.go index f3aac169..3d0a95b3 100644 --- a/vendor/github.com/jguer/go-alpm/handle.go +++ b/vendor/github.com/jguer/go-alpm/handle.go @@ -12,6 +12,8 @@ package alpm // #include +// #include //C.free +// #include //C.FNM_NOMATCH import "C" import ( @@ -25,12 +27,13 @@ type Handle struct { // Initialize func Init(root, dbpath string) (*Handle, error) { c_root := C.CString(root) - defer C.free(unsafe.Pointer(c_root)) c_dbpath := C.CString(dbpath) - defer C.free(unsafe.Pointer(c_dbpath)) var c_err C.alpm_errno_t h := C.alpm_initialize(c_root, c_dbpath, &c_err) + defer C.free(unsafe.Pointer(c_root)) + defer C.free(unsafe.Pointer(c_dbpath)) + if c_err != 0 { return nil, Error(c_err) } @@ -46,14 +49,6 @@ func (h *Handle) Release() error { return nil } -func (h Handle) Root() string { - return C.GoString(C.alpm_option_get_root(h.ptr)) -} - -func (h Handle) DbPath() string { - return C.GoString(C.alpm_option_get_dbpath(h.ptr)) -} - // LastError gets the last pm_error func (h Handle) LastError() error { if h.ptr != nil { @@ -65,21 +60,524 @@ func (h Handle) LastError() error { return nil } -func (h Handle) UseSyslog() bool { - value := C.alpm_option_get_usesyslog(h.ptr) - return (value != 0) +// +//alpm options getters and setters +// + +//helper functions for wrapping list_t getters and setters +func (h Handle) optionGetList(f func(*C.alpm_handle_t) *C.alpm_list_t) (StringList, error){ + alpmList := f(h.ptr) + goList := StringList{(*list)(unsafe.Pointer(alpmList))} + + if alpmList == nil { + return goList, h.LastError() + } + return goList, nil +} + + +func (h Handle) optionSetList(hookDirs []string, f func(*C.alpm_handle_t, *C.alpm_list_t) C.int) error { + var list *C.alpm_list_t = nil + + for _, dir := range hookDirs { + c_dir := C.CString(dir) + list = C.alpm_list_add(list, unsafe.Pointer(c_dir)) + defer C.free(unsafe.Pointer(c_dir)) + } + + ok := f(h.ptr, list) + if ok < 0 { + return h.LastError() + } + return nil +} + +func (h Handle) optionAddList(hookDir string, f func(*C.alpm_handle_t, *C.char) C.int) error { + c_hookdir := C.CString(hookDir) + defer C.free(unsafe.Pointer(c_hookdir)) + ok := f(h.ptr, c_hookdir) + if ok < 0 { + return h.LastError() + } + return nil +} + +func (h Handle) optionRemoveList(dir string, f func(*C.alpm_handle_t, *C.char) C.int) (bool, error) { + c_dir := C.CString(dir) + ok := f(h.ptr, c_dir) + defer C.free(unsafe.Pointer(c_dir)) + if ok < 0 { + return ok == 1, h.LastError() + } + return ok == 1, nil +} + +func (h Handle) optionMatchList(dir string, f func(*C.alpm_handle_t, *C.char) C.int) (bool, error) { + c_dir := C.CString(dir) + ok := f(h.ptr, c_dir) + defer C.free(unsafe.Pointer(c_dir)) + if ok == 0 { + return true, nil + } else if ok == C.FNM_NOMATCH { + return false, h.LastError() + } + return false, nil +} + +//helper functions for *char based getters and setters +func (h Handle) optionGetStr(f func(*C.alpm_handle_t) *C.char) (string, error) { + c_str := f(h.ptr) + str := C.GoString(c_str) + if c_str == nil { + return str, h.LastError() + } + + return str, nil +} + +func (h Handle) optionSetStr(str string, f func(*C.alpm_handle_t, *C.char) C.int) error { + c_str := C.CString(str) + defer C.free(unsafe.Pointer(c_str)) + ok := f(h.ptr, c_str) + + if ok < 0 { + h.LastError() + } + return nil +} + +// +//end of helpers +// + +func (h Handle) Root() (string, error) { + return h.optionGetStr(func(handle *C.alpm_handle_t) *C.char { + return C.alpm_option_get_root(handle) + }) +} + +func (h Handle) DBPath() (string, error) { + return h.optionGetStr(func(handle *C.alpm_handle_t) *C.char { + return C.alpm_option_get_dbpath(handle) + }) +} + +func (h Handle) Lockfile() (string, error) { + return h.optionGetStr(func(handle *C.alpm_handle_t) *C.char { + return C.alpm_option_get_lockfile(handle) + }) +} + + +func (h Handle) CacheDirs() (StringList, error) { + return h.optionGetList(func(handle *C.alpm_handle_t) *C.alpm_list_t { + return C.alpm_option_get_cachedirs(handle) + }) +} + +func (h Handle) AddCacheDir(hookDir string) error { + return h.optionAddList(hookDir, func(handle *C.alpm_handle_t, str *C.char) C.int { + return C.alpm_option_add_cachedir(handle, str) + }) +} + +func (h Handle) SetCacheDirs(hookDirs ...string) error { + return h.optionSetList(hookDirs, func(handle *C.alpm_handle_t, l *C.alpm_list_t) C.int { + return C.alpm_option_set_cachedirs(handle, l) + }) +} + +func (h Handle) RemoveCacheDir(dir string) (bool, error) { + return h.optionRemoveList(dir, func(handle *C.alpm_handle_t, str *C.char) C.int { + return C.alpm_option_remove_cachedir(handle, str) + }) +} + +func (h Handle) HookDirs() (StringList, error) { + return h.optionGetList(func(handle *C.alpm_handle_t) *C.alpm_list_t { + return C.alpm_option_get_hookdirs(handle) + }) +} + +func (h Handle) AddHookDir(hookDir string) error { + return h.optionAddList(hookDir, func(handle *C.alpm_handle_t, str *C.char) C.int { + return C.alpm_option_add_hookdir(handle, str) + }) +} + +func (h Handle) SetHookDirs(hookDirs ...string) error { + return h.optionSetList(hookDirs, func(handle *C.alpm_handle_t, l *C.alpm_list_t) C.int { + return C.alpm_option_set_hookdirs(handle, l) + }) +} + +func (h Handle) RemoveHookDir(dir string) (bool, error) { + return h.optionRemoveList(dir, func(handle *C.alpm_handle_t, str *C.char) C.int { + return C.alpm_option_remove_hookdir(handle, str) + }) +} + +func (h Handle) LogFile() (string, error) { + return h.optionGetStr(func(handle *C.alpm_handle_t) *C.char { + return C.alpm_option_get_logfile(handle) + }) +} + +func (h Handle) SetLogFile(str string) error { + return h.optionSetStr(str, func(handle *C.alpm_handle_t, c_str *C.char) C.int { + return C.alpm_option_set_logfile(handle, c_str) + }) +} + +func (h Handle) GPGDir() (string, error) { + return h.optionGetStr(func(handle *C.alpm_handle_t) *C.char { + return C.alpm_option_get_gpgdir(handle) + }) +} + +func (h Handle) SetGPGDir(str string) error { + return h.optionSetStr(str, func(handle *C.alpm_handle_t, c_str *C.char) C.int { + return C.alpm_option_set_gpgdir(handle, c_str) + }) +} + +func (h Handle) UseSyslog() (bool, error) { + ok := C.alpm_option_get_usesyslog(h.ptr) + b := false + + if ok > 0 { + b = true + } + if ok < 0 { + return b, h.LastError() + } + return b, nil } func (h Handle) SetUseSyslog(value bool) error { - var int_value C.int + var int_value C.int = 0 if value { int_value = 1 - } else { - int_value = 0 } + ok := C.alpm_option_set_usesyslog(h.ptr, int_value) if ok < 0 { return h.LastError() } return nil } + +func (h Handle) NoUpgrades() (StringList, error) { + return h.optionGetList(func(handle *C.alpm_handle_t) *C.alpm_list_t { + return C.alpm_option_get_noupgrades(handle) + }) +} + +func (h Handle) AddNoUpgrade(hookDir string) error { + return h.optionAddList(hookDir, func(handle *C.alpm_handle_t, str *C.char) C.int { + return C.alpm_option_add_noupgrade(handle, str) + }) +} + +func (h Handle) SetNoUpgrades(hookDirs ...string) error { + return h.optionSetList(hookDirs, func(handle *C.alpm_handle_t, l *C.alpm_list_t) C.int { + return C.alpm_option_set_noupgrades(handle, l) + }) +} + +func (h Handle) RemoveNoUpgrade(dir string) (bool, error) { + return h.optionRemoveList(dir, func(handle *C.alpm_handle_t, str *C.char) C.int { + return C.alpm_option_remove_noupgrade(handle, str) + }) +} + +func (h Handle) MatchNoUpgrade(dir string) (bool, error) { + return h.optionMatchList(dir, func(handle *C.alpm_handle_t, str *C.char) C.int { + return C.alpm_option_match_noupgrade(handle, str) + }) +} + +func (h Handle) NoExtracts() (StringList, error) { + return h.optionGetList(func(handle *C.alpm_handle_t) *C.alpm_list_t { + return C.alpm_option_get_noextracts(handle) + }) +} + +func (h Handle) AddNoExtract(hookDir string) error { + return h.optionAddList(hookDir, func(handle *C.alpm_handle_t, str *C.char) C.int { + return C.alpm_option_add_noextract(handle, str) + }) +} + +func (h Handle) SetNoExtracts(hookDirs ...string) error { + return h.optionSetList(hookDirs, func(handle *C.alpm_handle_t, l *C.alpm_list_t) C.int { + return C.alpm_option_set_noextracts(handle, l) + }) +} + +func (h Handle) RemoveNoExtract(dir string) (bool, error) { + return h.optionRemoveList(dir, func(handle *C.alpm_handle_t, str *C.char) C.int { + return C.alpm_option_remove_noextract(handle, str) + }) +} + +func (h Handle) MatchNoExtract(dir string) (bool, error) { + return h.optionMatchList(dir, func(handle *C.alpm_handle_t, str *C.char) C.int { + return C.alpm_option_match_noextract(handle, str) + }) +} + +func (h Handle) IgnorePkgs() (StringList, error) { + return h.optionGetList(func(handle *C.alpm_handle_t) *C.alpm_list_t { + return C.alpm_option_get_ignorepkgs(handle) + }) +} + +func (h Handle) AddIgnorePkg(hookDir string) error { + return h.optionAddList(hookDir, func(handle *C.alpm_handle_t, str *C.char) C.int { + return C.alpm_option_add_ignorepkg(handle, str) + }) +} + +func (h Handle) SetIgnorePkgs(hookDirs ...string) error { + return h.optionSetList(hookDirs, func(handle *C.alpm_handle_t, l *C.alpm_list_t) C.int { + return C.alpm_option_set_ignorepkgs(handle, l) + }) +} + +func (h Handle) RemoveIgnorePkg(dir string) (bool, error) { + return h.optionRemoveList(dir, func(handle *C.alpm_handle_t, str *C.char) C.int { + return C.alpm_option_remove_ignorepkg(handle, str) + }) +} + +func (h Handle) IgnoreGroups() (StringList, error) { + return h.optionGetList(func(handle *C.alpm_handle_t) *C.alpm_list_t { + return C.alpm_option_get_ignoregroups(handle) + }) +} + +func (h Handle) AddIgnoreGroup(hookDir string) error { + return h.optionAddList(hookDir, func(handle *C.alpm_handle_t, str *C.char) C.int { + return C.alpm_option_add_ignoregroup(handle, str) + }) +} + +func (h Handle) SetIgnoreGroups(hookDirs ...string) error { + return h.optionSetList(hookDirs, func(handle *C.alpm_handle_t, l *C.alpm_list_t) C.int { + return C.alpm_option_set_ignoregroups(handle, l) + }) +} + +func (h Handle) RemoveIgnoreGroup(dir string) (bool, error) { + return h.optionRemoveList(dir, func(handle *C.alpm_handle_t, str *C.char) C.int { + return C.alpm_option_remove_ignoregroup(handle, str) + }) +} + +/*func (h Handle) optionGetList(f func(*C.alpm_handle_t) *C.alpm_list_t) (StringList, error){ + alpmList := f(h.ptr) + goList := StringList{(*list)(unsafe.Pointer(alpmList))} + + if alpmList == nil { + return goList, h.LastError() + } + return goList, nil +}*/ + +//use alpm_depend_t +func (h Handle) AssumeInstalled() (DependList, error) { + alpmList := C.alpm_option_get_assumeinstalled(h.ptr) + depList := DependList{(*list)(unsafe.Pointer(alpmList))} + + if alpmList == nil { + return depList, h.LastError() + } + return depList, nil +} + +func (h Handle) AddAssumeInstalled(dep Depend) error { + c_dep := convertCDepend(dep) + defer freeCDepend(c_dep) + + ok := C.alpm_option_add_assumeinstalled(h.ptr, c_dep) + if ok < 0 { + return h.LastError() + } + return nil +} + +func (h Handle) SetAssumeInstalled(deps ...Depend) error { + //calling this function the first time causes alpm to set the + //assumeinstalled list to a list containing go allocated alpm_depend_t's + //this is bad because alpm might at some point tree to free them + //i believe this is whats causing this function to misbhave + //although i am not 100% sure + //maybe using C.malloc to make the struct could fix the problem + //pacamn does not use alpm_option_set_assumeinstalled in its source + //code so anybody using this should beable to do file without it + //although for the sake of completeness it would be nice to have this + //working + panic("This function (SetAssumeInstalled) does not work properly, please do not use. See source code for more details") + var list *C.alpm_list_t = nil + + for _, dep := range deps { + c_dep := convertCDepend(dep) + defer freeCDepend(c_dep) + list = C.alpm_list_add(list, unsafe.Pointer(c_dep)) + } + + ok := C.alpm_option_set_assumeinstalled(h.ptr, list) + if ok < 0 { + return h.LastError() + } + return nil + +} + +func (h Handle) RemoveAssumeInstalled(dep Depend) (bool, error) { + //internally alpm uses alpm_list_remove to remove a alpm_depend_t from + //the list + //i believe this function considers items equal if they are the same + //item in memeory, not just the same data + //every time we convert a go Depend to a alpm_depend_c we create a new + //instance of a alpm_depend_c + //this means that if you add a Depend using AddAssumeInstalled then try + //to remove it using the same Depend c will consider them different + //items and not remove them + //pacamn does not use alpm_option_set_assumeinstalled in its source + //code so anybody using this should beable to do file without it + //although for the sake of completeness it would be nice to have this + //working + panic("This function (RemoveAssumeInstalled) does not work properly, please do not use. See source code for more details") + c_dep := convertCDepend(dep) + defer freeCDepend(c_dep) + + ok := C.alpm_option_remove_assumeinstalled(h.ptr, c_dep) + if ok < 0 { + return ok == 1, h.LastError() + } + return ok == 1, nil +} + +func (h Handle) Arch() (string, error) { + return h.optionGetStr(func(handle *C.alpm_handle_t) *C.char { + return C.alpm_option_get_arch(handle) + }) +} + +func (h Handle) SetArch(str string) error { + return h.optionSetStr(str, func(handle *C.alpm_handle_t, c_str *C.char) C.int { + return C.alpm_option_set_arch(handle, c_str) + }) +} + + +func (h Handle) DeltaRatio() (float64, error) { + ok := C.alpm_option_get_deltaratio(h.ptr) + if ok < 0 { + return float64(ok), h.LastError() + } + return float64(ok), nil +} + +func (h Handle) SetDeltaRatio(ratio float64) error { + ok := C.alpm_option_set_deltaratio(h.ptr, C.double(ratio)) + if ok < 0 { + return h.LastError() + } + return nil +} + + +func (h Handle) CheckSpace() (bool, error) { + ok := C.alpm_option_get_checkspace(h.ptr) + b := false + + if ok > 0 { + b = true + } + if ok < 0 { + return b, h.LastError() + } + return b, nil +} + +func (h Handle) SetCheckSpace(value bool) error { + var int_value C.int = 0 + if value { + int_value = 1 + } + + ok := C.alpm_option_set_checkspace(h.ptr, int_value) + if ok < 0 { + return h.LastError() + } + return nil +} + +func (h Handle) DBExt() (string, error) { + return h.optionGetStr(func(handle *C.alpm_handle_t) *C.char { + return C.alpm_option_get_dbext(handle) + }) +} + +func (h Handle) SetDBExt(str string) error { + return h.optionSetStr(str, func(handle *C.alpm_handle_t, c_str *C.char) C.int { + return C.alpm_option_set_dbext(handle, c_str) + }) +} + +func (h Handle) GetDefaultSigLevel() (SigLevel, error) { + sigLevel := C.alpm_option_get_default_siglevel(h.ptr) + + if sigLevel < 0 { + return SigLevel(sigLevel), h.LastError() + } + return SigLevel(sigLevel), nil +} + +func (h Handle) SetDefaultSigLevel(siglevel SigLevel) error { + ok := C.alpm_option_set_default_siglevel(h.ptr, C.alpm_siglevel_t(siglevel)) + + if ok < 0 { + return h.LastError() + } + return nil +} + +func (h Handle) GetLocalFileSigLevel() (SigLevel, error) { + sigLevel := C.alpm_option_get_local_file_siglevel(h.ptr) + + if sigLevel < 0 { + return SigLevel(sigLevel), h.LastError() + } + return SigLevel(sigLevel), nil +} + +func (h Handle) SetLocalFileSigLevel(siglevel SigLevel) error { + ok := C.alpm_option_set_local_file_siglevel(h.ptr, C.alpm_siglevel_t(siglevel)) + + if ok < 0 { + return h.LastError() + } + return nil +} + +func (h Handle) GetRemoteFileSigLevel() (SigLevel, error) { + sigLevel := C.alpm_option_get_remote_file_siglevel(h.ptr) + + if sigLevel < 0 { + return SigLevel(sigLevel), h.LastError() + } + return SigLevel(sigLevel), nil +} + +func (h Handle) SetRemoteFileSigLevel(siglevel SigLevel) error { + ok := C.alpm_option_set_remote_file_siglevel(h.ptr, C.alpm_siglevel_t(siglevel)) + + if ok < 0 { + return h.LastError() + } + return nil +} diff --git a/vendor/github.com/jguer/go-alpm/package.go b/vendor/github.com/jguer/go-alpm/package.go index 6decfb43..e664ece4 100644 --- a/vendor/github.com/jguer/go-alpm/package.go +++ b/vendor/github.com/jguer/go-alpm/package.go @@ -13,9 +13,15 @@ int pkg_cmp(const void *v1, const void *v2) { alpm_pkg_t *p1 = (alpm_pkg_t *)v1; alpm_pkg_t *p2 = (alpm_pkg_t *)v2; - unsigned long int s1 = alpm_pkg_get_isize(p1); - unsigned long int s2 = alpm_pkg_get_isize(p2); - return(s2 - s1); + off_t s1 = alpm_pkg_get_isize(p1); + off_t s2 = alpm_pkg_get_isize(p2); + + if (s1 > s2) + return -1; + else if (s1 < s2) + return 1; + else + return 0; } */ import "C" @@ -244,3 +250,8 @@ func (pkg Package) NewVersion(l DbList) *Package { } return &Package{ptr, l.handle} } + +func (pkg Package) ShouldIgnore() bool { + result := C.alpm_pkg_should_ignore(pkg.handle.ptr, pkg.pmpkg) + return result == 1 +} diff --git a/vendor/github.com/jguer/go-alpm/package_test.go b/vendor/github.com/jguer/go-alpm/package_test.go index adc23a86..6bbde541 100644 --- a/vendor/github.com/jguer/go-alpm/package_test.go +++ b/vendor/github.com/jguer/go-alpm/package_test.go @@ -79,11 +79,13 @@ func TestPkginfo(t *testing.T) { buf := bytes.NewBuffer(nil) pkginfo_tpl.Execute(buf, PrettyPackage{*pkg}) t.Logf("%s...", buf.Bytes()[:1024]) + t.Logf("Should ignore %t", pkg.ShouldIgnore()) pkg, _ = db.PkgByName("linux") if pkg != nil { buf = bytes.NewBuffer(nil) pkginfo_tpl.Execute(buf, PrettyPackage{*pkg}) t.Logf("%s...", buf.Bytes()[:1024]) + t.Logf("Should ignore %t", pkg.ShouldIgnore()) } } diff --git a/vendor/github.com/jguer/go-alpm/types.go b/vendor/github.com/jguer/go-alpm/types.go index 7bd3cf47..c30f3ab6 100644 --- a/vendor/github.com/jguer/go-alpm/types.go +++ b/vendor/github.com/jguer/go-alpm/types.go @@ -19,14 +19,41 @@ import ( type Depend struct { Name string Version string + Description string + NameHash uint Mod DepMod } func convertDepend(dep *C.alpm_depend_t) Depend { return Depend{ - Name: C.GoString(dep.name), - Version: C.GoString(dep.version), - Mod: DepMod(dep.mod)} + Name: C.GoString(dep.name), + Version: C.GoString(dep.version), + Mod: DepMod(dep.mod), + Description: C.GoString(dep.desc), + NameHash: uint(dep.name_hash), + } +} + +func convertCDepend(dep Depend) *C.alpm_depend_t { + c_name := C.CString(dep.Name) + c_version := C.CString(dep.Version) + c_desc := C.CString(dep.Description) + + c_dep := C.alpm_depend_t{ + name: c_name, + version: c_version, + desc: c_desc, + name_hash: C.ulong(dep.NameHash), + mod: C.alpm_depmod_t(dep.Mod), + } + + return &c_dep +} + +func freeCDepend(dep *C.alpm_depend_t) { + defer C.free(unsafe.Pointer(dep.name)) + defer C.free(unsafe.Pointer(dep.version)) + defer C.free(unsafe.Pointer(dep.desc)) } func (dep Depend) String() string { diff --git a/vendor/github.com/mikkeloscar/gopkgbuild/pkgbuild.go b/vendor/github.com/mikkeloscar/gopkgbuild/pkgbuild.go index b6657613..f455e31a 100644 --- a/vendor/github.com/mikkeloscar/gopkgbuild/pkgbuild.go +++ b/vendor/github.com/mikkeloscar/gopkgbuild/pkgbuild.go @@ -204,6 +204,13 @@ func ParseSRCINFO(path string) (*PKGBUILD, error) { return parsePKGBUILD(string(f)) } +// ParseSRCINFOContent parses a .SRCINFO formatted byte slice. +// This is a safe alternative to ParsePKGBUILD given that the .SRCINFO content +// is available +func ParseSRCINFOContent(content []byte) (*PKGBUILD, error) { + return parsePKGBUILD(string(content)) +} + // parse a PKGBUILD and check that the required fields has a non-empty value func parsePKGBUILD(input string) (*PKGBUILD, error) { pkgb, err := parse(input) @@ -447,6 +454,10 @@ func parseDependency(dep string, deps []*Dependency) ([]*Dependency, error) { var name string var dependency *Dependency + if dep == "" { + return deps, nil + } + if dep[0] == '-' { return nil, fmt.Errorf("invalid dependency name") } @@ -526,5 +537,5 @@ func isValidPkgnameChar(c uint8) bool { // check if c is a valid pkgver char func isValidPkgverChar(c uint8) bool { - return isAlphaNumeric(c) || c == '_' || c == '+' || c == '.' + return isAlphaNumeric(c) || c == '_' || c == '+' || c == '.' || c == '~' } diff --git a/vendor/github.com/mikkeloscar/gopkgbuild/pkgbuild_test.go b/vendor/github.com/mikkeloscar/gopkgbuild/pkgbuild_test.go index 599a9f9e..08c033b9 100644 --- a/vendor/github.com/mikkeloscar/gopkgbuild/pkgbuild_test.go +++ b/vendor/github.com/mikkeloscar/gopkgbuild/pkgbuild_test.go @@ -9,11 +9,16 @@ func TestVersionParsing(t *testing.T) { "1.0.0.0.2": true, "a.3_4": true, "A.2": true, + "a~b~c": true, "_1.2": false, ".2": false, "a.2Ø": false, "1.?": false, "1.-": false, + "1 2": false, + "1\t2": false, + "1\n2": false, + "1\r2": false, } for version, valid := range versions { @@ -172,6 +177,7 @@ func TestRandomCoreSRCINFOs(t *testing.T) { "glibc", "systemd", "linux", + "pip2pkgbuild", } for _, srcinfo := range srcinfos { diff --git a/vendor/github.com/mikkeloscar/gopkgbuild/test_pkgbuilds/PKGBUILD_pip2pkgbuild b/vendor/github.com/mikkeloscar/gopkgbuild/test_pkgbuilds/PKGBUILD_pip2pkgbuild new file mode 100644 index 00000000..b6f93e0a --- /dev/null +++ b/vendor/github.com/mikkeloscar/gopkgbuild/test_pkgbuilds/PKGBUILD_pip2pkgbuild @@ -0,0 +1,40 @@ +# Maintainer: wenLiangcan + +pkgbase=('pip2pkgbuild') +pkgname=('pip2pkgbuild' 'python2-pip2pkgbuild') +_module='pip2pkgbuild' +pkgver='0.2.3' +pkgrel=1 +pkgdesc="Generate PKGBUILD file for a Python module from PyPi" +url="https://github.com/wenLiangcan/pip2pkgbuild" +depends=() +makedepends=('python-setuptools' 'python2-setuptools') +license=('MIT') +arch=('any') +source=("https://files.pythonhosted.org/packages/source/p/pip2pkgbuild/pip2pkgbuild-${pkgver}.tar.gz") +md5sums=('ba4c7a94ce78b8a62a5233bd8c265ec3') + +prepare() { + cp -a "${srcdir}/${_module}-${pkgver}"{,-python2} +} + +build() { + cd "${srcdir}/${_module}-${pkgver}" + python setup.py build + + cd "${srcdir}/${_module}-${pkgver}-python2" + python2 setup.py build +} + +package_pip2pkgbuild() { + depends+=('python' 'python-pip') + cd "${srcdir}/${_module}-${pkgver}" + python setup.py install --root="${pkgdir}" --optimize=1 --skip-build +} + +package_python2-pip2pkgbuild() { + depends+=('python2' 'python2-pip') + cd "${srcdir}/${_module}-${pkgver}-python2" + python2 setup.py install --root="${pkgdir}" --optimize=1 --skip-build + mv "${pkgdir}/usr/bin/pip2pkgbuild"{,2} +} diff --git a/vendor/github.com/mikkeloscar/gopkgbuild/test_pkgbuilds/SRCINFO_pip2pkgbuild b/vendor/github.com/mikkeloscar/gopkgbuild/test_pkgbuilds/SRCINFO_pip2pkgbuild new file mode 100644 index 00000000..4a8e4e17 --- /dev/null +++ b/vendor/github.com/mikkeloscar/gopkgbuild/test_pkgbuilds/SRCINFO_pip2pkgbuild @@ -0,0 +1,24 @@ +# Generated by mksrcinfo v8 +# Sat Dec 17 05:53:18 UTC 2016 +pkgbase = pip2pkgbuild + pkgdesc = Generate PKGBUILD file for a Python module from PyPi + pkgver = 0.2.3 + pkgrel = 1 + url = https://github.com/wenLiangcan/pip2pkgbuild + arch = any + license = MIT + makedepends = python-setuptools + makedepends = python2-setuptools + source = https://files.pythonhosted.org/packages/source/p/pip2pkgbuild/pip2pkgbuild-0.2.3.tar.gz + md5sums = ba4c7a94ce78b8a62a5233bd8c265ec3 + +pkgname = pip2pkgbuild + depends = + depends = python + depends = python-pip + +pkgname = python2-pip2pkgbuild + depends = + depends = python2 + depends = python2-pip +