diff --git a/swupd-inspector/cat.go b/swupd-inspector/cat.go index 60d71ce..2405a40 100644 --- a/swupd-inspector/cat.go +++ b/swupd-inspector/cat.go @@ -14,13 +14,8 @@ import ( // TODO: Support reading text files. -func runCat(cacheDir string, args []string) { - if len(args) != 2 { - usage() - os.Exit(2) - } - - base, version := parseURL(args[0]) +func runCat(cacheDir, url, arg string) { + base, version := parseURL(url) stateDir := filepath.Join(cacheDir, convertContentBaseToDirname(base)) state, err := client.NewState(stateDir, base) if err != nil { @@ -32,7 +27,6 @@ func runCat(cacheDir string, args []string) { log.Fatalf("ERROR: %s", err) } - arg := args[1] switch { case arg == "Manifest.MoM", arg == "Manifest.full": path, err := state.GetFile(version, arg) diff --git a/swupd-inspector/clean.go b/swupd-inspector/clean.go index ae6cd78..91e8e13 100644 --- a/swupd-inspector/clean.go +++ b/swupd-inspector/clean.go @@ -7,7 +7,7 @@ import ( "path/filepath" ) -func runClean(cacheDir string, args []string) { +func runClean(cacheDir string) { fis, err := ioutil.ReadDir(cacheDir) if err != nil { log.Fatalf("ERROR: %s", err) diff --git a/swupd-inspector/diff.go b/swupd-inspector/diff.go index 7c57196..ec4df2c 100644 --- a/swupd-inspector/diff.go +++ b/swupd-inspector/diff.go @@ -1,7 +1,6 @@ package main import ( - "flag" "fmt" "log" "path/filepath" @@ -20,38 +19,24 @@ var ( RESET = "\x1b[0m" ) -func runDiff(cacheDir string, args []string) { - var ( - noColor bool - strict bool - ) +type diffFlags struct { + noColor bool + strict bool +} - flagSet := flag.NewFlagSet("diff", flag.ExitOnError) - flagSet.BoolVar(&noColor, "no-color", false, "use no colors") - flagSet.BoolVar(&strict, "strict", false, "also compare version numbers") - flagSet.Usage = usage - err := flagSet.Parse(args) - if err != nil { - log.Fatalf("ERROR: %s", err) - } - - if len(flagSet.Args()) != 2 { - usage() - return - } - - if noColor { +func runDiff(cacheDir string, flags *diffFlags, urlA, urlB string) { + if flags.noColor { RED = "" GREEN = "" RESET = "" } - baseA, versionA := parseURL(flagSet.Arg(0)) - baseB, versionB := parseURL(flagSet.Arg(1)) + baseA, versionA := parseURL(urlA) + baseB, versionB := parseURL(urlB) var stateA, stateB *client.State stateDirA := filepath.Join(cacheDir, convertContentBaseToDirname(baseA)) - stateA, err = client.NewState(stateDirA, baseA) + stateA, err := client.NewState(stateDirA, baseA) if err != nil { log.Fatalf("ERROR: %s", err) } @@ -122,7 +107,7 @@ func runDiff(cacheDir string, args []string) { fmt.Printf("%s+%s%s %s%s\n", RED, a.Type, a.Status, a.Name, RESET) } else { fmt.Printf(" %s%s %s", a.Type, a.Status, a.Name) - if strict && a.Version != b.Version { + if flags.strict && a.Version != b.Version { fmt.Printf(" (VERSION: %s-%d%s / %s+%d%s)", RED, a.Version, RESET, GREEN, b.Version, RESET) } if a.Hash != b.Hash { @@ -140,7 +125,7 @@ func runDiff(cacheDir string, args []string) { }) fmt.Println() - flags := func(f *swupd.File) string { + flagString := func(f *swupd.File) string { result, err := f.GetFlagString() if err != nil { result = "...." @@ -202,16 +187,16 @@ func runDiff(cacheDir string, args []string) { walkFiles(mA.Files, mB.Files, func(a, b *swupd.File) { switch { case a == nil: - fmt.Printf("%s+%s %s%s\n", GREEN, flags(b), b.Name, RESET) + fmt.Printf("%s+%s %s%s\n", GREEN, flagString(b), b.Name, RESET) case b == nil: - fmt.Printf("%s-%s %s%s\n", RED, flags(a), a.Name, RESET) + fmt.Printf("%s-%s %s%s\n", RED, flagString(a), a.Name, RESET) default: - if flags(a) != flags(b) { - fmt.Printf("%s-%s %s%s\n", RED, flags(a), a.Name, RESET) - fmt.Printf("%s+%s %s%s\n", GREEN, flags(b), b.Name, RESET) - } else if a.Rename != b.Rename || a.Hash != b.Hash || (strict && a.Version != b.Version) { - fmt.Printf(" %s %s", flags(a), a.Name) - if strict && a.Version != b.Version { + if flagString(a) != flagString(b) { + fmt.Printf("%s-%s %s%s\n", RED, flagString(a), a.Name, RESET) + fmt.Printf("%s+%s %s%s\n", GREEN, flagString(b), b.Name, RESET) + } else if a.Rename != b.Rename || a.Hash != b.Hash || (flags.strict && a.Version != b.Version) { + fmt.Printf(" %s %s", flagString(a), a.Name) + if flags.strict && a.Version != b.Version { fmt.Printf(" (VERSION: %s-%d%s / %s+%d%s)", RED, a.Version, RESET, GREEN, b.Version, RESET) } if a.Rename != b.Rename { diff --git a/swupd-inspector/get.go b/swupd-inspector/get.go index daf0121..7e4dceb 100644 --- a/swupd-inspector/get.go +++ b/swupd-inspector/get.go @@ -12,13 +12,8 @@ import ( "github.com/clearlinux/mixer-tools/swupd" ) -func runGet(cacheDir string, args []string) { - if len(args) != 2 { - usage() - os.Exit(2) - } - - base, version := parseURL(args[0]) +func runGet(cacheDir, url, arg string) { + base, version := parseURL(url) stateDir := filepath.Join(cacheDir, convertContentBaseToDirname(base)) state, err := client.NewState(stateDir, base) if err != nil { @@ -30,7 +25,6 @@ func runGet(cacheDir string, args []string) { log.Fatalf("ERROR: %s", err) } - arg := args[1] switch { case arg == "Manifest.MoM", arg == "Manifest.full": diff --git a/swupd-inspector/log.go b/swupd-inspector/log.go index 0ea5b3c..0d10685 100644 --- a/swupd-inspector/log.go +++ b/swupd-inspector/log.go @@ -3,7 +3,6 @@ package main import ( "fmt" "log" - "os" "path/filepath" "github.com/clearlinux/mixer-tools/internal/client" @@ -12,21 +11,15 @@ import ( // TODO: Consider a --unique flag that would not print consecutive versions that have the same hash. -func runLog(cacheDir string, args []string) { - if len(args) != 2 { - usage() - os.Exit(2) - } - - base, version := parseURL(args[0]) +func runLog(cacheDir, url, filename string) { + base, version := parseURL(url) stateDir := filepath.Join(cacheDir, convertContentBaseToDirname(base)) state, err := client.NewState(stateDir, base) if err != nil { log.Fatalf("ERROR: %s", err) } - arg := args[1] - if arg == "" || arg[0] != '/' { + if filename == "" || filename[0] != '/' { // TODO: Support Manifest.* files too, but showing the diff of the files? log.Fatalf("Second argument to 'log' must be an absolute path") } @@ -44,7 +37,7 @@ func runLog(cacheDir string, args []string) { var found *swupd.File visit := func(bundle, file *swupd.File) bool { - if file.Name == arg && file.Present() { + if file.Name == filename && file.Present() { found = file lastBundle = bundle.Name return true @@ -95,7 +88,7 @@ func runLog(cacheDir string, args []string) { } if lastBundle == "" { - log.Fatalf("ERROR: file %s not found in version %s", arg, version) + log.Fatalf("ERROR: file %s not found in version %s", filename, version) } } diff --git a/swupd-inspector/main.go b/swupd-inspector/main.go index bc8a4c0..cf54ee1 100644 --- a/swupd-inspector/main.go +++ b/swupd-inspector/main.go @@ -2,13 +2,14 @@ package main import ( "bufio" - "fmt" "log" "os" "os/user" "path/filepath" "strconv" "strings" + + "github.com/spf13/cobra" ) // TODO: Flag to set cacheDir. @@ -17,58 +18,9 @@ import ( // TODO: Take into account deleted files, right now 'get' fails trying to download 0000...0.tar. -func usage() { - fmt.Printf(`swupd-inspector analyzes swupd content - -Commands: - - cat URL Manifest.NAME - Print the contents of the given Manifest. - - get URL Manifest.NAME - Download the contents of the given Manifest. - - get URL FILENAME - Search for the FILENAME and download the corresponding fullfile. - The FILENAME must be an absolute path. - - get URL HASH - Download the fullfile corresponding to the hash. - - diff [--strict] [--no-color] URL1 URL2 - Compare two versions of swupd content. The filenames and flags - will be compared, recursing to the bundles. Use --strict to - also compare the version numbers of the files. Use --no-color - to not emit escape codes in the output. - - log URL FILENAME - Show FILENAME version and its previous versions. - - clean - Clean up any cached content. - -The program will cache everything downloaded, and can keep content from -different sources. The cache directory is $HOME/.cache/swupd-inspector. - -The URLs must refer to a specific version like -https://download.clearlinux.org/update/20520. Absolute local paths can -also be used instead of URLs. - -It is possible to refer to content by aliases. The alias 'clear' works -by default, so clear/20520 refer to the same as the URL above. Other -aliases can be defined in $HOME/.config/swupd-inspector/aliases in the -format ALIAS=URL per line. -`) -} - func main() { log.SetFlags(0) - if len(os.Args) < 2 { - usage() - os.Exit(2) - } - user, err := user.Current() if err != nil { log.Fatal(err) @@ -83,26 +35,99 @@ func main() { log.Fatalf("couldn't create cache directory: %s", err) } - cmd := os.Args[1] - args := os.Args[2:] - switch cmd { - case "help", "-h", "--help": - usage() - os.Exit(0) - case "diff": - runDiff(cacheDir, args) - case "get": - runGet(cacheDir, args) - case "cat": - runCat(cacheDir, args) - case "log": - runLog(cacheDir, args) - case "clean": - runClean(cacheDir, args) - default: - usage() - os.Exit(2) + rootCmd := &cobra.Command{ + Use: "swupd-inspector", + Short: "Inspect and download swupd content", + Long: `Inspect and download swupd content + +The program will cache everything downloaded, and can keep content from +different sources. The cache directory is $HOME/.cache/swupd-inspector. + +The URLs must refer to a specific version like +https://download.clearlinux.org/update/20520. Absolute local paths can +also be used instead of URLs. + +It is possible to refer to content by aliases. The alias 'clear' works +by default, so clear/20520 refer to the same as the URL above. Other +aliases can be defined in $HOME/.config/swupd-inspector/aliases in the +format ALIAS=URL per line. +`, } + + diffFlags := &diffFlags{} + diffCmd := &cobra.Command{ + Use: "diff [flags] URL1 URL2", + Short: "Compare two versions of swupd content", + Long: `Compare two versions of swupd content. + +The filenames and flags will be compared, recursing to the +bundles. Use --strict to also compare the version numbers of the +files. Use --no-color to not emit escape codes in the output. +`, + Args: cobra.ExactArgs(2), + Run: func(cmd *cobra.Command, args []string) { + runDiff(cacheDir, diffFlags, args[0], args[1]) + }, + } + diffCmd.Flags().BoolVar(&diffFlags.noColor, "no-color", false, "disable colored output") + diffCmd.Flags().BoolVar(&diffFlags.strict, "strict", false, "compare version numbers of files") + rootCmd.AddCommand(diffCmd) + + getCmd := &cobra.Command{ + Use: "get [flags] URL (FILENAME|HASH|Manifest.NAME)", + Short: "Download content from a swupd repository", + Long: `Download content from a swupd repository. + +Different types of content can be downloaded: + + swupd-inspector get URL Manifest.NAME + Download the contents of the given Manifest. + + swupd-inspector get URL FILENAME + Search for the FILENAME and download the corresponding fullfile. + The FILENAME must be an absolute path. + + swupd-inspector get URL HASH + Download the fullfile corresponding to the hash. +`, + Args: cobra.ExactArgs(2), + Run: func(cmd *cobra.Command, args []string) { + runGet(cacheDir, args[0], args[1]) + }, + } + rootCmd.AddCommand(getCmd) + + cleanCmd := &cobra.Command{ + Use: "clean", + Short: "Clean up any cached content", + Args: cobra.NoArgs, + Run: func(cmd *cobra.Command, args []string) { + runClean(cacheDir) + }, + } + rootCmd.AddCommand(cleanCmd) + + catCmd := &cobra.Command{ + Use: "cat [flags] URL Manifest.NAME", + Short: "Print the contents of a Manifest", + Args: cobra.ExactArgs(2), + Run: func(cmd *cobra.Command, args []string) { + runCat(cacheDir, args[0], args[1]) + }, + } + rootCmd.AddCommand(catCmd) + + logCmd := &cobra.Command{ + Use: "log [flags] URL FILENAME", + Short: "Print FILENAME version and all previous versions", + Args: cobra.ExactArgs(2), + Run: func(cmd *cobra.Command, args []string) { + runLog(cacheDir, args[0], args[1]) + }, + } + rootCmd.AddCommand(logCmd) + + _ = rootCmd.Execute() } var aliases = map[string]string{