AT Protocol IPLD-CAR Repository toolkit (CLI)

new log cmd, update inspect

tree 5b22b667 1109c58b

+59 -3
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" ··· 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)", ··· 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 Items: %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()
··· 1 package cmd 2 3 import ( 4 + "context" 5 + "encoding/hex" 6 "fmt" 7 "os" 8 + "sort" 9 + "strings" 10 11 "github.com/atscan/atr/cli" 12 "github.com/atscan/atr/engine" ··· 17 ) 18 19 func init() { 20 + rootCmd.AddCommand(LsCmd) 21 } 22 23 + var LsCmd = &cobra.Command{ 24 Use: "inspect", 25 Aliases: []string{"i"}, 26 Short: "Inspect repo(s)", ··· 40 } 41 yellow := color.New(color.FgYellow).SprintFunc() 42 cyan := color.New(color.FgCyan).SprintFunc() 43 + boldCyan := color.New(color.FgCyan, color.Bold).SprintFunc() 44 + green := color.New(color.FgGreen).SprintFunc() 45 + 46 + fmt.Printf("%v:\n", yellow(ss.File)) 47 + fmt.Printf(" DID: %s Repo Version: %v\n", boldCyan(ss.Repo.SignedCommit().Did), cyan(ss.Repo.SignedCommit().Version)) 48 + fmt.Printf(" Head: %s\n", cyan(ss.Root.String())) 49 + fmt.Printf(" Sig: %s\n", cyan(hex.EncodeToString(ss.Repo.SignedCommit().Sig))) 50 + 51 + stats, _ := ss.GetCollectionStats("") 52 + keys := make([]string, 0, len(stats)) 53 + total := 0 54 + for k := range stats { 55 + keys = append(keys, k) 56 + total += stats[k] 57 + } 58 + sort.Strings(keys) 59 + cp, _ := ss.Repo.GetCommitsPath(-1) 60 + _, v, _ := ss.Repo.GetRecord(context.TODO(), "app.bsky.actor.profile/self") 61 + 62 + dn := v["displayName"] 63 + if dn != nil { 64 + dn = boldCyan(dn) 65 + } else { 66 + dn = "(empty)" 67 + } 68 + desc := v["description"] 69 + if desc != nil { 70 + desc = cyan(strings.Replace(desc.(string), "\n", "\n ", -1)) 71 + } else { 72 + desc = "(empty)" 73 + } 74 + 75 + fmt.Printf(" Size: %s Blocks: %v Commits: %v Objects: %v\n", cyan(humanize.Bytes(uint64(ss.Size))), cyan(humanize.Comma(int64(ss.Repo.Blocks))), cyan(humanize.Comma(int64(len(cp)))), cyan(humanize.Comma(int64(total)))) 76 + fmt.Printf(" Profile:\n") 77 + fmt.Printf(" Display Name: %v\n", dn) 78 + fmt.Printf(" Description: %v\n", desc) 79 + 80 + fmt.Printf(" Collections:\n") 81 + for _, k := range keys { 82 + fmt.Printf(" %s: %v\n", green(k), cyan(humanize.Comma(int64(stats[k])))) 83 + } 84 + fmt.Printf(" Last 5 commits:\n") 85 + for i, cid := range cp { 86 + fmt.Printf(" %v\n", cyan(cid.String())) 87 + if i >= 5 { 88 + break 89 + } 90 + } 91 + if len(cp) > 5 { 92 + fmt.Printf(" %s\n", cyan("...")) 93 + } 94 + 95 + fmt.Println("") 96 } 97 98 stat, _ := os.Stdin.Stat()
+72
cmd/atr-log.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/fatih/color" 11 + "github.com/spf13/cobra" 12 + ) 13 + 14 + var ( 15 + LogRaw bool 16 + ) 17 + 18 + func init() { 19 + rootCmd.AddCommand(LogCmd) 20 + LogCmd.Flags().BoolVar(&LogRaw, "raw", false, "Do not use colors (faster)") 21 + } 22 + 23 + var LogCmd = &cobra.Command{ 24 + Use: "log [target] [--raw]", 25 + Aliases: []string{"l"}, 26 + Short: "Show commit history (path)", 27 + Long: ``, 28 + Run: func(cmd *cobra.Command, args []string) { 29 + ctx := cli.Context{ 30 + WorkingDir: workingDir, 31 + Args: args, 32 + } 33 + walk := func(ss repo.RepoSnapshot, err error) { 34 + if ss.Root.String() == "b" { 35 + return 36 + } 37 + cp, _ := ss.Repo.GetCommitsPath(-1) 38 + //cp = util.ReverseCidSlice(cp) 39 + 40 + if LogRaw { 41 + for _, cid := range cp { 42 + fmt.Printf("%v\n", cid.String()) 43 + } 44 + } else { 45 + yellow := color.New(color.FgYellow).SprintFunc() 46 + cyan := color.New(color.FgCyan).SprintFunc() 47 + green := color.New(color.FgGreen).SprintFunc() 48 + 49 + fmt.Printf("[%v]\n", yellow(ss.File)) 50 + for i, cid := range cp { 51 + stats, _ := ss.GetCollectionStats(cid.String()) 52 + 53 + sum := 0 54 + for _, v := range stats { 55 + sum += v 56 + } 57 + fmt.Printf("%v [#%v] %v objects\n", cyan(cid.String()), len(cp)-i, green(sum)) 58 + } 59 + } 60 + //fmt.Printf("\n") 61 + } 62 + 63 + stat, _ := os.Stdin.Stat() 64 + if (stat.Mode() & os.ModeCharDevice) == 0 { 65 + // data is being piped to stdin 66 + engine.WalkStream(&ctx, os.Stdin, walk) 67 + } else { 68 + //stdin is from a terminal 69 + engine.WalkFiles(&ctx, walk) 70 + } 71 + }, 72 + }
+11
cmd/atr-show.go
··· 22 QueryJmes string 23 Type string 24 Raw bool 25 ) 26 27 func init() { 28 rootCmd.AddCommand(ShowCmd) 29 ShowCmd.Flags().StringVarP(&Type, "type", "t", "", "Filter by item type") 30 ShowCmd.Flags().StringVarP(&Query, "query", "q", "", "Query results (jq)") 31 ShowCmd.Flags().StringVarP(&QueryJmes, "query-jmes", "x", "", "Query results (jmespath)") ··· 78 hg := cli.Highlight(style) 79 80 walk := func(ss repo.RepoSnapshot, err error) { 81 82 for _, e := range ss.Items { 83 tf := Type
··· 22 QueryJmes string 23 Type string 24 Raw bool 25 + Root string 26 + GoBack int 27 ) 28 29 func init() { 30 rootCmd.AddCommand(ShowCmd) 31 + ShowCmd.Flags().StringVarP(&Root, "root", "r", "", "Use specific root") 32 + ShowCmd.Flags().IntVarP(&GoBack, "back", "b", 0, "Go back (n) commits") 33 ShowCmd.Flags().StringVarP(&Type, "type", "t", "", "Filter by item type") 34 ShowCmd.Flags().StringVarP(&Query, "query", "q", "", "Query results (jq)") 35 ShowCmd.Flags().StringVarP(&QueryJmes, "query-jmes", "x", "", "Query results (jmespath)") ··· 82 hg := cli.Highlight(style) 83 84 walk := func(ss repo.RepoSnapshot, err error) { 85 + 86 + rr := Root 87 + if GoBack > 0 { 88 + gb, _ := ss.Repo.GetCommitsPath(GoBack) 89 + rr = gb[len(gb)-1].String() 90 + } 91 + ss.LoadItems(rr) 92 93 for _, e := range ss.Items { 94 tf := Type
+12 -14
engine/io.go
··· 10 "strings" 11 12 "github.com/atscan/atr/repo" 13 - "github.com/ipfs/go-cid" 14 "github.com/klauspost/compress/zstd" 15 ) 16 ··· 52 } 53 54 func LoadFromStream(input io.Reader) (repo.RepoSnapshot, error) { 55 rctx := context.TODO() 56 ss := repo.RepoSnapshot{} 57 ··· 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 }
··· 10 "strings" 11 12 "github.com/atscan/atr/repo" 13 "github.com/klauspost/compress/zstd" 14 ) 15 ··· 51 } 52 53 func LoadFromStream(input io.Reader) (repo.RepoSnapshot, error) { 54 + ss, err := LoadRepoFromStream(input) 55 + if err != nil { 56 + return ss, err 57 + } 58 + 59 + ss.Root = ss.Repo.Head() 60 + 61 + return ss, nil 62 + } 63 + 64 + func LoadRepoFromStream(input io.Reader) (repo.RepoSnapshot, error) { 65 rctx := context.TODO() 66 ss := repo.RepoSnapshot{} 67 ··· 76 if err != nil { 77 return ss, err 78 } 79 + ss.Repo = *r 80 return ss, nil 81 }
+2 -2
go.mod
··· 8 github.com/dustin/go-humanize v1.0.1 9 github.com/fatih/color v1.15.0 10 github.com/fxamacker/cbor/v2 v2.4.0 11 github.com/ipfs/go-cid v0.4.1 12 github.com/ipfs/go-datastore v0.6.0 13 - github.com/ipfs/go-ipfs-blockstore v1.3.0 14 github.com/ipfs/go-ipld-cbor v0.0.7-0.20230126201833-a73d038d90bc 15 github.com/ipld/go-car/v2 v2.10.1 16 github.com/itchyny/gojq v0.12.13 ··· 33 github.com/inconshreveable/mousetrap v1.1.0 // indirect 34 github.com/ipfs/bbloom v0.0.4 // indirect 35 github.com/ipfs/go-block-format v0.1.2 // indirect 36 github.com/ipfs/go-ipfs-ds-help v1.1.0 // indirect 37 github.com/ipfs/go-ipfs-util v0.0.2 // indirect 38 github.com/ipfs/go-ipld-format v0.5.0 // indirect ··· 57 github.com/multiformats/go-varint v0.0.7 // indirect 58 github.com/opentracing/opentracing-go v1.2.0 // indirect 59 github.com/petar/GoLLRB v0.0.0-20210522233825-ae3b015fd3e9 // indirect 60 - github.com/pkg/errors v0.9.1 // indirect 61 github.com/polydawn/refmt v0.89.1-0.20221221234430-40501e09de1f // indirect 62 github.com/spaolacci/murmur3 v1.1.0 // indirect 63 github.com/spf13/pflag v1.0.5 // indirect
··· 8 github.com/dustin/go-humanize v1.0.1 9 github.com/fatih/color v1.15.0 10 github.com/fxamacker/cbor/v2 v2.4.0 11 + github.com/ipfs/boxo v0.8.0 12 github.com/ipfs/go-cid v0.4.1 13 github.com/ipfs/go-datastore v0.6.0 14 github.com/ipfs/go-ipld-cbor v0.0.7-0.20230126201833-a73d038d90bc 15 github.com/ipld/go-car/v2 v2.10.1 16 github.com/itchyny/gojq v0.12.13 ··· 33 github.com/inconshreveable/mousetrap v1.1.0 // indirect 34 github.com/ipfs/bbloom v0.0.4 // indirect 35 github.com/ipfs/go-block-format v0.1.2 // indirect 36 + github.com/ipfs/go-ipfs-blockstore v1.3.0 // indirect 37 github.com/ipfs/go-ipfs-ds-help v1.1.0 // indirect 38 github.com/ipfs/go-ipfs-util v0.0.2 // indirect 39 github.com/ipfs/go-ipld-format v0.5.0 // indirect ··· 58 github.com/multiformats/go-varint v0.0.7 // indirect 59 github.com/opentracing/opentracing-go v1.2.0 // indirect 60 github.com/petar/GoLLRB v0.0.0-20210522233825-ae3b015fd3e9 // indirect 61 github.com/polydawn/refmt v0.89.1-0.20221221234430-40501e09de1f // indirect 62 github.com/spaolacci/murmur3 v1.1.0 // indirect 63 github.com/spf13/pflag v1.0.5 // indirect
+4 -3
go.sum
··· 1 github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= 2 github.com/alecthomas/chroma v0.10.0 h1:7XDcGkCQopCNKjZHfYrNLraA+M7e0fMiJ/Mfikbfjek= 3 github.com/alecthomas/chroma v0.10.0/go.mod h1:jtJATyUxlIORhUOFNA9NZDWGAQ8wpxQQqNSB4rjA/1s= 4 - github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8= 5 github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= 6 github.com/bluesky-social/indigo v0.0.0-20230714174244-57d75d8cfc65 h1:0z5rF7oA9eqqoAFoiHTfioBK8U4hzMmyGMoajEqJVFE= 7 github.com/bluesky-social/indigo v0.0.0-20230714174244-57d75d8cfc65/go.mod h1:oDI5NiD0XzShv5VITWyUJNP3pSh4prTDEzhKbkdKORA= 8 github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= ··· 30 github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 31 github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= 32 github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 33 - github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= 34 github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= 35 github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= 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/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= ··· 45 github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= 46 github.com/ipfs/bbloom v0.0.4 h1:Gi+8EGJ2y5qiD5FbsbpX/TMNcJw8gSqr7eyjHa4Fhvs= 47 github.com/ipfs/bbloom v0.0.4/go.mod h1:cS9YprKXpoZ9lT0n/Mw/a6/aFV6DTjTLYHeA+gyqMG0= 48 github.com/ipfs/go-bitfield v1.1.0 h1:fh7FIo8bSwaJEh6DdTWbCeZ1eqOaOkKFI74SCnsWbGA= 49 github.com/ipfs/go-block-format v0.1.2 h1:GAjkfhVx1f4YTODS6Esrj1wt2HhrtwTnhEr+DyPUaJo= 50 github.com/ipfs/go-block-format v0.1.2/go.mod h1:mACVcrxarQKstUU3Yf/RdwbC4DzPV6++rO2a3d+a/KE= ··· 159 github.com/petar/GoLLRB v0.0.0-20210522233825-ae3b015fd3e9/go.mod h1:x3N5drFsm2uilKKuuYo6LdyD8vZAW55sH/9w+pbo1sw= 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= 163 github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 164 github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 165 github.com/polydawn/refmt v0.89.1-0.20221221234430-40501e09de1f h1:VXTQfuJj9vKR4TCkEuWIckKvdHFeJH/huIFJ9/cXOB0=
··· 1 github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= 2 github.com/alecthomas/chroma v0.10.0 h1:7XDcGkCQopCNKjZHfYrNLraA+M7e0fMiJ/Mfikbfjek= 3 github.com/alecthomas/chroma v0.10.0/go.mod h1:jtJATyUxlIORhUOFNA9NZDWGAQ8wpxQQqNSB4rjA/1s= 4 github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= 5 + github.com/benbjohnson/clock v1.3.0 h1:ip6w0uFQkncKQ979AypyG0ER7mqUSBdKLOgAle/AT8A= 6 github.com/bluesky-social/indigo v0.0.0-20230714174244-57d75d8cfc65 h1:0z5rF7oA9eqqoAFoiHTfioBK8U4hzMmyGMoajEqJVFE= 7 github.com/bluesky-social/indigo v0.0.0-20230714174244-57d75d8cfc65/go.mod h1:oDI5NiD0XzShv5VITWyUJNP3pSh4prTDEzhKbkdKORA= 8 github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= ··· 30 github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 31 github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= 32 github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 33 github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= 34 + github.com/gopherjs/gopherjs v0.0.0-20190430165422-3e4dfb77656c h1:7lF+Vz0LqiRidnzC1Oq86fpX1q/iEv2KJdrCtttYjT4= 35 github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= 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/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= ··· 45 github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= 46 github.com/ipfs/bbloom v0.0.4 h1:Gi+8EGJ2y5qiD5FbsbpX/TMNcJw8gSqr7eyjHa4Fhvs= 47 github.com/ipfs/bbloom v0.0.4/go.mod h1:cS9YprKXpoZ9lT0n/Mw/a6/aFV6DTjTLYHeA+gyqMG0= 48 + github.com/ipfs/boxo v0.8.0 h1:UdjAJmHzQHo/j3g3b1bAcAXCj/GM6iTwvSlBDvPBNBs= 49 + github.com/ipfs/boxo v0.8.0/go.mod h1:RIsi4CnTyQ7AUsNn5gXljJYZlQrHBMnJp94p73liFiA= 50 github.com/ipfs/go-bitfield v1.1.0 h1:fh7FIo8bSwaJEh6DdTWbCeZ1eqOaOkKFI74SCnsWbGA= 51 github.com/ipfs/go-block-format v0.1.2 h1:GAjkfhVx1f4YTODS6Esrj1wt2HhrtwTnhEr+DyPUaJo= 52 github.com/ipfs/go-block-format v0.1.2/go.mod h1:mACVcrxarQKstUU3Yf/RdwbC4DzPV6++rO2a3d+a/KE= ··· 161 github.com/petar/GoLLRB v0.0.0-20210522233825-ae3b015fd3e9/go.mod h1:x3N5drFsm2uilKKuuYo6LdyD8vZAW55sH/9w+pbo1sw= 162 github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 163 github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= 164 github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 165 github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 166 github.com/polydawn/refmt v0.89.1-0.20221221234430-40501e09de1f h1:VXTQfuJj9vKR4TCkEuWIckKvdHFeJH/huIFJ9/cXOB0=
-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 - }
···
+61 -12
repo/repo.go
··· 9 10 "github.com/bluesky-social/indigo/mst" 11 "github.com/bluesky-social/indigo/util" 12 "github.com/ipfs/go-cid" 13 "github.com/ipfs/go-datastore" 14 - blockstore "github.com/ipfs/go-ipfs-blockstore" 15 cbor "github.com/ipfs/go-ipld-cbor" 16 "github.com/ipld/go-car/v2" 17 ) ··· 35 } 36 37 type Repo struct { 38 sc SignedCommit 39 cst cbor.IpldStore 40 bs blockstore.Blockstore ··· 67 return buf.Bytes(), nil 68 }*/ 69 70 - func IngestRepo(ctx context.Context, bs blockstore.Blockstore, r io.Reader) (cid.Cid, error) { 71 br, err := car.NewBlockReader(r) 72 if err != nil { 73 - return cid.Undef, err 74 } 75 76 for { 77 blk, err := br.Next() 78 if err != nil { 79 if err == io.EOF { 80 break 81 } 82 - return cid.Undef, err 83 } 84 85 if err := bs.Put(ctx, blk); err != nil { 86 - return cid.Undef, err 87 } 88 } 89 90 - return br.Roots[0], nil 91 } 92 93 func ReadRepoFromCar(ctx context.Context, r io.Reader) (*Repo, error) { 94 bs := blockstore.NewBlockstore(datastore.NewMapDatastore()) 95 - root, err := IngestRepo(ctx, bs, r) 96 if err != nil { 97 return nil, err 98 } 99 100 - return OpenRepo(ctx, bs, root, false) 101 } 102 103 - func OpenRepo(ctx context.Context, bs blockstore.Blockstore, root cid.Cid, fullRepo bool) (*Repo, error) { 104 cst := util.CborStore(bs) 105 106 var sc SignedCommit ··· 117 bs: bs, 118 cst: cst, 119 repoCid: root, 120 }, nil 121 } 122 123 func (r *Repo) Head() cid.Cid { 124 return r.repoCid 125 } 126 127 func (r *Repo) getMst(ctx context.Context) (*mst.MerkleSearchTree, error) { 128 if r.mst != nil { 129 return r.mst, nil ··· 134 return t, nil 135 } 136 137 var ErrDoneIterating = fmt.Errorf("done iterating") 138 139 func (r *Repo) ForEach(ctx context.Context, prefix string, cb func(k string, v cid.Cid) error) error { 140 - t := mst.LoadMST(r.cst, r.sc.Data) 141 142 if err := t.WalkLeavesFrom(ctx, prefix, cb); err != nil { 143 if err != ErrDoneIterating { ··· 148 return nil 149 } 150 151 - func (r *Repo) GetRecord(ctx context.Context, rpath string) (cid.Cid, interface{}, error) { 152 mst, err := r.getMst(ctx) 153 if err != nil { 154 return cid.Undef, nil, fmt.Errorf("getting repo mst: %w", err) ··· 163 if err != nil { 164 return cid.Undef, nil, err 165 } 166 - var v interface{} 167 cbor2.Unmarshal(blk.RawData(), &v) 168 169 return cc, v, nil
··· 9 10 "github.com/bluesky-social/indigo/mst" 11 "github.com/bluesky-social/indigo/util" 12 + blockstore "github.com/ipfs/boxo/blockstore" 13 "github.com/ipfs/go-cid" 14 "github.com/ipfs/go-datastore" 15 cbor "github.com/ipfs/go-ipld-cbor" 16 "github.com/ipld/go-car/v2" 17 ) ··· 35 } 36 37 type Repo struct { 38 + Blocks int 39 + 40 sc SignedCommit 41 cst cbor.IpldStore 42 bs blockstore.Blockstore ··· 69 return buf.Bytes(), nil 70 }*/ 71 72 + func IngestRepo(ctx context.Context, bs blockstore.Blockstore, r io.Reader) (cid.Cid, int, error) { 73 br, err := car.NewBlockReader(r) 74 if err != nil { 75 + return cid.Undef, 0, err 76 } 77 78 + size := 0 79 for { 80 blk, err := br.Next() 81 if err != nil { 82 if err == io.EOF { 83 break 84 } 85 + return cid.Undef, size, err 86 } 87 88 if err := bs.Put(ctx, blk); err != nil { 89 + return cid.Undef, size, err 90 } 91 + size++ 92 } 93 94 + return br.Roots[0], size, nil 95 } 96 97 func ReadRepoFromCar(ctx context.Context, r io.Reader) (*Repo, error) { 98 bs := blockstore.NewBlockstore(datastore.NewMapDatastore()) 99 + root, size, err := IngestRepo(ctx, bs, r) 100 if err != nil { 101 return nil, err 102 } 103 104 + return OpenRepo(ctx, bs, root, size) 105 } 106 107 + func OpenRepo(ctx context.Context, bs blockstore.Blockstore, root cid.Cid, size int) (*Repo, error) { 108 cst := util.CborStore(bs) 109 110 var sc SignedCommit ··· 121 bs: bs, 122 cst: cst, 123 repoCid: root, 124 + Blocks: size, 125 }, nil 126 } 127 128 + func (r *Repo) GetCommitsPath(len int) ([]cid.Cid, error) { 129 + path := []cid.Cid{} 130 + path = append(path, r.repoCid) 131 + if r.sc.Prev != nil { 132 + getParentCommits(r, *r.sc.Prev, &path, len-1) 133 + } 134 + return path, nil 135 + } 136 + 137 + func getParentCommits(r *Repo, c cid.Cid, p *[]cid.Cid, len int) ([]cid.Cid, error) { 138 + var sc SignedCommit 139 + ctx := context.TODO() 140 + if err := r.cst.Get(ctx, c, &sc); err != nil { 141 + return nil, fmt.Errorf("loading root from blockstore: %w", err) 142 + } 143 + *p = append(*p, c) 144 + if len == 0 { 145 + return nil, nil 146 + } else { 147 + len-- 148 + } 149 + if sc.Prev != nil { 150 + return getParentCommits(r, *sc.Prev, p, len) 151 + } 152 + return nil, nil 153 + } 154 + 155 func (r *Repo) Head() cid.Cid { 156 return r.repoCid 157 } 158 159 + func (r *Repo) SignedCommit() SignedCommit { 160 + return r.sc 161 + } 162 + 163 + func (r *Repo) MerkleSearchTree() *mst.MerkleSearchTree { 164 + return r.mst 165 + } 166 + 167 + func (r *Repo) BlockStore() blockstore.Blockstore { 168 + return r.bs 169 + } 170 + 171 func (r *Repo) getMst(ctx context.Context) (*mst.MerkleSearchTree, error) { 172 if r.mst != nil { 173 return r.mst, nil ··· 178 return t, nil 179 } 180 181 + func (r *Repo) MST() *mst.MerkleSearchTree { 182 + mst, _ := r.getMst(context.TODO()) 183 + return mst 184 + } 185 + 186 var ErrDoneIterating = fmt.Errorf("done iterating") 187 188 func (r *Repo) ForEach(ctx context.Context, prefix string, cb func(k string, v cid.Cid) error) error { 189 + t, _ := r.getMst(ctx) 190 191 if err := t.WalkLeavesFrom(ctx, prefix, cb); err != nil { 192 if err != ErrDoneIterating { ··· 197 return nil 198 } 199 200 + func (r *Repo) GetRecord(ctx context.Context, rpath string) (cid.Cid, map[string]interface{}, error) { 201 mst, err := r.getMst(ctx) 202 if err != nil { 203 return cid.Undef, nil, fmt.Errorf("getting repo mst: %w", err) ··· 212 if err != nil { 213 return cid.Undef, nil, err 214 } 215 + var v map[string]interface{} 216 cbor2.Unmarshal(blk.RawData(), &v) 217 218 return cc, v, nil
+84
repo/snapshot.go
···
··· 1 + package repo 2 + 3 + import ( 4 + "context" 5 + "log" 6 + "strings" 7 + 8 + cid "github.com/ipfs/go-cid" 9 + ) 10 + 11 + type RepoItem struct { 12 + Cid cid.Cid 13 + Path string 14 + Body interface{} 15 + } 16 + 17 + type RepoSnapshot struct { 18 + Root cid.Cid 19 + File string 20 + Size int 21 + Items []RepoItem 22 + Repo Repo 23 + } 24 + 25 + func (ss *RepoSnapshot) GetCollectionStats(root string) (map[string]int, error) { 26 + rctx := context.TODO() 27 + 28 + rr := ss.Repo 29 + if root != "" && root != "b" { 30 + cid, err := cid.Parse(root) 31 + if err != nil { 32 + log.Fatalf("cannot parse CID: %s", root) 33 + } 34 + cr, err := OpenRepo(rctx, rr.BlockStore(), cid, 0) 35 + if err != nil { 36 + log.Fatal("cannot open repo") 37 + } 38 + rr = *cr 39 + } 40 + stats := make(map[string]int) 41 + if err := rr.ForEach(rctx, "", func(k string, v cid.Cid) error { 42 + col := strings.Split(k, "/")[0] 43 + _, ok := stats[col] 44 + if !ok { 45 + stats[col] = 0 46 + } 47 + stats[col]++ 48 + return nil 49 + }); err != nil { 50 + return nil, err 51 + } 52 + return stats, nil 53 + } 54 + 55 + func (ss *RepoSnapshot) LoadItems(root string) error { 56 + rctx := context.TODO() 57 + 58 + rr := ss.Repo 59 + if root != "" && root != "b" { 60 + cid, err := cid.Parse(root) 61 + if err != nil { 62 + log.Fatalf("cannot parse CID: %s", root) 63 + } 64 + cr, err := OpenRepo(rctx, rr.BlockStore(), cid, 0) 65 + if err != nil { 66 + log.Fatal("cannot open repo") 67 + } 68 + rr = *cr 69 + } 70 + 71 + var out []RepoItem 72 + if err := rr.ForEach(rctx, "", func(k string, v cid.Cid) error { 73 + _, rec, err := rr.GetRecord(rctx, k) 74 + if err != nil { 75 + log.Println("Cannot get record:", v.String()) 76 + } 77 + out = append(out, RepoItem{Cid: v, Path: k, Body: rec}) 78 + ss.Items = out 79 + return nil 80 + }); err != nil { 81 + return err 82 + } 83 + return nil 84 + }
+10
util/util.go
···
··· 1 + package util 2 + 3 + import "github.com/ipfs/go-cid" 4 + 5 + func ReverseCidSlice(arr []cid.Cid) []cid.Cid { 6 + for i, j := 0, len(arr)-1; i < j; i, j = i+1, j-1 { 7 + arr[i], arr[j] = arr[j], arr[i] 8 + } 9 + return arr 10 + }