This repository has no description
0

Configure Feed

Select the types of activity you want to include in your feed.

1package main 2 3import ( 4 "context" 5 "crypto/sha1" 6 "encoding/json" 7 "fmt" 8 "io" 9 "net/url" 10 "os" 11 "path/filepath" 12 13 "github.com/bluesky-social/indigo/atproto/identity" 14 "github.com/bluesky-social/indigo/atproto/syntax" 15 "github.com/sourcegraph/zoekt" 16 "tangled.org/core/repoident" 17 "tangled.org/core/repoverify" 18) 19 20// 1 MB; match https://sourcegraph.sourcegraph.com/r/github.com/sourcegraph/sourcegraph/-/blob/cmd/searcher/internal/search/store.go?L32 21const MaxFileSize = 1 << 20 22 23func gitIndex(ctx context.Context, cfg *Config, dir identity.Directory, req indexRequest) error { 24 ctx, cancel := context.WithTimeout(ctx, cfg.IndexTimeout) 25 defer cancel() 26 27 repo, err := loadRepo(ctx, cfg, dir, req.Repo) 28 if err != nil { 29 return fmt.Errorf("loading repo %s: %w", req.Repo, err) 30 } 31 repo.Branches = req.Branches 32 33 gitDir, err := tmpGitDir(repo.Did.String()) 34 if err != nil { 35 return err 36 } 37 defer os.RemoveAll(gitDir) // best-effort cleanup 38 39 if err := fetchRepo(ctx, gitDir, repo.CloneURL(), req.Branches); err != nil { 40 return err 41 } 42 43 if err := indexRepo(ctx, cfg, gitDir, *repo); err != nil { 44 return err 45 } 46 47 return nil 48} 49 50func loadRepo(ctx context.Context, cfg *Config, dir identity.Directory, repoDID repoident.RepoDid) (*Repo, error) { 51 ident, err := dir.LookupDID(ctx, syntax.DID(repoDID)) 52 if err != nil { 53 return nil, err 54 } 55 56 knot, err := repoident.KnotURLFromIdentity(ident, cfg.KnotScheme) 57 if err != nil { 58 return nil, fmt.Errorf("repoDid %s: %w", repoDID, err) 59 } 60 61 described, err := repoverify.Describe(ctx, nil, knot, repoDID) 62 if err != nil { 63 return nil, err 64 } 65 66 return &Repo{ 67 Did: repoDID, 68 Owner: described.OwnerDid, 69 Slug: described.Rkey, 70 Knot: knot, 71 }, nil 72} 73 74func fetchRepo(ctx context.Context, gitDir, cloneUrl string, branches []zoekt.RepositoryBranch) error { 75 // Create a repo to fetch into 76 if err := executeCmd(ctx, 77 "git", 78 // use a random default branch. This is so that HEAD isn't a symref to a 79 // branch that is indexed. For example if you are indexing 80 // HEAD,master. Then HEAD would be pointing to master by default. 81 "-c", "init.defaultBranch=nonExistentBranchBB0FOFCH32", 82 "init", 83 // we don't need a working copy 84 "--bare", 85 gitDir, 86 ); err != nil { 87 return err 88 } 89 90 fetchArgs := []string{ 91 "-C", gitDir, 92 "-c", "protocol.version=2", 93 "fetch", "--depth=1", "--no-tags", 94 } 95 // Git's blob:limit filter excludes blobs whose size is >= the given limit, 96 // while zoekt indexes files up to and including FileLimit bytes. 97 fetchArgs = append(fetchArgs, fmt.Sprintf("--filter=blob:limit=%d", int64(MaxFileSize)+1)) 98 99 fetchArgs = append(fetchArgs, cloneUrl) 100 101 var commits []string 102 for _, b := range branches { 103 commits = append(commits, b.Version) 104 } 105 fetchArgs = append(fetchArgs, commits...) 106 107 if err := executeCmd(ctx, "git", fetchArgs...); err != nil { 108 return err 109 } 110 111 for _, b := range branches { 112 ref := b.Name 113 if ref != "HEAD" { 114 ref = "refs/heads/" + ref 115 } 116 if err := executeCmd(ctx, "git", "-C", gitDir, "update-ref", ref, b.Version); err != nil { 117 return fmt.Errorf("failed update-ref %s to %s: %w", ref, b.Version, err) 118 } 119 } 120 121 return nil 122} 123 124func indexRepo(ctx context.Context, cfg *Config, gitDir string, repo Repo) error { 125 executablePath, err := os.Executable() 126 if err != nil { 127 return err 128 } 129 130 repoJson, err := json.Marshal(repo) 131 if err != nil { 132 return err 133 } 134 135 args := []string{"index"} 136 args = append(args, "-index-dir", cfg.IndexDir) 137 args = append(args, "-appview-url", cfg.AppviewUrl) 138 args = append(args, gitDir, string(repoJson)) 139 if err := executeCmd(ctx, executablePath, args...); err != nil { 140 return err 141 } 142 return nil 143} 144 145func tmpGitDir(name string) (string, error) { 146 abs := url.QueryEscape(name) 147 if len(abs) > 200 { 148 h := sha1.New() 149 _, _ = io.WriteString(h, abs) 150 abs = abs[:200] + fmt.Sprintf("%x", h.Sum(nil))[:8] 151 } 152 dir := filepath.Join(os.TempDir(), abs+".git") 153 if _, err := os.Stat(dir); err == nil { 154 if err := os.RemoveAll(dir); err != nil { 155 return "", err 156 } 157 } 158 return dir, nil 159}