Skip to content

Commit

Permalink
Merge pull request #25 from jamie-harness/master
Browse files Browse the repository at this point in the history
[CI-5673]: Implement automatic cache detect and provide ability to prepare folder for each build tool
  • Loading branch information
jamie-harness authored Dec 9, 2022
2 parents 1383e88 + cad28b4 commit 998ef00
Show file tree
Hide file tree
Showing 8 changed files with 385 additions and 12 deletions.
102 changes: 102 additions & 0 deletions internal/plugin/autodetect/auto_detect_util.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
package autodetect

import (
"crypto/md5" // #nosec
"encoding/hex"
"io"
"os"
"path/filepath"
)

type buildToolInfo struct {
globToDetect string
tool string
preparer RepoPreparer
}

func DetectDirectoriesToCache() ([]string, []string, string, error) {
var buildToolInfoMapping = []buildToolInfo{
{
globToDetect: "*pom.xml",
tool: "maven",
preparer: newMavenPreparer(),
},
{
globToDetect: "*build.gradle",
tool: "gradle",
preparer: newGradlePreparer(),
},
}

var directoriesToCache []string

var buildToolsDetected []string

var hashes string

for _, supportedTool := range buildToolInfoMapping {
hash, err := hashIfFileExist(supportedTool.globToDetect)
if err != nil {
return nil, nil, "", err
}

if hash != "" {
dirToCache, err := supportedTool.preparer.PrepareRepo()
if err != nil {
return nil, nil, "", err
}

directoriesToCache = append(directoriesToCache, dirToCache)
buildToolsDetected = append(buildToolsDetected, supportedTool.tool)
hashes += hash
}
}

return directoriesToCache, buildToolsDetected, hashes, nil
}

func hashIfFileExist(glob string) (string, error) {
matches, _ := filepath.Glob(glob)

if len(matches) == 0 {
return "", nil
}

return calculateMd5FromFiles(matches)
}

func calculateMd5FromFiles(fileList []string) (string, error) {
rootMostFile := shortestPath(fileList)
file, err := os.Open(rootMostFile)

if err != nil {
return "", err
}

defer file.Close()

if err != nil {
return "", err
}

hash := md5.New() // #nosec
_, err = io.Copy(hash, file)

if err != nil {
return "", err
}

return hex.EncodeToString(hash.Sum(nil)), nil
}

func shortestPath(input []string) (shortest string) {
size := len(input[0])
for _, v := range input {
if len(v) <= size {
shortest = v
size = len(v)
}
}

return
}
120 changes: 120 additions & 0 deletions internal/plugin/autodetect/auto_detect_util_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
package autodetect

import (
"os"
"path/filepath"
"testing"

"github.com/meltwater/drone-cache/test"
)

const (
pomFile = "pom.xml"
nestedDirectory = "dir"
bazelBuildFile = "build.gradle"
testFileContent = "some_content"
testFileContent2 = "some_other_content"
toolMaven = "maven"
toolMavenDir = ".m2/repository"
toolGradle = "gradle"
toolGradleDir = ".gradle"
)

func TestDetectDirectoriesToCacheMaven(t *testing.T) {
f, err := os.Create(pomFile)
test.Ok(t, err)
defer f.Close()
_, err = f.WriteString(testFileContent)
test.Ok(t, err)
directoriesToCache, buildToolsDetected, hashes, err := DetectDirectoriesToCache()
test.Ok(t, err)
test.Ok(t, os.RemoveAll(pomFile))
expectedCacheDir := []string{toolMavenDir}
expectedDetectedTool := []string{toolMaven}
test.Equals(t, directoriesToCache, expectedCacheDir)
test.Equals(t, buildToolsDetected, expectedDetectedTool)
test.Equals(t, hashes, "baab6c16d9143523b7865d46896e4596")
}

func TestDetectDirectoriesToCacheMavenMultiMaven(t *testing.T) {
f, err := os.Create(pomFile)
test.Ok(t, err)
defer f.Close()

_, err = f.WriteString(testFileContent)

test.Ok(t, err)
test.Ok(t, os.MkdirAll(nestedDirectory, 0755))

f2, err := os.Create(filepath.Join(nestedDirectory, pomFile))

test.Ok(t, err)
defer f2.Close()

_, err = f2.WriteString(testFileContent2)

test.Ok(t, err)
directoriesToCache, buildToolsDetected, hashes, err := DetectDirectoriesToCache()

test.Ok(t, err)
test.Ok(t, os.RemoveAll(pomFile))
test.Ok(t, os.RemoveAll(filepath.Join(nestedDirectory, pomFile)))

expectedCacheDir := []string{toolMavenDir}
expectedDetectedTool := []string{toolMaven}

test.Equals(t, directoriesToCache, expectedCacheDir)
test.Equals(t, buildToolsDetected, expectedDetectedTool)
test.Equals(t, hashes, "baab6c16d9143523b7865d46896e4596")
}

