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