go scratch code for atproto

glot: move source files around for easier goat merge

cmd/glot/breaking.go cmd/glot/lex_breaking.go
cmd/glot/check_dns.go cmd/glot/lex_check_dns.go
cmd/glot/codegen.go cmd/glot/lex_codegen.go
cmd/glot/diff.go cmd/glot/lex_diff.go
+163
cmd/glot/lex_util.go
··· 1 + package main 2 + 3 + import ( 4 + "context" 5 + "encoding/json" 6 + "fmt" 7 + "log/slog" 8 + "sort" 9 + "strings" 10 + 11 + "github.com/bluesky-social/indigo/api/agnostic" 12 + "github.com/bluesky-social/indigo/atproto/atclient" 13 + "github.com/bluesky-social/indigo/atproto/identity" 14 + "github.com/bluesky-social/indigo/atproto/lexicon" 15 + "github.com/bluesky-social/indigo/atproto/syntax" 16 + 17 + "github.com/urfave/cli/v3" 18 + ) 19 + 20 + var ( 21 + schemaNSID = syntax.NSID("com.atproto.lexicon.schema") 22 + ) 23 + 24 + func nsidGroup(nsid syntax.NSID) string { 25 + parts := strings.Split(string(nsid), ".") 26 + g := strings.Join(parts[0:len(parts)-1], ".") + "." 27 + return g 28 + } 29 + 30 + // Checks if a string is a valid NSID group pattern, which is a partial NSID ending in '.' or '.*' 31 + func ParseNSIDGroup(raw string) (string, error) { 32 + if strings.HasSuffix(raw, ".*") { 33 + raw = raw[:len(raw)-1] 34 + } 35 + if !strings.HasSuffix(raw, ".") { 36 + return "", fmt.Errorf("not an NSID group pattern") 37 + } 38 + _, err := syntax.ParseNSID(raw + "name") 39 + if err != nil { 40 + return "", fmt.Errorf("not an NSID group pattern") 41 + } 42 + return raw, nil 43 + } 44 + 45 + // helper which runs a comparison function across local and remote schemas, based on 'cmd' configuration 46 + func runComparisons(ctx context.Context, cmd *cli.Command, comp func(ctx context.Context, cmd *cli.Command, nsid syntax.NSID, localJSON, remoteJSON json.RawMessage) error) error { 47 + 48 + // collect all NSID/path mappings 49 + localSchemas, err := collectSchemaJSON(cmd) 50 + if err != nil { 51 + return err 52 + } 53 + remoteSchemas := map[syntax.NSID]json.RawMessage{} 54 + 55 + localGroups := map[string]bool{} 56 + allNSIDMap := map[syntax.NSID]bool{} 57 + for k := range localSchemas { 58 + g := nsidGroup(k) 59 + localGroups[g] = true 60 + allNSIDMap[k] = true 61 + } 62 + 63 + for g := range localGroups { 64 + if err := resolveLexiconGroup(ctx, cmd, g, &remoteSchemas); err != nil { 65 + return err 66 + } 67 + } 68 + 69 + for k := range remoteSchemas { 70 + allNSIDMap[k] = true 71 + } 72 + allNSID := []string{} 73 + for k := range allNSIDMap { 74 + allNSID = append(allNSID, string(k)) 75 + } 76 + sort.Strings(allNSID) 77 + 78 + anyFailures := false 79 + for _, k := range allNSID { 80 + nsid := syntax.NSID(k) 81 + if err := comp(ctx, cmd, nsid, localSchemas[nsid], remoteSchemas[nsid]); err != nil { 82 + if err != ErrLintFailures { 83 + return err 84 + } 85 + anyFailures = true 86 + } 87 + } 88 + 89 + if anyFailures { 90 + return ErrLintFailures 91 + } 92 + return nil 93 + } 94 + 95 + // helper which resolves and fetches all lexicon schemas (as JSON), storing them in provided map 96 + func resolveLexiconGroup(ctx context.Context, cmd *cli.Command, group string, remote *map[syntax.NSID]json.RawMessage) error { 97 + 98 + slog.Debug("resolving schemas for NSID group", "group", group) 99 + 100 + // TODO: netclient support for listing records 101 + dir := identity.BaseDirectory{} 102 + did, err := dir.ResolveNSID(ctx, syntax.NSID(group+"name")) 103 + if err != nil { 104 + // if NSID isn't registered, just skip comparison 105 + slog.Warn("skipping NSID pattern which did not resolve", "group", group) 106 + return nil 107 + } 108 + ident, err := dir.LookupDID(ctx, did) 109 + if err != nil { 110 + return err 111 + } 112 + c := atclient.NewAPIClient(ident.PDSEndpoint()) 113 + 114 + cursor := "" 115 + for { 116 + // collection string, cursor string, limit int64, repo string, reverse bool 117 + resp, err := agnostic.RepoListRecords(ctx, c, schemaNSID.String(), cursor, 100, ident.DID.String(), false) 118 + if err != nil { 119 + return err 120 + } 121 + for _, rec := range resp.Records { 122 + aturi, err := syntax.ParseATURI(rec.Uri) 123 + if err != nil { 124 + return err 125 + } 126 + nsid, err := syntax.ParseNSID(aturi.RecordKey().String()) 127 + if err != nil { 128 + slog.Warn("ignoring invalid schema NSID", "did", ident.DID, "rkey", aturi.RecordKey()) 129 + continue 130 + } 131 + if nsidGroup(nsid) != group { 132 + // ignoring other NSIDs 133 + continue 134 + } 135 + if rec.Value == nil { 136 + return fmt.Errorf("missing record value: %s", nsid) 137 + } 138 + 139 + // parse file to check for errors 140 + // TODO: use json/v2 when available for case-sensitivity 141 + var sf lexicon.SchemaFile 142 + err = json.Unmarshal(*rec.Value, &sf) 143 + if err == nil { 144 + err = sf.FinishParse() 145 + } 146 + if err == nil { 147 + err = sf.CheckSchema() 148 + } 149 + if err != nil { 150 + return fmt.Errorf("invalid lexicon schema record (%s): %w", nsid, err) 151 + } 152 + 153 + (*remote)[nsid] = *rec.Value 154 + 155 + } 156 + if resp.Cursor != nil && *resp.Cursor != "" { 157 + cursor = *resp.Cursor 158 + } else { 159 + break 160 + } 161 + } 162 + return nil 163 + }
cmd/glot/lint.go cmd/glot/lex_lint.go
+4 -4
cmd/glot/new.go cmd/glot/lex_new.go
··· 13 13 "github.com/urfave/cli/v3" 14 14 ) 15 15 16 - //go:embed templates/record.json 16 + //go:embed lexicon-templates/record.json 17 17 var tmplRecord string 18 18 19 - //go:embed templates/query-view.json 19 + //go:embed lexicon-templates/query-view.json 20 20 var tmplQueryView string 21 21 22 - //go:embed templates/query-list.json 22 + //go:embed lexicon-templates/query-list.json 23 23 var tmplQueryList string 24 24 25 - //go:embed templates/procedure.json 25 + //go:embed lexicon-templates/procedure.json 26 26 var tmplProcedure string 27 27 28 28 var cmdNew = &cli.Command{
cmd/glot/publish.go cmd/glot/lex_publish.go
cmd/glot/pull.go cmd/glot/lex_pull.go
cmd/glot/status.go cmd/glot/lex_status.go
cmd/glot/templates/procedure.json cmd/glot/lexicon-templates/procedure.json
cmd/glot/templates/query-list.json cmd/glot/lexicon-templates/query-list.json
cmd/glot/templates/query-view.json cmd/glot/lexicon-templates/query-view.json
cmd/glot/templates/record.json cmd/glot/lexicon-templates/record.json
cmd/glot/unpublish.go cmd/glot/lex_unpublish.go
-33
cmd/glot/util.go
··· 1 - package main 2 - 3 - import ( 4 - "fmt" 5 - "strings" 6 - 7 - "github.com/bluesky-social/indigo/atproto/syntax" 8 - ) 9 - 10 - var ( 11 - schemaNSID = syntax.NSID("com.atproto.lexicon.schema") 12 - ) 13 - 14 - func nsidGroup(nsid syntax.NSID) string { 15 - parts := strings.Split(string(nsid), ".") 16 - g := strings.Join(parts[0:len(parts)-1], ".") + "." 17 - return g 18 - } 19 - 20 - // Checks if a string is a valid NSID group pattern, which is a partial NSID ending in '.' or '.*' 21 - func ParseNSIDGroup(raw string) (string, error) { 22 - if strings.HasSuffix(raw, ".*") { 23 - raw = raw[:len(raw)-1] 24 - } 25 - if !strings.HasSuffix(raw, ".") { 26 - return "", fmt.Errorf("not an NSID group pattern") 27 - } 28 - _, err := syntax.ParseNSID(raw + "name") 29 - if err != nil { 30 - return "", fmt.Errorf("not an NSID group pattern") 31 - } 32 - return raw, nil 33 - }
-60
cmd/glot/util_compare.go
··· 1 - package main 2 - 3 - import ( 4 - "context" 5 - "encoding/json" 6 - "sort" 7 - 8 - "github.com/bluesky-social/indigo/atproto/syntax" 9 - 10 - "github.com/urfave/cli/v3" 11 - ) 12 - 13 - func runComparisons(ctx context.Context, cmd *cli.Command, comp func(ctx context.Context, cmd *cli.Command, nsid syntax.NSID, localJSON, remoteJSON json.RawMessage) error) error { 14 - 15 - // collect all NSID/path mappings 16 - localSchemas, err := collectSchemaJSON(cmd) 17 - if err != nil { 18 - return err 19 - } 20 - remoteSchemas := map[syntax.NSID]json.RawMessage{} 21 - 22 - localGroups := map[string]bool{} 23 - allNSIDMap := map[syntax.NSID]bool{} 24 - for k := range localSchemas { 25 - g := nsidGroup(k) 26 - localGroups[g] = true 27 - allNSIDMap[k] = true 28 - } 29 - 30 - for g := range localGroups { 31 - if err := resolveLexiconGroup(ctx, cmd, g, &remoteSchemas); err != nil { 32 - return err 33 - } 34 - } 35 - 36 - for k := range remoteSchemas { 37 - allNSIDMap[k] = true 38 - } 39 - allNSID := []string{} 40 - for k := range allNSIDMap { 41 - allNSID = append(allNSID, string(k)) 42 - } 43 - sort.Strings(allNSID) 44 - 45 - anyFailures := false 46 - for _, k := range allNSID { 47 - nsid := syntax.NSID(k) 48 - if err := comp(ctx, cmd, nsid, localSchemas[nsid], remoteSchemas[nsid]); err != nil { 49 - if err != ErrLintFailures { 50 - return err 51 - } 52 - anyFailures = true 53 - } 54 - } 55 - 56 - if anyFailures { 57 - return ErrLintFailures 58 - } 59 - return nil 60 - }
-86
cmd/glot/util_fetch.go
··· 1 - package main 2 - 3 - import ( 4 - "context" 5 - "encoding/json" 6 - "fmt" 7 - "log/slog" 8 - 9 - "github.com/bluesky-social/indigo/api/agnostic" 10 - "github.com/bluesky-social/indigo/atproto/atclient" 11 - "github.com/bluesky-social/indigo/atproto/identity" 12 - "github.com/bluesky-social/indigo/atproto/lexicon" 13 - "github.com/bluesky-social/indigo/atproto/syntax" 14 - 15 - "github.com/urfave/cli/v3" 16 - ) 17 - 18 - // helper which resolves and fetches all lexicon schemas (as JSON), storing them in provided map 19 - func resolveLexiconGroup(ctx context.Context, cmd *cli.Command, group string, remote *map[syntax.NSID]json.RawMessage) error { 20 - 21 - slog.Debug("resolving schemas for NSID group", "group", group) 22 - 23 - // TODO: netclient support for listing records 24 - dir := identity.BaseDirectory{} 25 - did, err := dir.ResolveNSID(ctx, syntax.NSID(group+"name")) 26 - if err != nil { 27 - // if NSID isn't registered, just skip comparison 28 - slog.Warn("skipping NSID pattern which did not resolve", "group", group) 29 - return nil 30 - } 31 - ident, err := dir.LookupDID(ctx, did) 32 - if err != nil { 33 - return err 34 - } 35 - c := atclient.NewAPIClient(ident.PDSEndpoint()) 36 - 37 - cursor := "" 38 - for { 39 - // collection string, cursor string, limit int64, repo string, reverse bool 40 - resp, err := agnostic.RepoListRecords(ctx, c, schemaNSID.String(), cursor, 100, ident.DID.String(), false) 41 - if err != nil { 42 - return err 43 - } 44 - for _, rec := range resp.Records { 45 - aturi, err := syntax.ParseATURI(rec.Uri) 46 - if err != nil { 47 - return err 48 - } 49 - nsid, err := syntax.ParseNSID(aturi.RecordKey().String()) 50 - if err != nil { 51 - slog.Warn("ignoring invalid schema NSID", "did", ident.DID, "rkey", aturi.RecordKey()) 52 - continue 53 - } 54 - if nsidGroup(nsid) != group { 55 - // ignoring other NSIDs 56 - continue 57 - } 58 - if rec.Value == nil { 59 - return fmt.Errorf("missing record value: %s", nsid) 60 - } 61 - 62 - // parse file to check for errors 63 - // TODO: use json/v2 when available for case-sensitivity 64 - var sf lexicon.SchemaFile 65 - err = json.Unmarshal(*rec.Value, &sf) 66 - if err == nil { 67 - err = sf.FinishParse() 68 - } 69 - if err == nil { 70 - err = sf.CheckSchema() 71 - } 72 - if err != nil { 73 - return fmt.Errorf("invalid lexicon schema record (%s): %w", nsid, err) 74 - } 75 - 76 - (*remote)[nsid] = *rec.Value 77 - 78 - } 79 - if resp.Cursor != nil && *resp.Cursor != "" { 80 - cursor = *resp.Cursor 81 - } else { 82 - break 83 - } 84 - } 85 - return nil 86 - }
cmd/glot/util_files.go cmd/glot/lex_util_files.go