// Copyright (C) 2024 Umorpha Systems // SPDX-License-Identifier: AGPL-3.0-or-later package main import ( "context" "fmt" "os" "sort" "time" "github.com/datawire/ocibuild/pkg/cliutil" "github.com/spf13/cobra" source "git.mothstuff.lol/lukeshu/eclipse" "git.mothstuff.lol/lukeshu/eclipse/lib/gitcache" ) func main() { argparser := &cobra.Command{ Use: os.Args[0] + " {[flags]|SUBCOMMAND...}", Short: "Directly interact with a gitcache", Args: cliutil.WrapPositionalArgs(cliutil.OnlySubcommands), RunE: cliutil.RunSubcommands, SilenceErrors: true, // we'll handle this ourselves after .ExecuteContext() SilenceUsage: true, // FlagErrorFunc will handle this CompletionOptions: cobra.CompletionOptions{ DisableDefaultCmd: true, }, } argparser.SetFlagErrorFunc(cliutil.FlagErrorFunc) argparser.SetHelpTemplate(cliutil.HelpTemplate) var cache gitcache.Cache argparser.PersistentFlags().StringVarP(&cache.Dir, "cache-dir", "d", source.DefaultGitCacheDir, "Where to store cached data") _ = argparser.MarkFlagDirname("cache-dir") argparser.PersistentFlags().DurationVar(&cache.MinPeriod, "min-interval", 5*time.Second, "Do not fetch from the same remote more often than this") argparser.AddCommand(&cobra.Command{ Use: "fetch [flags] URL", Short: "Update the cache's store of the repository at URL", Args: cliutil.WrapPositionalArgs(cobra.ExactArgs(1)), RunE: func(_ *cobra.Command, args []string) error { return cache.Fetch(os.Stderr, args[0]) }, }) var noFetch bool revParse := &cobra.Command{ Use: "rev-parse [flags] URL REVS...", Short: "Resolve each REV to an object ID within the repository at URL", Args: cliutil.WrapPositionalArgs(cobra.MinimumNArgs(2)), RunE: func(_ *cobra.Command, args []string) error { url := args[0] revglobs := args[1:] if !noFetch { if err := cache.Fetch(os.Stderr, url); err != nil { fmt.Fprintf(os.Stderr, "[gitcache] Ignoring update error: %v\n", err) } } ret, err := cache.RevParse(os.Stderr, url, revglobs...) if err != nil { return err } failed := 0 for _, revglob := range revglobs { matches := ret[revglob] if len(matches) == 0 { failed++ } fmt.Printf("%s => (%d)", revglob, len(matches)) refnames := make([]string, 0, len(matches)) for refname := range matches { refnames = append(refnames, refname) } sort.Strings(refnames) for _, refname := range refnames { fmt.Printf(" %s:%s", refname, matches[refname]) } fmt.Printf("\n") } if failed > 0 { return fmt.Errorf("failed to resolve %d revision(s)", failed) } return nil }, } revParse.Flags().BoolVar(&noFetch, "no-fetch", false, "Do not attempt to update the cache before resolving the rev") argparser.AddCommand(revParse) clone := &cobra.Command{ Use: "clone [flags] URL DIR [-- GIT_CLONE_FLAGS...]", Short: "Clone the repository at URL from the cache to DIR", Args: cliutil.WrapPositionalArgs(cobra.MinimumNArgs(2)), RunE: func(cmd *cobra.Command, args []string) error { if !noFetch { if err := cache.Fetch(os.Stderr, args[0]); err != nil { fmt.Fprintf(os.Stderr, "[gitcache] Ignoring update error: %v\n", err) } } return cache.Clone(os.Stderr, args[0], args[1], args[2:]...) }, } clone.Flags().BoolVar(&noFetch, "no-fetch", false, "Do not attempt to update the cache before cloning") argparser.AddCommand(clone) argparser.AddCommand(&cobra.Command{ Use: "maintenance [flags] [-- GIT_MAINTENANCE_FLAGS...]", Short: "Run Git maintenance tasks (a la `git-maintenance run`)", RunE: func(cmd *cobra.Command, args []string) error { return cache.Maintenance(os.Stderr, args...) }, }) argparser.AddCommand(&cobra.Command{ Use: "url2ns [flags] URL", Short: "Convert a URL to a cache namespace", Args: cliutil.WrapPositionalArgs(cobra.ExactArgs(1)), RunE: func(_ *cobra.Command, args []string) error { fmt.Println(gitcache.URL2NS(args[0])) return nil }, }) argparser.AddCommand(&cobra.Command{ Use: "ns2url [flags] URL", Short: "Convert cache namespace to a URL", Args: cliutil.WrapPositionalArgs(cobra.ExactArgs(1)), RunE: func(_ *cobra.Command, args []string) error { fmt.Println(gitcache.NS2URL(args[0])) return nil }, }) ctx := context.Background() if err := argparser.ExecuteContext(ctx); err != nil { fmt.Fprintf(os.Stderr, "%v: error: %v\n", argparser.CommandPath(), err) os.Exit(1) } }