diff options
Diffstat (limited to 'cmd/slackware.com/main.go')
-rw-r--r-- | cmd/slackware.com/main.go | 271 |
1 files changed, 271 insertions, 0 deletions
diff --git a/cmd/slackware.com/main.go b/cmd/slackware.com/main.go new file mode 100644 index 0000000..54f171a --- /dev/null +++ b/cmd/slackware.com/main.go @@ -0,0 +1,271 @@ +package main + +import ( + "errors" + "fmt" + "net/url" + "os" + "path" + "slackware_com/internal/slackware_com" + "sort" + "strconv" + + "github.com/pborman/getopt/v2" + "golang.org/x/exp/maps" +) + +type Flags struct { + // local directory for downloads + Quiet bool + // remote root slackware package location + SlackwareMirror string +} + +var DefaultFlags = Flags{ + Quiet: false, + SlackwareMirror: "https://mirrors.kernel.org/slackware/slackware64-15.0", +} + +func applyEnvVars(flags *Flags) error { + var err error + if v, ok := os.LookupEnv("QUIET"); ok { + flags.Quiet, err = strconv.ParseBool(v) + } + if v, ok := os.LookupEnv("SLACKWARE_MIRROR"); ok { + flags.SlackwareMirror = v + } + + return err +} + +func applyCommandFlags(flags *Flags) { + getopt.FlagLong(&flags.Quiet, "quiet", 0, "be quiet") + getopt.FlagLong(&flags.SlackwareMirror, "slackware-mirror", 0, "/") + getopt.Parse() +} + +func ParseFlags() *Flags { + flags := DefaultFlags + + applyEnvVars(&flags) + applyCommandFlags(&flags) + + return &flags +} + +type SubCommand struct { + Description string + Command func(globalOpts *Flags, args []string) error +} + +func Unimplemented(globalOpts *Flags, args []string) error { + return errors.New("not implemented") +} + +var subcommands = map[string]SubCommand{ + "changelog": { + Description: "show changes described in the Changelog since the last update", + Command: func(globalOpts *Flags, args []string) error { + mirrorUrl, err := url.Parse(globalOpts.SlackwareMirror) + if err != nil { + return err + } + + mirror, err := slackware_com.OpenMirror(mirrorUrl) + if err != nil { + return err + } + + registry, err := slackware_com.NewPackageStore(slackware_com.PkgToolsPath) + if err != nil { + return err + } + installed, err := registry.GetInstalledPackages() + if err != nil { + return err + } + + lastInstall := slackware_com.GetLastInstallTime( + mirror.ChangeLog, + installed, + mirror.Checksums.Files(), + ) + + firstEntry := true + for _, entry := range mirror.ChangeLog.Entries { + if !entry.Time.After(lastInstall) { + continue + } + + if !firstEntry { + fmt.Println(slackware_com.Break) + firstEntry = false + } + fmt.Println(entry.String()) + } + + return nil + }, + }, + "download": { + Description: "download the given packages", + Command: func(globalOpts *Flags, args []string) error { + if len(args) <= 0 { + return errors.New("not enough arguments") + } + + mirrorUrl, err := url.Parse(globalOpts.SlackwareMirror) + if err != nil { + return err + } + + mirror, err := slackware_com.OpenMirror(mirrorUrl) + if err != nil { + return err + } + + var pkgPaths []string + for _, pattern := range args { + pkgPath, ok := mirror.FindPackage(slackware_com.PackageNamePattern(pattern)) + if !ok { + return fmt.Errorf("could not find '%s' at '%s'", pattern, mirrorUrl.String()) + } + + pkgPaths = append(pkgPaths, pkgPath) + } + + for _, pkgPath := range pkgPaths { + fileName := path.Base(pkgPath) + + tempFileName := fmt.Sprintf("%s.part", fileName) + f, err := os.Create(tempFileName) + if err != nil { + return err + } + defer f.Close() + + err = mirror.DownloadAndVerify(f, pkgPath) + if err != nil { + return fmt.Errorf("downloading '%s': %w", pkgPath, err) + } + + err = os.Rename(tempFileName, fileName) + if err != nil { + return err + } + fmt.Println(fileName) + } + + return nil + }, + }, + "list": { + Description: "list Slackware mirrors", + Command: Unimplemented, + }, + "sync": { + Description: "update knowledge about mirror's content", + Command: Unimplemented, + }, + "updates": { + Description: "print all new and updated packages on mirror", + Command: func(globalOpts *Flags, args []string) error { + mirrorUrl, err := url.Parse(globalOpts.SlackwareMirror) + if err != nil { + return err + } + + mirror, err := slackware_com.OpenMirror(mirrorUrl) + if err != nil { + return err + } + + registry, err := slackware_com.NewPackageStore(slackware_com.PkgToolsPath) + if err != nil { + return err + } + + installed, err := registry.GetInstalledPackages() + if err != nil { + return err + } + + isInstalled := make(map[string]bool) + for _, pkg := range installed { + isInstalled[pkg.Application] = true + } + + lastInstall := slackware_com.GetLastInstallTime( + mirror.ChangeLog, + installed, + mirror.Checksums.Files(), + ) + + var packages []slackware_com.PackageName + for _, entry := range mirror.ChangeLog.Entries { + if !entry.Time.After(lastInstall) { + continue + } + + for _, item := range entry.Items { + pathUpdate, ok := item.(slackware_com.PathUpdate) + if !ok { + continue + } + + // TODO: fix me + pkg, err := slackware_com.NewPackageNameFromPath(pathUpdate.GetPath()) + if err != nil { + continue + } + if !isInstalled[pkg.Application] { + continue + } + + packages = append(packages, pkg) + } + } + + for _, pkg := range packages { + fmt.Println(pkg.AppplicationVersion()) + } + + return err + }, + }, +} + +func printHelp(commands map[string]SubCommand) { + fmt.Printf("%s is an unofficial command line interface to Slackware's website.\n", os.Args[0]) + fmt.Println() + fmt.Println("The commands are:") + fmt.Println() + cmdNames := maps.Keys(commands) + sort.Strings(cmdNames) + for _, name := range cmdNames { + fmt.Printf("\t%s\n", name) + fmt.Printf("\t\t - %s\n", subcommands[name].Description) + } +} + +func main() { + userCommand := "" + args := os.Args + if len(args) > 1 { + userCommand = os.Args[1] + args = args[2:] + } + + cmd, ok := subcommands[userCommand] + if !ok { + printHelp(subcommands) + os.Exit(-1) + } + + flags := ParseFlags() + err := cmd.Command(flags, args) + if err != nil { + fmt.Fprintf(os.Stderr, "%s\n", err) + os.Exit(-1) + } +} |