+59
-3
cmd/atr-inspect.go
+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
+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
+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
+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
+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
+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
-16
repo/ext.go
+61
-12
repo/repo.go
+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
+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
+
}