func TestDetectDirectoriesToCacheBazel(t *testing.T) {
f, err := os.Create(bazelBuildFile)
test.Ok(t, err)
defer f.Close()

_, err = f.WriteString(testFileContent)
test.Ok(t, err)

directoriesToCache, buildToolsDetected, hashes, err := DetectDirectoriesToCache()

test.Ok(t, os.RemoveAll(bazelBuildFile))
test.Ok(t, err)

expectedCacheDir := []string{toolGradleDir}
expectedDetectedTool := []string{toolGradle}

test.Equals(t, directoriesToCache, expectedCacheDir)
test.Equals(t, buildToolsDetected, expectedDetectedTool)
test.Equals(t, hashes, "baab6c16d9143523b7865d46896e4596")
}

func TestDetectDirectoriesToCacheCombined(t *testing.T) {
f, err := os.Create(bazelBuildFile)
test.Ok(t, err)
defer f.Close()

_, err = f.WriteString(testFileContent)

test.Ok(t, err)
f2, err := os.Create(pomFile)

test.Ok(t, err)
defer f2.Close()

_, err = f2.WriteString(testFileContent2)

test.Ok(t, err)
directoriesToCache, buildToolsDetected, hashes, err := DetectDirectoriesToCache()

test.Ok(t, os.RemoveAll(bazelBuildFile))
test.Ok(t, os.RemoveAll(pomFile))
test.Ok(t, err)

expectedCacheDir := []string{toolMavenDir, toolGradleDir}
expectedDetectedTool := []string{toolMaven, toolGradle}

test.Equals(t, directoriesToCache, expectedCacheDir)
test.Equals(t, buildToolsDetected, expectedDetectedTool)
test.Equals(t, hashes, "1eb00e74bffac0c4fa2d6dbfd8c26cb7baab6c16d9143523b7865d46896e4596")
}
48 changes: 48 additions & 0 deletions internal/plugin/autodetect/prepare_gradle.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package autodetect

import (
"errors"
"fmt"
"os"
)

type gradlePreparer struct{}

func newGradlePreparer() *gradlePreparer {
return &gradlePreparer{}
}

func (*gradlePreparer) PrepareRepo() (string, error) {
fileName := "gradle.properties"
pathToCache := ".gradle"
cmdToOverrideRepo := fmt.Sprintf("systemProp.gradle.user.home=/%s/\norg.gradle.caching=true\n", pathToCache)

if _, err := os.Stat(fileName); errors.Is(err, os.ErrNotExist) {
f, err := os.Create(fileName)
if err != nil {
return "", err
}
defer f.Close()
_, err = f.WriteString(cmdToOverrideRepo)

if err != nil {
return "", err
}

return pathToCache, nil
}

f, err := os.OpenFile(fileName, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)

if err != nil {
return "", err
}
defer f.Close()
_, err = f.WriteString(cmdToOverrideRepo)

if err != nil {
return "", err
}

return pathToCache, nil
}
56 changes: 56 additions & 0 deletions internal/plugin/autodetect/prepare_maven.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package autodetect

import (
"errors"
"fmt"
"os"
"path/filepath"
)

type mavenPreparer struct{}

func newMavenPreparer() *mavenPreparer {
return &mavenPreparer{}
}
func (*mavenPreparer) PrepareRepo() (string, error) {
configPath := ".mvn"
fileName := "maven.config"
pathToCache := filepath.Join(".m2", "repository")
cmdToOverrideRepo := fmt.Sprintf(" -Dmaven.repo.local=%s ", pathToCache)

if _, err := os.Stat(filepath.Join(configPath, fileName)); errors.Is(err, os.ErrNotExist) {
err := os.MkdirAll(configPath, os.ModePerm)

if err != nil {
return "", err
}

f, err := os.Create(filepath.Join(configPath, fileName))

if err != nil {
return "", err
}
defer f.Close()
_, err = f.WriteString(cmdToOverrideRepo)

if err != nil {
return "", err
}

return pathToCache, err
}

f, err := os.OpenFile(filepath.Join(configPath, fileName), os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)

if err != nil {
return "", err
}
defer f.Close()
_, err = f.WriteString(cmdToOverrideRepo)

if err != nil {
return "", err
}

return pathToCache, nil
}
6 changes: 6 additions & 0 deletions internal/plugin/autodetect/prepare_repo.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package autodetect

type RepoPreparer interface {
// PrepareRepo change local files to a state where cache intelligence options can be performed
PrepareRepo() (string, error)
}
8 changes: 5 additions & 3 deletions internal/plugin/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,13 @@ type Config struct {
CacheKeyTemplate string
RemoteRoot string
LocalRoot string
AccountID string

// Modes
Debug bool
Rebuild bool
Restore bool
Debug bool
Rebuild bool
Restore bool
AutoDetect bool

// Optional
SkipSymlinks bool
Expand Down
Loading

0 comments on commit 998ef00

Please sign in to comment.