fork of https://github.com/sourcegraph/zoekt
1package index
2
3import (
4 "encoding/json"
5 "fmt"
6 "os"
7 "path/filepath"
8
9 "github.com/sourcegraph/zoekt"
10)
11
12var mockRepos []*zoekt.Repository
13
14// SetTombstone idempotently sets a tombstone for repoName in .meta.
15func SetTombstone(shardPath string, repoID uint32) error {
16 return setTombstone(shardPath, repoID, true)
17}
18
19// UnsetTombstone idempotently removes a tombstones for reopName in .meta.
20func UnsetTombstone(shardPath string, repoID uint32) error {
21 return setTombstone(shardPath, repoID, false)
22}
23
24func setTombstone(shardPath string, repoID uint32, tombstone bool) error {
25 var repos []*zoekt.Repository
26 var err error
27
28 if mockRepos != nil {
29 repos = mockRepos
30 } else {
31 repos, _, err = ReadMetadataPath(shardPath)
32 if err != nil {
33 return err
34 }
35 }
36
37 for _, repo := range repos {
38 if repo.ID == repoID {
39 repo.Tombstone = tombstone
40 }
41 }
42
43 tempPath, finalPath, err := JsonMarshalRepoMetaTemp(shardPath, repos)
44 if err != nil {
45 return err
46 }
47
48 err = os.Rename(tempPath, finalPath)
49 if err != nil {
50 os.Remove(tempPath)
51 }
52
53 return nil
54}
55
56// JsonMarshalRepoMetaTemp writes the json encoding of the given repository metadata to a temporary file
57// in the same directory as the given shard path. It returns both the path of the temporary file and the
58// path of the final file that the caller should use.
59//
60// The caller is responsible for renaming the temporary file to the final file path, or removing
61// the temporary file if it is no longer needed.
62// TODO: Should we stick this in a util package?
63func JsonMarshalRepoMetaTemp(shardPath string, repositoryMetadata any) (tempPath, finalPath string, err error) {
64 finalPath = shardPath + ".meta"
65
66 b, err := json.Marshal(repositoryMetadata)
67 if err != nil {
68 return "", "", fmt.Errorf("marshalling json: %w", err)
69 }
70
71 f, err := os.CreateTemp(filepath.Dir(finalPath), filepath.Base(finalPath)+".*.tmp")
72 if err != nil {
73 return "", "", fmt.Errorf("writing temporary file: %s", err)
74 }
75
76 defer func() {
77 f.Close()
78 if err != nil {
79 _ = os.Remove(f.Name())
80 }
81 }()
82
83 err = f.Chmod(0o666 &^ umask)
84 if err != nil {
85 return "", "", fmt.Errorf("chmoding temporary file: %s", err)
86 }
87
88 _, err = f.Write(b)
89 if err != nil {
90 return "", "", fmt.Errorf("writing json to temporary file: %s", err)
91 }
92
93 return f.Name(), finalPath, nil
94}