Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix:[PIPE-24876]: enable cgi to be prepackaged. Move cgi to %HOME/.harness-runner so that all the artifacts put together in one place #19

Merged
merged 3 commits into from
Feb 7, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion main.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,13 @@ import (
"log"
"log/slog"
"os"
"path/filepath"

"github.com/drone/go-task/task"
"github.com/drone/go-task/task/cloner"
download "github.com/drone/go-task/task/downloader"
"github.com/drone/go-task/task/drivers/cgi"
"github.com/drone/go-task/task/packaged"
)

var (
Expand Down Expand Up @@ -98,8 +100,9 @@ func main() {
cloner.Default(),

// top-level directory where the downloading should happen
cache,
filepath.Join(cache, "download"),
)
packageLoader := packaged.New(filepath.Join(cache, "default"))

// create the task router
router := task.NewRouter()
Expand All @@ -112,6 +115,7 @@ func main() {
// use the default downloader which
// caches tasks at ~/.cache/harness/task
downloader,
packageLoader,
),
)

Expand Down
9 changes: 1 addition & 8 deletions task/downloader/downloader.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ package downloader

import (
"context"
"path/filepath"

"github.com/drone/go-task/task"
"github.com/drone/go-task/task/cloner"
Expand All @@ -22,15 +21,9 @@ type Downloader struct {
}

func New(cloner cloner.Cloner, dir string) Downloader {
baseDir := getBaseDownloadDir(dir)
repoDownloader := newRepoDownloader(cloner)
executableDownloader := newExecutableDownloader()
return Downloader{dir: baseDir, repoDownloader: repoDownloader, executableDownloader: executableDownloader}
}

// getBaseDownloadDir returns the top-level directory where all files should be downloaded
func getBaseDownloadDir(dir string) string {
return filepath.Join(dir, ".harness", "cache")
return Downloader{dir: dir, repoDownloader: repoDownloader, executableDownloader: executableDownloader}
}

func (d *Downloader) DownloadRepo(ctx context.Context, repo *task.Repository) (string, error) {
Expand Down
10 changes: 6 additions & 4 deletions task/downloader/executable_downloader.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,17 +43,19 @@ func (e *executableDownloader) download(ctx context.Context, dir string, taskTyp
return "", fmt.Errorf("os [%s] and architecture [%s] are not specified in executable configuration", operatingSystem, architecture)
}

destDir := filepath.Join(dir, taskType, getHash(url))
dest := getDownloadPath(url, destDir)
destDir := filepath.Join(dir, taskType, exec.Name)
// {baseDir}/taskType/{name}/{name}-{version}-{os}-{arch}
// download to a file named by this runner to make sure upstream changes doesn't affect the cache hit lookup
dest := filepath.Join(destDir, exec.Name+"-"+exec.Version+"-"+operatingSystem+"-"+architecture)

if cacheHit := isCacheHitFn(ctx, destDir); cacheHit {
if cacheHit := isCacheHitFn(ctx, dest); cacheHit {
// exit if the artifact destination already exists
return dest, nil
}

// if no cache hit, remove all downloaded executables for this task's type
// so that we don't keep multiple executables of the same type
err := removeAllFn(filepath.Join(dir, taskType))
err := removeAllFn(destDir)
if err != nil {
return "", err
}
Expand Down
25 changes: 18 additions & 7 deletions task/drivers/cgi/driver.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"path/filepath"

"github.com/drone/go-task/task/logger"
"github.com/drone/go-task/task/packaged"

"github.com/drone/go-task/task"
"github.com/drone/go-task/task/builder"
Expand All @@ -31,12 +32,13 @@ type Config struct {
}

// New returns the task execution driver.
func New(d downloader.Downloader) task.Handler {
return &driver{downloader: d}
func New(d downloader.Downloader, pl packaged.PackageLoader) task.Handler {
xingchi-jin marked this conversation as resolved.
Show resolved Hide resolved
return &driver{downloader: d, packageLoader: pl}
}

type driver struct {
downloader downloader.Downloader
downloader downloader.Downloader
packageLoader packaged.PackageLoader
}

// Handle handles the task execution request.
Expand All @@ -50,9 +52,9 @@ func (d *driver) Handle(ctx context.Context, req *task.Request) task.Response {
return task.Error(err)
}

path, err := d.downloadArtifact(ctx, req.Task.Type, conf)
path, err := d.prepareArtifact(ctx, req.Task.Type, conf)
if err != nil {
log.WithError(err).Error("artifact download failed")
log.WithError(err).Error("Prepare artifact failed")
return task.Error(err)
}

Expand All @@ -74,13 +76,22 @@ func (d *driver) Handle(ctx context.Context, req *task.Request) task.Response {
return task.Respond(resp)
}

func (d *driver) downloadArtifact(ctx context.Context, taskType string, conf *Config) (string, error) {
func (d *driver) prepareArtifact(ctx context.Context, taskType string, conf *Config) (string, error) {
// use binary artifact
if conf.ExecutableConfig != nil {
return d.downloader.DownloadExecutable(ctx, taskType, conf.ExecutableConfig)
if shouldUsePrepackagedBinary(conf) {
return d.packageLoader.GetPackagePath(ctx, taskType, conf.ExecutableConfig)
} else {
return d.downloader.DownloadExecutable(ctx, taskType, conf.ExecutableConfig)
}
}
return d.downloader.DownloadRepo(ctx, conf.Repository)
}

func shouldUsePrepackagedBinary(conf *Config) bool {
return len(conf.ExecutableConfig.Executables) == 0
}

func setDefaultConfigValues(conf *Config) {
if conf.Method == "" {
conf.Method = "POST"
Expand Down
51 changes: 51 additions & 0 deletions task/packaged/packaged.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package packaged

/**
* @title PackageLoader

* @desc PackageLoader is a struct that provides a method to get the path of a pre-package artifact
* based on the task type and the executable name. This is used when artifacts are packaged with Runner
* in a container.
* It is assumed there is only one artifact per task type and executable name, because the OS and architecture
* are pre-determined.
*/

import (
"context"
"fmt"
"os"
"path/filepath"

"github.com/drone/go-task/task"
)

type PackageLoader struct {
dir string
}

func New(dir string) PackageLoader {
return PackageLoader{dir: dir}
}

func (p *PackageLoader) GetPackagePath(ctx context.Context, taskType string, exec *task.ExecutableConfig) (string, error) {
dir := filepath.Join(p.dir, taskType, exec.Name)
return getFirstFile(dir)
}

func getFirstFile(directory string) (string, error) {
// Open the directory
files, err := os.ReadDir(directory)
if err != nil {
return "", err
}

// Iterate through files to find the first file (not a directory)
for _, file := range files {
if !file.IsDir() {
return filepath.Join(directory, file.Name()), nil // Return the first file found
}
}

// If no files are found, return an error
return "", fmt.Errorf("no files found in directory: %s", directory)
}
2 changes: 2 additions & 0 deletions task/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,8 @@ type Repository struct {
// supported operating systems and architectures
type ExecutableConfig struct {
Executables []Executable `json:"executables"`
Name string `json:"name"`
Version string `json:"version"`
}

// Executable provides the url to download
Expand Down