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