github.com/nektos/act@v0.2.83/pkg/runner/local_repository_cache.go (about)

     1  package runner
     2  
     3  import (
     4  	"archive/tar"
     5  	"bytes"
     6  	"context"
     7  	"fmt"
     8  	"io"
     9  	"io/fs"
    10  	goURL "net/url"
    11  	"os"
    12  	"path/filepath"
    13  	"strings"
    14  
    15  	"github.com/nektos/act/pkg/common"
    16  	"github.com/nektos/act/pkg/filecollector"
    17  )
    18  
    19  type LocalRepositoryCache struct {
    20  	Parent            ActionCache
    21  	LocalRepositories map[string]string
    22  	CacheDirCache     map[string]string
    23  }
    24  
    25  func (l *LocalRepositoryCache) Fetch(ctx context.Context, cacheDir, url, ref, token string) (string, error) {
    26  	logger := common.Logger(ctx)
    27  	logger.Debugf("LocalRepositoryCache fetch %s with ref %s", url, ref)
    28  	if dest, ok := l.LocalRepositories[fmt.Sprintf("%s@%s", url, ref)]; ok {
    29  		logger.Infof("LocalRepositoryCache matched %s with ref %s to %s", url, ref, dest)
    30  		l.CacheDirCache[fmt.Sprintf("%s@%s", cacheDir, ref)] = dest
    31  		return ref, nil
    32  	}
    33  	if purl, err := goURL.Parse(url); err == nil {
    34  		if dest, ok := l.LocalRepositories[fmt.Sprintf("%s@%s", strings.TrimPrefix(purl.Path, "/"), ref)]; ok {
    35  			logger.Infof("LocalRepositoryCache matched %s with ref %s to %s", url, ref, dest)
    36  			l.CacheDirCache[fmt.Sprintf("%s@%s", cacheDir, ref)] = dest
    37  			return ref, nil
    38  		}
    39  	}
    40  	logger.Infof("LocalRepositoryCache not matched %s with Ref %s", url, ref)
    41  	return l.Parent.Fetch(ctx, cacheDir, url, ref, token)
    42  }
    43  
    44  func (l *LocalRepositoryCache) GetTarArchive(ctx context.Context, cacheDir, sha, includePrefix string) (io.ReadCloser, error) {
    45  	logger := common.Logger(ctx)
    46  	// sha is mapped to ref in fetch if there is a local override
    47  	if dest, ok := l.CacheDirCache[fmt.Sprintf("%s@%s", cacheDir, sha)]; ok {
    48  		logger.Infof("LocalRepositoryCache read cachedir %s with ref %s and subpath '%s' from %s", cacheDir, sha, includePrefix, dest)
    49  		srcPath := filepath.Join(dest, includePrefix)
    50  		buf := &bytes.Buffer{}
    51  		tw := tar.NewWriter(buf)
    52  		defer tw.Close()
    53  		srcPath = filepath.Clean(srcPath)
    54  		fi, err := os.Lstat(srcPath)
    55  		if err != nil {
    56  			return nil, err
    57  		}
    58  		tc := &filecollector.TarCollector{
    59  			TarWriter: tw,
    60  		}
    61  		if fi.IsDir() {
    62  			srcPrefix := srcPath
    63  			if !strings.HasSuffix(srcPrefix, string(filepath.Separator)) {
    64  				srcPrefix += string(filepath.Separator)
    65  			}
    66  			fc := &filecollector.FileCollector{
    67  				Fs:        &filecollector.DefaultFs{},
    68  				SrcPath:   srcPath,
    69  				SrcPrefix: srcPrefix,
    70  				Handler:   tc,
    71  			}
    72  			err = filepath.Walk(srcPath, fc.CollectFiles(ctx, []string{}))
    73  			if err != nil {
    74  				return nil, err
    75  			}
    76  		} else {
    77  			var f io.ReadCloser
    78  			var linkname string
    79  			if fi.Mode()&fs.ModeSymlink != 0 {
    80  				linkname, err = os.Readlink(srcPath)
    81  				if err != nil {
    82  					return nil, err
    83  				}
    84  			} else {
    85  				f, err = os.Open(srcPath)
    86  				if err != nil {
    87  					return nil, err
    88  				}
    89  				defer f.Close()
    90  			}
    91  			err := tc.WriteFile(fi.Name(), fi, linkname, f)
    92  			if err != nil {
    93  				return nil, err
    94  			}
    95  		}
    96  		return io.NopCloser(buf), nil
    97  	}
    98  	logger.Infof("LocalRepositoryCache not matched cachedir %s with Ref %s and subpath '%s'", cacheDir, sha, includePrefix)
    99  	return l.Parent.GetTarArchive(ctx, cacheDir, sha, includePrefix)
   100  }