Skip to content

Commit 96126f6

Browse files
committed
Add a package for working with a cache.
g
1 parent 88246e8 commit 96126f6

File tree

4 files changed

+226
-3
lines changed

4 files changed

+226
-3
lines changed

go.sum

Lines changed: 0 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
package cachedirectory
2+
3+
import (
4+
"fmt"
5+
"io"
6+
"io/ioutil"
7+
"os"
8+
"path"
9+
"path/filepath"
10+
11+
"github.com/pkg/errors"
12+
)
13+
14+
const errorCacheWrongVersion = "The cache you are trying to push was created with an old version of the CodeQL Action Sync tool. Please re-pull it with this version of the tool."
15+
const errorNotACacheOrEmpty = "The cache directory you have selected is not empty, but was not created by the CodeQL Action Sync tool. If you are sure you want to use this directory, please delete it and run the sync tool again."
16+
const errorCacheParentDoesNotExist = "Cannot create cache directory because its parent, does not exist."
17+
const errorPushNonCache = "The directory you have provided does not appear to be valid. Please check it exists and that you have run the `pull` command to populate it."
18+
19+
type CacheDirectory struct {
20+
path string
21+
}
22+
23+
func NewCacheDirectory(path string) CacheDirectory {
24+
return CacheDirectory{
25+
path: path,
26+
}
27+
}
28+
29+
func isEmptyOrNonExistentDirectory(path string) (bool, error) {
30+
f, err := os.Open(path)
31+
if err != nil {
32+
if os.IsNotExist(err) {
33+
return true, nil
34+
}
35+
return false, errors.Wrap(err, fmt.Sprintf("Could not access directory %s.", path))
36+
}
37+
defer f.Close()
38+
39+
_, err = f.Readdirnames(1)
40+
if err != nil {
41+
if err == io.EOF {
42+
return true, nil
43+
}
44+
return false, errors.Wrap(err, fmt.Sprintf("Could not read contents of directory %s.", path))
45+
}
46+
return false, nil
47+
}
48+
49+
func (cacheDirectory *CacheDirectory) CheckOrCreateVersionFile(pull bool, version string) error {
50+
cacheVersionFilePath := cacheDirectory.versionFilePath()
51+
cacheVersionBytes, err := ioutil.ReadFile(cacheVersionFilePath)
52+
cacheVersionFileExists := !os.IsNotExist(err)
53+
if err != nil && cacheVersionFileExists {
54+
return errors.Wrap(err, "Could not read version file from cache directory.")
55+
}
56+
cacheVersion := string(cacheVersionBytes)
57+
58+
if cacheVersion == version {
59+
return nil
60+
}
61+
62+
if pull {
63+
cacheParentPath := filepath.Dir(cacheDirectory.path)
64+
_, err := os.Stat(cacheParentPath)
65+
if err != nil {
66+
if os.IsNotExist(err) {
67+
return errors.New(errorCacheParentDoesNotExist)
68+
}
69+
return errors.Wrap(err, "Could not access parent path of cache directory.")
70+
}
71+
72+
if cacheVersionFileExists {
73+
err := os.RemoveAll(cacheDirectory.path)
74+
if err != nil {
75+
return errors.Wrap(err, "Error removing outdated cache directory.")
76+
}
77+
}
78+
79+
isEmptyOrNonExistent, err := isEmptyOrNonExistentDirectory(cacheDirectory.path)
80+
if err != nil {
81+
return err
82+
}
83+
if isEmptyOrNonExistent {
84+
err := os.Mkdir(cacheDirectory.path, 0755)
85+
if err != nil {
86+
return errors.Wrap(err, "Could not create cache directory.")
87+
}
88+
err = ioutil.WriteFile(cacheVersionFilePath, []byte(version), 0644)
89+
if err != nil {
90+
return errors.Wrap(err, "Could not create cache version file.")
91+
}
92+
return nil
93+
}
94+
return errors.New(errorNotACacheOrEmpty)
95+
}
96+
97+
if cacheVersionFileExists {
98+
return errors.New(errorCacheWrongVersion)
99+
}
100+
return errors.New(errorPushNonCache)
101+
}
102+
103+
func (cacheDirectory *CacheDirectory) versionFilePath() string {
104+
return path.Join(cacheDirectory.path, ".codeql-actions-sync-version")
105+
}
106+
107+
func (cacheDirectory *CacheDirectory) GitPath() string {
108+
return path.Join(cacheDirectory.path, "git")
109+
}
110+
111+
func (cacheDirectory *CacheDirectory) ReleasesPath() string {
112+
return path.Join(cacheDirectory.path, "releases")
113+
}
114+
115+
func (cacheDirectory *CacheDirectory) ReleasePath(release string) string {
116+
return path.Join(cacheDirectory.ReleasesPath(), release)
117+
}
118+
119+
func (cacheDirectory *CacheDirectory) AssetsPath(release string) string {
120+
return path.Join(cacheDirectory.ReleasePath(release), "assets")
121+
}
122+
123+
func (cacheDirectory *CacheDirectory) MetadataPath(release string) string {
124+
return path.Join(cacheDirectory.ReleasePath(release), "metadata.json")
125+
}
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
package cachedirectory
2+
3+
import (
4+
"io/ioutil"
5+
"os"
6+
"path"
7+
"testing"
8+
9+
"github.com/github/codeql-action-sync/test"
10+
"github.com/stretchr/testify/require"
11+
)
12+
13+
const aVersion = "1.0.0"
14+
const aDifferentVersion = "1.0.1"
15+
16+
func TestCreateCacheDirectoryDuringPullThenReuse(t *testing.T) {
17+
temporaryDirectory := test.CreateTemporaryDirectory(t)
18+
cacheDirectory := NewCacheDirectory(path.Join(temporaryDirectory, "cache"))
19+
err := cacheDirectory.CheckOrCreateVersionFile(true, aVersion)
20+
require.NoError(t, err)
21+
flagFile := path.Join(cacheDirectory.path, "flag")
22+
ioutil.WriteFile(flagFile, []byte("test"), 0644)
23+
err = cacheDirectory.CheckOrCreateVersionFile(true, aVersion)
24+
require.NoError(t, err)
25+
err = cacheDirectory.CheckOrCreateVersionFile(false, aVersion)
26+
require.NoError(t, err)
27+
require.FileExists(t, flagFile)
28+
}
29+
30+
func TestOverwriteCacheDirectoryIfVersionMismatchDuringPull(t *testing.T) {
31+
temporaryDirectory := test.CreateTemporaryDirectory(t)
32+
cacheDirectory := NewCacheDirectory(path.Join(temporaryDirectory, "cache"))
33+
err := cacheDirectory.CheckOrCreateVersionFile(true, aVersion)
34+
require.NoError(t, err)
35+
flagFile := path.Join(cacheDirectory.path, "flag")
36+
ioutil.WriteFile(flagFile, []byte("test"), 0644)
37+
err = cacheDirectory.CheckOrCreateVersionFile(true, aDifferentVersion)
38+
require.NoError(t, err)
39+
require.NoFileExists(t, flagFile)
40+
}
41+
42+
func TestErrorIfVersionMismatchDuringPush(t *testing.T) {
43+
temporaryDirectory := test.CreateTemporaryDirectory(t)
44+
cacheDirectory := NewCacheDirectory(path.Join(temporaryDirectory, "cache"))
45+
err := cacheDirectory.CheckOrCreateVersionFile(true, aVersion)
46+
require.NoError(t, err)
47+
err = cacheDirectory.CheckOrCreateVersionFile(false, aDifferentVersion)
48+
require.EqualError(t, err, errorCacheWrongVersion)
49+
}
50+
51+
func TestErrorIfCacheIsNonEmptyAndNotCache(t *testing.T) {
52+
temporaryDirectory := test.CreateTemporaryDirectory(t)
53+
cacheDirectoryPath := path.Join(temporaryDirectory, "cache")
54+
err := os.MkdirAll(cacheDirectoryPath, 0755)
55+
require.NoError(t, err)
56+
flagFile := path.Join(cacheDirectoryPath, "flag")
57+
ioutil.WriteFile(flagFile, []byte("test"), 0644)
58+
cacheDirectory := NewCacheDirectory(cacheDirectoryPath)
59+
err = cacheDirectory.CheckOrCreateVersionFile(true, aVersion)
60+
require.EqualError(t, err, errorNotACacheOrEmpty)
61+
require.FileExists(t, flagFile)
62+
}
63+
64+
func TestErrorIfCacheParentDoesNotExist(t *testing.T) {
65+
temporaryDirectory := test.CreateTemporaryDirectory(t)
66+
cacheDirectory := NewCacheDirectory(path.Join(temporaryDirectory, "non-existent-parent", "cache"))
67+
err := cacheDirectory.CheckOrCreateVersionFile(true, aVersion)
68+
require.EqualError(t, err, errorCacheParentDoesNotExist)
69+
}
70+
71+
func TestErrorIfPushNonCache(t *testing.T) {
72+
temporaryDirectory := test.CreateTemporaryDirectory(t)
73+
cacheDirectory := NewCacheDirectory(temporaryDirectory)
74+
err := cacheDirectory.CheckOrCreateVersionFile(false, aVersion)
75+
require.EqualError(t, err, errorPushNonCache)
76+
}
77+
78+
func TestErrorIfPushNonExistent(t *testing.T) {
79+
temporaryDirectory := test.CreateTemporaryDirectory(t)
80+
cacheDirectory := NewCacheDirectory(path.Join(temporaryDirectory, "cache"))
81+
err := cacheDirectory.CheckOrCreateVersionFile(false, aVersion)
82+
require.EqualError(t, err, errorPushNonCache)
83+
}

test/test.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package test
2+
3+
import (
4+
"io/ioutil"
5+
"os"
6+
"testing"
7+
8+
"github.com/stretchr/testify/require"
9+
)
10+
11+
func CreateTemporaryDirectory(t *testing.T) string {
12+
directory, err := ioutil.TempDir("", "codeql-action-sync-tests")
13+
require.NoError(t, err)
14+
t.Cleanup(func() {
15+
os.RemoveAll(directory)
16+
})
17+
return directory
18+
}

0 commit comments

Comments
 (0)