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