AT Protocol IPLD-CAR Repository toolkit (CLI)

change urfave cli -> cobra

tree bcbc6a52 5d8477f7

+2 -2
Makefile
··· 9 9 10 10 .PHONY: build 11 11 build: ## Build all executables 12 - go build ./cmd/atr.go 12 + go build -ldflags "-X main._version=`git tag --sort=-version:refname | head -n 1`" ./atr.go 13 13 b: 14 14 @make build 15 15 16 16 install: ## Install all executables 17 - go install -ldflags "-X main._version=`git tag --sort=-version:refname | head -n 1`" ./cmd/atr.go 17 + go install -ldflags "-X main._version=`git tag --sort=-version:refname | head -n 1`" ./atr.go 18 18 i: 19 19 @make install 20 20
+15
atr.go
··· 1 + package main 2 + 3 + import ( 4 + "github.com/atscan/atr/cmd" 5 + ) 6 + 7 + var _version string 8 + 9 + func main() { 10 + cmd.Execute() 11 + } 12 + 13 + func Version() string { 14 + return _version 15 + }
+6
cli/context.go
··· 1 + package cli 2 + 3 + type Context struct { 4 + Args []string 5 + WorkingDir string 6 + }
+31
cli/highlight.go
··· 1 + package cli 2 + 3 + import ( 4 + "io" 5 + 6 + "github.com/alecthomas/chroma" 7 + "github.com/alecthomas/chroma/formatters" 8 + "github.com/alecthomas/chroma/lexers" 9 + "github.com/alecthomas/chroma/styles" 10 + ) 11 + 12 + func Highlight(style string) func(w io.Writer, source string) { 13 + // Determine lexer. 14 + l := lexers.Get("json") 15 + l = chroma.Coalesce(l) 16 + 17 + // Determine formatter. 18 + f := formatters.Get("terminal") 19 + if f == nil { 20 + f = formatters.Fallback 21 + } 22 + // Determine style. 23 + s := styles.Get(style) 24 + if s == nil { 25 + s = styles.Fallback 26 + } 27 + return func(w io.Writer, source string) { 28 + it, _ := l.Tokenise(nil, source) 29 + f.Format(w, s, it) 30 + } 31 + }
+36
cli/print.go
··· 1 + package cli 2 + 3 + import ( 4 + "fmt" 5 + "io" 6 + "log" 7 + "os" 8 + 9 + jsoniter "github.com/json-iterator/go" 10 + ) 11 + 12 + func Print(v interface{}) error { 13 + json, err := jsoniter.Marshal(v) 14 + if err != nil { 15 + log.Fatal(err) 16 + } 17 + s := string(json) 18 + if s == "null" { 19 + return nil 20 + } 21 + fmt.Println(string(json)) 22 + return nil 23 + } 24 + 25 + func PrettyPrint(v interface{}, hg func(io.Writer, string)) error { 26 + json, err := jsoniter.MarshalIndent(v, "", " ") 27 + if err != nil { 28 + log.Fatal(err) 29 + } 30 + s := string(json) 31 + if s == "null" { 32 + return nil 33 + } 34 + hg(os.Stdout, s+"\n") 35 + return nil 36 + }
+51
cmd/atr-inspect.go
··· 1 + package cmd 2 + 3 + import ( 4 + "fmt" 5 + "os" 6 + 7 + "github.com/atscan/atr/cli" 8 + "github.com/atscan/atr/engine" 9 + "github.com/atscan/atr/repo" 10 + "github.com/dustin/go-humanize" 11 + "github.com/fatih/color" 12 + "github.com/spf13/cobra" 13 + ) 14 + 15 + func init() { 16 + rootCmd.AddCommand(InspectCmd) 17 + } 18 + 19 + var InspectCmd = &cobra.Command{ 20 + Use: "inspect", 21 + Aliases: []string{"i"}, 22 + Short: "Inspect repo(s)", 23 + Long: ``, 24 + Run: func(cmd *cobra.Command, args []string) { 25 + ctx := cli.Context{ 26 + WorkingDir: workingDir, 27 + Args: args, 28 + } 29 + 30 + walk := func(ss repo.RepoSnapshot, err error) { 31 + if ss.Root.String() == "b" { 32 + return 33 + } 34 + if ss.File == "" { 35 + ss.File = "(pipe)" 36 + } 37 + yellow := color.New(color.FgYellow).SprintFunc() 38 + cyan := color.New(color.FgCyan).SprintFunc() 39 + fmt.Printf("%v:\n Head: %s\n Size: %s Commits: %v\n\n", yellow(ss.File), cyan(ss.Root.String()), cyan(humanize.Bytes(uint64(ss.Size))), cyan(humanize.Comma(int64(len(ss.Items))))) 40 + } 41 + 42 + stat, _ := os.Stdin.Stat() 43 + if (stat.Mode() & os.ModeCharDevice) == 0 { 44 + // data is being piped to stdin 45 + engine.WalkStream(&ctx, os.Stdin, walk) 46 + } else { 47 + //stdin is from a terminal 48 + engine.WalkFiles(&ctx, walk) 49 + } 50 + }, 51 + }
+144
cmd/atr-show.go
··· 1 + package cmd 2 + 3 + import ( 4 + "log" 5 + "os" 6 + "os/exec" 7 + "regexp" 8 + "strings" 9 + 10 + "github.com/atscan/atr/cli" 11 + "github.com/atscan/atr/engine" 12 + "github.com/atscan/atr/repo" 13 + "github.com/itchyny/gojq" 14 + "github.com/jmespath/go-jmespath" 15 + jsoniter "github.com/json-iterator/go" 16 + "github.com/spf13/cobra" 17 + ) 18 + 19 + var ( 20 + Query string 21 + QueryJmes string 22 + Type string 23 + Raw bool 24 + ) 25 + 26 + func init() { 27 + rootCmd.AddCommand(ShowCmd) 28 + ShowCmd.Flags().StringVarP(&Type, "type", "t", "", "Filter by item type") 29 + ShowCmd.Flags().StringVarP(&Query, "query", "q", "", "Query results (jq)") 30 + ShowCmd.Flags().StringVarP(&QueryJmes, "query-jmes", "x", "", "Query results (jmespath)") 31 + ShowCmd.Flags().BoolVar(&Raw, "raw", false, "Do not use colors (faster)") 32 + } 33 + 34 + var ShowCmd = &cobra.Command{ 35 + Use: "show", 36 + Aliases: []string{"s"}, 37 + Short: "Show repo(s) documents", 38 + Long: ``, 39 + Run: func(cmd *cobra.Command, args []string) { 40 + ctx := cli.Context{ 41 + WorkingDir: workingDir, 42 + Args: args, 43 + } 44 + 45 + //q := ctx.Args().First() 46 + q := Query 47 + var query *gojq.Query 48 + if q != "" { 49 + tq, err := gojq.Parse(q) 50 + if err != nil { 51 + log.Fatalln("gojq parse error:", err) 52 + //return err 53 + } else { 54 + query = tq 55 + } 56 + } 57 + qq := QueryJmes 58 + var queryJmes *jmespath.JMESPath 59 + if qq != "" { 60 + jc, err := jmespath.Compile(qq) 61 + if err != nil { 62 + return 63 + } 64 + queryJmes = jc 65 + } 66 + 67 + eo, err := exec.Command("defaults", "read", "-g", "AppleInterfaceStyle").Output() 68 + if err != nil { 69 + log.Fatal(err) 70 + } 71 + style := "paraiso-dark" 72 + if strings.Index(string(eo), "Dark") != 0 { 73 + style = "paraiso-light" 74 + } 75 + hg := cli.Highlight(style) 76 + 77 + walk := func(ss repo.RepoSnapshot, err error) { 78 + 79 + for _, e := range ss.Items { 80 + tf := Type 81 + if tf != "" { 82 + if m := regexp.MustCompile(tf).Match([]byte(e.Path)); !m { 83 + continue 84 + } 85 + } 86 + var out interface{} 87 + if q != "" || qq != "" { 88 + json, err := jsoniter.Marshal(e.Body) 89 + if err != nil { 90 + log.Fatal("jsoniter error:", err) 91 + continue 92 + } 93 + var pv interface{} 94 + err = jsoniter.Unmarshal(json, &pv) 95 + if err != nil { 96 + log.Fatal("jsoniter error:", err) 97 + continue 98 + } 99 + if q != "" { 100 + iter := query.Run(interface{}(pv)) 101 + for { 102 + v, ok := iter.Next() 103 + if !ok { 104 + break 105 + } 106 + if err, ok := v.(error); ok { 107 + log.Fatalln("gojq iter error:", err) 108 + continue 109 + } 110 + if v == nil { 111 + continue 112 + } 113 + out = v 114 + } 115 + } 116 + if qq != "" { 117 + r, err := queryJmes.Search(pv) 118 + if err != nil { 119 + log.Fatalln("jmespath error:", err) 120 + } 121 + out = r 122 + } 123 + } else { 124 + out = e.Body 125 + } 126 + stat, _ := os.Stdout.Stat() 127 + if !Raw && (stat.Mode()&os.ModeCharDevice) != 0 { 128 + cli.PrettyPrint(out, hg) 129 + } else { 130 + cli.Print(out) 131 + } 132 + } 133 + } 134 + 135 + stat, _ := os.Stdin.Stat() 136 + if (stat.Mode() & os.ModeCharDevice) == 0 { 137 + // data is being piped to stdin 138 + engine.WalkStream(&ctx, os.Stdin, walk) 139 + } else { 140 + //stdin is from a terminal 141 + engine.WalkFiles(&ctx, walk) 142 + } 143 + }, 144 + }
-390
cmd/atr.go
··· 1 - package main 2 - 3 - import ( 4 - "bytes" 5 - "context" 6 - "errors" 7 - "fmt" 8 - "io" 9 - "log" 10 - "os" 11 - "os/exec" 12 - "path/filepath" 13 - "regexp" 14 - "strings" 15 - "syscall" 16 - 17 - "github.com/alecthomas/chroma" 18 - "github.com/alecthomas/chroma/formatters" 19 - "github.com/alecthomas/chroma/lexers" 20 - "github.com/alecthomas/chroma/styles" 21 - repo "github.com/atscan/atr/repo" 22 - "github.com/dustin/go-humanize" 23 - "github.com/fatih/color" 24 - "github.com/ipfs/go-cid" 25 - "github.com/itchyny/gojq" 26 - "github.com/jmespath/go-jmespath" 27 - jsoniter "github.com/json-iterator/go" 28 - "github.com/klauspost/compress/zstd" 29 - "github.com/urfave/cli/v2" 30 - ) 31 - 32 - var _version string 33 - 34 - func main() { 35 - 36 - app := &cli.App{ 37 - Name: "atr", 38 - Usage: "AT Protocol IPLD-CAR Repository toolkit", 39 - Version: _version, 40 - Flags: []cli.Flag{ 41 - &cli.StringFlag{ 42 - Name: "C", 43 - Usage: "Working directory", 44 - Value: ".", 45 - }, 46 - }, 47 - Commands: []*cli.Command{ 48 - ShowCommand, 49 - InspectCommand, 50 - }, 51 - } 52 - 53 - if err := app.Run(os.Args); err != nil { 54 - log.Fatal(err) 55 - } 56 - } 57 - 58 - type RepoItem struct { 59 - Cid cid.Cid 60 - Path string 61 - Body interface{} 62 - } 63 - 64 - type RepoSnapshot struct { 65 - Root cid.Cid 66 - File string 67 - Size int 68 - Items []RepoItem 69 - } 70 - 71 - var InspectCommand = &cli.Command{ 72 - Name: "inspect", 73 - Aliases: []string{"i"}, 74 - Usage: "Inspect repo(s)", 75 - Action: func(ctx *cli.Context) error { 76 - 77 - walk := func(ss RepoSnapshot, err error) { 78 - if ss.Root.String() == "b" { 79 - return 80 - } 81 - if ss.File == "" { 82 - ss.File = "(pipe)" 83 - } 84 - yellow := color.New(color.FgYellow).SprintFunc() 85 - cyan := color.New(color.FgCyan).SprintFunc() 86 - fmt.Printf("%v:\n Head: %s\n Size: %s Commits: %v\n\n", yellow(ss.File), cyan(ss.Root.String()), cyan(humanize.Bytes(uint64(ss.Size))), cyan(humanize.Comma(int64(len(ss.Items))))) 87 - } 88 - 89 - stat, _ := os.Stdin.Stat() 90 - if (stat.Mode() & os.ModeCharDevice) == 0 { 91 - // data is being piped to stdin 92 - WalkStream(ctx, os.Stdin, walk) 93 - } else { 94 - //stdin is from a terminal 95 - WalkFiles(ctx, walk) 96 - } 97 - return nil 98 - }, 99 - } 100 - 101 - var ShowCommand = &cli.Command{ 102 - Name: "show", 103 - Aliases: []string{"s"}, 104 - ArgsUsage: "[<target>]", 105 - Usage: "Show repo(s) documents", 106 - Flags: []cli.Flag{ 107 - &cli.StringFlag{ 108 - Name: "type", 109 - Aliases: []string{"t"}, 110 - Usage: "Filter by item type", 111 - Value: "", 112 - }, 113 - &cli.StringFlag{ 114 - Name: "query", 115 - Aliases: []string{"q"}, 116 - Usage: "Query results (jq)", 117 - Value: "", 118 - }, 119 - &cli.StringFlag{ 120 - Name: "query-jmes", 121 - Aliases: []string{"qq"}, 122 - Usage: "Query results (jmespath)", 123 - Value: "", 124 - }, 125 - &cli.BoolFlag{ 126 - Name: "raw", 127 - Usage: "Do not use pretty print (faster)", 128 - Value: false, 129 - }, 130 - }, 131 - Action: func(ctx *cli.Context) error { 132 - //q := ctx.Args().First() 133 - q := ctx.String("query") 134 - var query *gojq.Query 135 - if q != "" { 136 - tq, err := gojq.Parse(q) 137 - if err != nil { 138 - log.Fatalln("gojq parse error:", err) 139 - //return err 140 - } else { 141 - query = tq 142 - } 143 - } 144 - qq := ctx.String("query-jmes") 145 - var queryJmes *jmespath.JMESPath 146 - if qq != "" { 147 - jc, err := jmespath.Compile(qq) 148 - if err != nil { 149 - return err 150 - } 151 - queryJmes = jc 152 - } 153 - 154 - eo, err := exec.Command("defaults", "read", "-g", "AppleInterfaceStyle").Output() 155 - if err != nil { 156 - log.Fatal(err) 157 - } 158 - style := "paraiso-dark" 159 - if strings.Index(string(eo), "Dark") != 0 { 160 - style = "paraiso-light" 161 - } 162 - hg := highlight(style) 163 - 164 - walk := func(ss RepoSnapshot, err error) { 165 - 166 - for _, e := range ss.Items { 167 - tf := ctx.String("type") 168 - if tf != "" { 169 - if m := regexp.MustCompile(tf).Match([]byte(e.Path)); !m { 170 - continue 171 - } 172 - } 173 - var out interface{} 174 - if q != "" || qq != "" { 175 - json, err := jsoniter.Marshal(e.Body) 176 - if err != nil { 177 - log.Fatal("jsoniter error:", err) 178 - continue 179 - } 180 - var pv interface{} 181 - err = jsoniter.Unmarshal(json, &pv) 182 - if err != nil { 183 - log.Fatal("jsoniter error:", err) 184 - continue 185 - } 186 - if q != "" { 187 - iter := query.Run(interface{}(pv)) 188 - for { 189 - v, ok := iter.Next() 190 - if !ok { 191 - break 192 - } 193 - if err, ok := v.(error); ok { 194 - log.Fatalln("gojq iter error:", err) 195 - continue 196 - } 197 - if v == nil { 198 - continue 199 - } 200 - out = v 201 - } 202 - } 203 - if qq != "" { 204 - r, err := queryJmes.Search(pv) 205 - if err != nil { 206 - log.Fatalln("jmespath error:", err) 207 - } 208 - out = r 209 - } 210 - } else { 211 - out = e.Body 212 - } 213 - stat, _ := os.Stdout.Stat() 214 - if ((stat.Mode() & os.ModeCharDevice) != 0) && ctx.Bool("raw") == false { 215 - prettyPrint(out, hg) 216 - } else { 217 - print(out) 218 - } 219 - } 220 - } 221 - 222 - stat, _ := os.Stdin.Stat() 223 - if (stat.Mode() & os.ModeCharDevice) == 0 { 224 - // data is being piped to stdin 225 - WalkStream(ctx, os.Stdin, walk) 226 - } else { 227 - //stdin is from a terminal 228 - WalkFiles(ctx, walk) 229 - } 230 - return nil 231 - }, 232 - } 233 - 234 - func WalkFiles(ctx *cli.Context, cb func(RepoSnapshot, error)) error { 235 - wd := ctx.String("C") 236 - if wd != "." { 237 - syscall.Chdir(wd) 238 - } 239 - 240 - dir := ctx.Args().First() 241 - if dir == "" { 242 - dir = "." 243 - } 244 - info, err := os.Stat(dir) 245 - if err != nil { 246 - fmt.Println(err) 247 - return err 248 - } 249 - if !info.IsDir() { 250 - cb(Load(dir)) 251 - return nil 252 - } 253 - err = filepath.Walk(dir, 254 - func(fn string, info os.FileInfo, err error) error { 255 - if err != nil { 256 - return err 257 - } 258 - cb(Load(fn)) 259 - return nil 260 - }) 261 - if err != nil { 262 - log.Println(err) 263 - } 264 - return nil 265 - } 266 - 267 - func WalkStream(ctx *cli.Context, input io.Reader, cb func(RepoSnapshot, error)) error { 268 - ss, err := LoadFromStream(input) 269 - if err != nil { 270 - log.Println("Cannot load from stream:", err) 271 - return nil 272 - } 273 - cb(ss, nil) 274 - return nil 275 - } 276 - 277 - func Load(fn string) (RepoSnapshot, error) { 278 - var ss RepoSnapshot 279 - var err error 280 - if strings.HasSuffix(fn, ".car.zst") { 281 - ss, err = LoadCompressed(fn) 282 - } else if strings.HasSuffix(fn, ".car") { 283 - ss, err = LoadRaw(fn) 284 - } 285 - if err != nil { 286 - log.Fatal("Cannot load: ", fn) 287 - return ss, errors.New("Cannot load") 288 - } 289 - ss.File = fn 290 - return ss, nil 291 - } 292 - 293 - func LoadRaw(fn string) (RepoSnapshot, error) { 294 - dat, err := os.Open(fn) 295 - defer dat.Close() 296 - 297 - if err != nil { 298 - return RepoSnapshot{}, err 299 - } 300 - return LoadFromStream(dat) 301 - } 302 - 303 - func LoadCompressed(fn string) (RepoSnapshot, error) { 304 - dat, err := os.Open(fn) 305 - defer dat.Close() 306 - 307 - if err != nil { 308 - return RepoSnapshot{}, err 309 - } 310 - decoder, _ := zstd.NewReader(dat) 311 - return LoadFromStream(decoder) 312 - } 313 - 314 - func LoadFromStream(input io.Reader) (RepoSnapshot, error) { 315 - rctx := context.TODO() 316 - ss := RepoSnapshot{} 317 - 318 - buf := new(bytes.Buffer) 319 - size, err := io.Copy(buf, input) 320 - if err != nil { 321 - log.Fatal(err) 322 - } 323 - ss.Size = int(size) 324 - 325 - r, err := repo.ReadRepoFromCar(rctx, buf) 326 - if err != nil { 327 - return ss, err 328 - } 329 - ss.Root = r.Head() 330 - var out []RepoItem 331 - if err := r.ForEach(rctx, "", func(k string, v cid.Cid) error { 332 - _, rec, err := r.GetRecord(rctx, k) 333 - if err != nil { 334 - log.Println("Cannot get record:", v.String()) 335 - } 336 - out = append(out, RepoItem{Cid: v, Path: k, Body: rec}) 337 - ss.Items = out 338 - return nil 339 - }); err != nil { 340 - return ss, err 341 - } 342 - return ss, nil 343 - } 344 - 345 - func print(v interface{}) error { 346 - json, err := jsoniter.Marshal(v) 347 - if err != nil { 348 - log.Fatal(err) 349 - } 350 - s := string(json) 351 - if s == "null" { 352 - return nil 353 - } 354 - fmt.Println(string(json)) 355 - return nil 356 - } 357 - 358 - func prettyPrint(v interface{}, hg func(io.Writer, string)) error { 359 - json, err := jsoniter.MarshalIndent(v, "", " ") 360 - if err != nil { 361 - log.Fatal(err) 362 - } 363 - s := string(json) 364 - if s == "null" { 365 - return nil 366 - } 367 - hg(os.Stdout, s+"\n") 368 - return nil 369 - } 370 - 371 - func highlight(style string) func(w io.Writer, source string) { 372 - // Determine lexer. 373 - l := lexers.Get("json") 374 - l = chroma.Coalesce(l) 375 - 376 - // Determine formatter. 377 - f := formatters.Get("terminal") 378 - if f == nil { 379 - f = formatters.Fallback 380 - } 381 - // Determine style. 382 - s := styles.Get(style) 383 - if s == nil { 384 - s = styles.Fallback 385 - } 386 - return func(w io.Writer, source string) { 387 - it, _ := l.Tokenise(nil, source) 388 - f.Format(w, s, it) 389 - } 390 - }
+64
cmd/root.go
··· 1 + package cmd 2 + 3 + import ( 4 + "fmt" 5 + 6 + "github.com/atscan/atr/util/version" 7 + "github.com/spf13/cobra" 8 + ) 9 + 10 + var ( 11 + // Used for flags. 12 + //cfgFile string 13 + workingDir string 14 + 15 + rootCmd = &cobra.Command{ 16 + Use: "atr", 17 + Short: "AT Protocol IPLD-CAR Repository toolkit", 18 + //Long: `.`, 19 + } 20 + ) 21 + 22 + // Execute executes the root command. 23 + func Execute() error { 24 + return rootCmd.Execute() 25 + } 26 + 27 + func init() { 28 + //cobra.OnInitialize(initConfig) 29 + 30 + rootCmd.PersistentFlags().StringVarP(&workingDir, "working-dir", "C", ".", "") 31 + 32 + //rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.cobra.yaml)") 33 + rootCmd.AddCommand(versionCmd) 34 + //rootCmd.AddCommand(ShowCmd) 35 + } 36 + 37 + /*func initConfig() { 38 + if cfgFile != "" { 39 + // Use config file from the flag. 40 + //viper.SetConfigFile(cfgFile) 41 + } else { 42 + // Find home directory. 43 + //home, err := os.UserHomeDir() 44 + //cobra.CheckErr(err) 45 + 46 + viper.AddConfigPath(home) 47 + viper.SetConfigType("yaml") 48 + viper.SetConfigName(".atr") 49 + } 50 + 51 + //viper.AutomaticEnv() 52 + 53 + if err := viper.ReadInConfig(); err == nil { 54 + fmt.Println("Using config file:", viper.ConfigFileUsed()) 55 + } 56 + }*/ 57 + 58 + var versionCmd = &cobra.Command{ 59 + Use: "version", 60 + Short: "Print the version number", 61 + Run: func(cmd *cobra.Command, args []string) { 62 + fmt.Println(version.Version("")) 63 + }, 64 + }
+1
engine/file.go
··· 1 + package engine
+83
engine/io.go
··· 1 + package engine 2 + 3 + import ( 4 + "bytes" 5 + "context" 6 + "errors" 7 + "io" 8 + "log" 9 + "os" 10 + "strings" 11 + 12 + "github.com/atscan/atr/repo" 13 + "github.com/ipfs/go-cid" 14 + "github.com/klauspost/compress/zstd" 15 + ) 16 + 17 + func Load(fn string) (repo.RepoSnapshot, error) { 18 + var ss repo.RepoSnapshot 19 + var err error 20 + if strings.HasSuffix(fn, ".car.zst") { 21 + ss, err = LoadCompressed(fn) 22 + } else if strings.HasSuffix(fn, ".car") { 23 + ss, err = LoadRaw(fn) 24 + } 25 + if err != nil { 26 + log.Fatal("Cannot load: ", fn) 27 + return ss, errors.New("Cannot load") 28 + } 29 + ss.File = fn 30 + return ss, nil 31 + } 32 + 33 + func LoadRaw(fn string) (repo.RepoSnapshot, error) { 34 + dat, err := os.Open(fn) 35 + defer dat.Close() 36 + 37 + if err != nil { 38 + return repo.RepoSnapshot{}, err 39 + } 40 + return LoadFromStream(dat) 41 + } 42 + 43 + func LoadCompressed(fn string) (repo.RepoSnapshot, error) { 44 + dat, err := os.Open(fn) 45 + defer dat.Close() 46 + 47 + if err != nil { 48 + return repo.RepoSnapshot{}, err 49 + } 50 + decoder, _ := zstd.NewReader(dat) 51 + return LoadFromStream(decoder) 52 + } 53 + 54 + func LoadFromStream(input io.Reader) (repo.RepoSnapshot, error) { 55 + rctx := context.TODO() 56 + ss := repo.RepoSnapshot{} 57 + 58 + buf := new(bytes.Buffer) 59 + size, err := io.Copy(buf, input) 60 + if err != nil { 61 + log.Fatal(err) 62 + } 63 + ss.Size = int(size) 64 + 65 + r, err := repo.ReadRepoFromCar(rctx, buf) 66 + if err != nil { 67 + return ss, err 68 + } 69 + ss.Root = r.Head() 70 + var out []repo.RepoItem 71 + if err := r.ForEach(rctx, "", func(k string, v cid.Cid) error { 72 + _, rec, err := r.GetRecord(rctx, k) 73 + if err != nil { 74 + log.Println("Cannot get record:", v.String()) 75 + } 76 + out = append(out, repo.RepoItem{Cid: v, Path: k, Body: rec}) 77 + ss.Items = out 78 + return nil 79 + }); err != nil { 80 + return ss, err 81 + } 82 + return ss, nil 83 + }
+59
engine/walk.go
··· 1 + package engine 2 + 3 + import ( 4 + "fmt" 5 + "io" 6 + "log" 7 + "os" 8 + "path/filepath" 9 + "syscall" 10 + 11 + "github.com/atscan/atr/cli" 12 + "github.com/atscan/atr/repo" 13 + ) 14 + 15 + func WalkFiles(ctx *cli.Context, cb func(repo.RepoSnapshot, error)) error { 16 + wd := ctx.WorkingDir 17 + if wd != "." { 18 + syscall.Chdir(wd) 19 + } 20 + 21 + dir := "." 22 + if len(ctx.Args) > 0 { 23 + dir = ctx.Args[0] 24 + } 25 + if dir == "" { 26 + dir = "." 27 + } 28 + info, err := os.Stat(dir) 29 + if err != nil { 30 + fmt.Println(err) 31 + return err 32 + } 33 + if !info.IsDir() { 34 + cb(Load(dir)) 35 + return nil 36 + } 37 + err = filepath.Walk(dir, 38 + func(fn string, info os.FileInfo, err error) error { 39 + if err != nil { 40 + return err 41 + } 42 + cb(Load(fn)) 43 + return nil 44 + }) 45 + if err != nil { 46 + log.Println(err) 47 + } 48 + return nil 49 + } 50 + 51 + func WalkStream(ctx *cli.Context, input io.Reader, cb func(repo.RepoSnapshot, error)) error { 52 + ss, err := LoadFromStream(input) 53 + if err != nil { 54 + log.Println("Cannot load from stream:", err) 55 + return nil 56 + } 57 + cb(ss, nil) 58 + return nil 59 + }
+5 -7
go.mod
··· 17 17 github.com/jmespath/go-jmespath v0.4.0 18 18 github.com/json-iterator/go v1.1.12 19 19 github.com/klauspost/compress v1.16.7 20 - github.com/urfave/cli/v2 v2.25.7 20 + github.com/spf13/cobra v1.7.0 21 21 github.com/whyrusleeping/cbor-gen v0.0.0-20230331140348-1f892b517e70 22 22 golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 23 23 ) 24 24 25 25 require ( 26 - github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect 27 26 github.com/dlclark/regexp2 v1.4.0 // indirect 28 27 github.com/gogo/protobuf v1.3.2 // indirect 29 28 github.com/google/uuid v1.3.0 // indirect 30 29 github.com/hashicorp/go-cleanhttp v0.5.2 // indirect 30 + github.com/hashicorp/go-hclog v1.2.0 // indirect 31 31 github.com/hashicorp/go-retryablehttp v0.7.2 // indirect 32 32 github.com/hashicorp/golang-lru v0.5.4 // indirect 33 33 github.com/inconshreveable/mousetrap v1.1.0 // indirect ··· 46 46 github.com/mattn/go-colorable v0.1.13 // indirect 47 47 github.com/mattn/go-isatty v0.0.19 // indirect 48 48 github.com/minio/sha256-simd v1.0.0 // indirect 49 - github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 // indirect 49 + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect 50 50 github.com/modern-go/reflect2 v1.0.2 // indirect 51 51 github.com/mr-tron/base58 v1.2.0 // indirect 52 52 github.com/multiformats/go-base32 v0.1.0 // indirect ··· 57 57 github.com/multiformats/go-varint v0.0.7 // indirect 58 58 github.com/opentracing/opentracing-go v1.2.0 // indirect 59 59 github.com/petar/GoLLRB v0.0.0-20210522233825-ae3b015fd3e9 // indirect 60 + github.com/pkg/errors v0.9.1 // indirect 60 61 github.com/polydawn/refmt v0.89.1-0.20221221234430-40501e09de1f // indirect 61 - github.com/russross/blackfriday/v2 v2.1.0 // indirect 62 62 github.com/spaolacci/murmur3 v1.1.0 // indirect 63 - github.com/spf13/cobra v1.7.0 // indirect 64 63 github.com/spf13/pflag v1.0.5 // indirect 65 64 github.com/whyrusleeping/cbor v0.0.0-20171005072247-63513f603b11 // indirect 66 65 github.com/x448/float16 v0.8.4 // indirect 67 - github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect 68 66 go.uber.org/atomic v1.10.0 // indirect 69 67 go.uber.org/multierr v1.11.0 // indirect 70 68 go.uber.org/zap v1.24.0 // indirect 71 - golang.org/x/crypto v0.7.0 // indirect 69 + golang.org/x/crypto v0.9.0 // indirect 72 70 golang.org/x/exp v0.0.0-20230321023759-10a507213a29 // indirect 73 71 golang.org/x/sys v0.10.0 // indirect 74 72 lukechampine.com/blake3 v1.1.7 // indirect
+14 -11
go.sum
··· 6 6 github.com/bluesky-social/indigo v0.0.0-20230714174244-57d75d8cfc65 h1:0z5rF7oA9eqqoAFoiHTfioBK8U4hzMmyGMoajEqJVFE= 7 7 github.com/bluesky-social/indigo v0.0.0-20230714174244-57d75d8cfc65/go.mod h1:oDI5NiD0XzShv5VITWyUJNP3pSh4prTDEzhKbkdKORA= 8 8 github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= 9 - github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w= 10 9 github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= 11 10 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 12 11 github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= ··· 15 14 github.com/dlclark/regexp2 v1.4.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc= 16 15 github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= 17 16 github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= 17 + github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= 18 18 github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs= 19 19 github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw= 20 20 github.com/frankban/quicktest v1.14.4 h1:g2rn0vABPOOXmZUj+vbmUp0lPoXEMuhTpIluN0XL9UY= ··· 34 34 github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= 35 35 github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= 36 36 github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= 37 - github.com/hashicorp/go-hclog v0.9.2 h1:CG6TE5H9/JXsFWJCfoIVpKFIkFe6ysEuHirp4DxCsHI= 38 37 github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= 38 + github.com/hashicorp/go-hclog v1.2.0 h1:La19f8d7WIlm4ogzNHB0JGqs5AUDAZ2UfCY4sJXcJdM= 39 + github.com/hashicorp/go-hclog v1.2.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= 39 40 github.com/hashicorp/go-retryablehttp v0.7.2 h1:AcYqCvkpalPnPF2pn0KamgwamS42TqUDDYFRKq/RAd0= 40 41 github.com/hashicorp/go-retryablehttp v0.7.2/go.mod h1:Jy/gPYAdjqffZ/yFGCFV2doI5wjtH1ewM9u8iYVjtX8= 41 42 github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= ··· 112 113 github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= 113 114 github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= 114 115 github.com/libp2p/go-buffer-pool v0.1.0 h1:oK4mSFcQz7cTQIfqbe4MIj9gLW+mnanjyFtc6cdF0Y8= 116 + github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= 115 117 github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= 116 118 github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= 119 + github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= 120 + github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84= 117 121 github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= 118 122 github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= 119 123 github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= ··· 122 126 github.com/minio/sha256-simd v0.1.1-0.20190913151208-6de447530771/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM= 123 127 github.com/minio/sha256-simd v1.0.0 h1:v1ta+49hkWZyvaKwrQB8elexRqm6Y0aMLjCNsrYxo6g= 124 128 github.com/minio/sha256-simd v1.0.0/go.mod h1:OuYzVNI5vcoYIAmbIvHPl3N3jUzVedXbKy5RFepssQM= 125 - github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc= 126 129 github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= 130 + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= 131 + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= 127 132 github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= 128 133 github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= 129 134 github.com/mr-tron/base58 v1.1.0/go.mod h1:xcD2VGqlgYjBdcBLw+TuYLr8afG+Hj8g2eTVqeSzSU8= ··· 152 157 github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc= 153 158 github.com/petar/GoLLRB v0.0.0-20210522233825-ae3b015fd3e9 h1:1/WtZae0yGtPq+TI6+Tv1WTxkukpXeMlviSxvL7SRgk= 154 159 github.com/petar/GoLLRB v0.0.0-20210522233825-ae3b015fd3e9/go.mod h1:x3N5drFsm2uilKKuuYo6LdyD8vZAW55sH/9w+pbo1sw= 155 - github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= 156 160 github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 161 + github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= 162 + github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 157 163 github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 158 164 github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 159 165 github.com/polydawn/refmt v0.89.1-0.20221221234430-40501e09de1f h1:VXTQfuJj9vKR4TCkEuWIckKvdHFeJH/huIFJ9/cXOB0= ··· 161 167 github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= 162 168 github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= 163 169 github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= 164 - github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= 165 170 github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= 166 171 github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= 167 172 github.com/smartystreets/assertions v1.2.0 h1:42S6lae5dvLc7BrLu/0ugRtcFVjoJNMC/N3yZFZkDFs= ··· 181 186 github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 182 187 github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= 183 188 github.com/urfave/cli v1.22.10/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= 184 - github.com/urfave/cli/v2 v2.25.7 h1:VAzn5oq403l5pHjc4OhD54+XGO9cdKVL/7lDjF+iKUs= 185 - github.com/urfave/cli/v2 v2.25.7/go.mod h1:8qnjx1vcq5s2/wpsqoZFndg2CE5tNFyrTvS6SinrnYQ= 186 189 github.com/warpfork/go-testmark v0.11.0 h1:J6LnV8KpceDvo7spaNU4+DauH2n1x+6RaO2rJrmpQ9U= 187 190 github.com/warpfork/go-wish v0.0.0-20220906213052-39a1cc7a02d0 h1:GDDkbFiaK8jsSDJfjId/PEGEShv6ugrt4kYsC5UIDaQ= 188 191 github.com/warpfork/go-wish v0.0.0-20220906213052-39a1cc7a02d0/go.mod h1:x6AKhvSSexNrVSrViXSHUEbICjmGXhtgABaHIySUSGw= ··· 193 196 github.com/whyrusleeping/chunker v0.0.0-20181014151217-fe64bd25879f h1:jQa4QT2UP9WYv2nzyawpKMOCl+Z/jW7djv2/J50lj9E= 194 197 github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= 195 198 github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= 196 - github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU= 197 - github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8= 198 199 github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= 199 200 github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= 200 201 github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= ··· 218 219 golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 219 220 golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 220 221 golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= 221 - golang.org/x/crypto v0.7.0 h1:AvwMYaRytfdeVt3u6mLaxYtErKYjxA2OXjJ1HHq6t3A= 222 - golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= 222 + golang.org/x/crypto v0.9.0 h1:LF6fAI+IutBocDJ2OT0Q1g8plpYljMZ4+lty+dsqw3g= 223 + golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0= 223 224 golang.org/x/exp v0.0.0-20230321023759-10a507213a29 h1:ooxPy7fPvB4kwsA2h+iBNHkAbp/4JxTSwCmvdjEYmug= 224 225 golang.org/x/exp v0.0.0-20230321023759-10a507213a29/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc= 225 226 golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= ··· 238 239 golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 239 240 golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 240 241 golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 242 + golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 241 243 golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 244 + golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 242 245 golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 243 246 golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 244 247 golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+16
repo/ext.go
··· 1 + package repo 2 + 3 + import cid "github.com/ipfs/go-cid" 4 + 5 + type RepoItem struct { 6 + Cid cid.Cid 7 + Path string 8 + Body interface{} 9 + } 10 + 11 + type RepoSnapshot struct { 12 + Root cid.Cid 13 + File string 14 + Size int 15 + Items []RepoItem 16 + }