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 9beaa75e..e33aa966 100644 --- a/cmd.go +++ b/cmd.go @@ -6,51 +6,58 @@ import ( "fmt" "io" "os" + "os/exec" "path/filepath" "strconv" "strings" "time" ) +var cmdArgs *arguments = 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.") @@ -88,15 +95,15 @@ 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:", 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.Println("Error reading config: %s", err) } else { defer cfile.Close() decoder := json.NewDecoder(cfile) @@ -120,194 +127,343 @@ 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 []string, packages []string, changedConfig bool, err error) { - if len(os.Args) < 2 { - err = fmt.Errorf("no operation specified") + err = fmt.Errorf("Unable to CreateHandle", 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 } // 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 aq, err := narrowSearch(pkgS, true) @@ -315,6 +471,7 @@ func numberMenu(pkgS []string, flags []string) (err error) { fmt.Println("Error during AUR search:", err) } numaq := len(aq) + pq, numpq, err := queryRepo(pkgS) if err != nil { return @@ -369,11 +526,14 @@ func numberMenu(pkgS []string, flags []string) (err error) { } 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 @@ -408,3 +568,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 bdf52edc..92924c3c 100644 --- a/upgrade.go +++ b/upgrade.go @@ -329,8 +329,13 @@ 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.") }