github.com/kubri/kubri@v0.5.1-0.20240317001612-bda2aaef967e/source/local/local.go (about)

     1  // Package local is a source backend for loading packages from a single directory.
     2  package local
     3  
     4  import (
     5  	"context"
     6  	"os"
     7  	"path/filepath"
     8  	"strings"
     9  	"time"
    10  
    11  	"github.com/kubri/kubri/source"
    12  )
    13  
    14  type Config struct {
    15  	Path    string
    16  	Version string
    17  }
    18  
    19  type localSource struct {
    20  	path    string
    21  	root    string
    22  	version string
    23  }
    24  
    25  func New(c Config) (*source.Source, error) {
    26  	root, err := getRoot(c.Path)
    27  	if err != nil {
    28  		return nil, err
    29  	}
    30  	return source.New(&localSource{path: c.Path, root: root, version: c.Version}), nil
    31  }
    32  
    33  func (s *localSource) ListReleases(ctx context.Context) ([]*source.Release, error) {
    34  	r, err := s.GetRelease(ctx, s.version)
    35  	if err != nil {
    36  		return nil, err
    37  	}
    38  
    39  	return []*source.Release{r}, nil
    40  }
    41  
    42  func (s *localSource) GetRelease(ctx context.Context, version string) (*source.Release, error) {
    43  	files, err := getFiles(s.path)
    44  	if err != nil {
    45  		return nil, err
    46  	}
    47  
    48  	r := &source.Release{
    49  		Version: version,
    50  		Date:    time.Now(),
    51  		Assets:  make([]*source.Asset, 0, len(files)),
    52  	}
    53  
    54  	for _, path := range files {
    55  		if err := ctx.Err(); err != nil {
    56  			return nil, err
    57  		}
    58  
    59  		f, err := os.Stat(path)
    60  		if err != nil {
    61  			return nil, err
    62  		}
    63  
    64  		path, err = filepath.Abs(path)
    65  		if err != nil {
    66  			return nil, err
    67  		}
    68  
    69  		r.Assets = append(r.Assets, &source.Asset{
    70  			Name: f.Name(),
    71  			URL:  "file://" + path,
    72  			Size: int(f.Size()),
    73  		})
    74  	}
    75  
    76  	return r, nil
    77  }
    78  
    79  func (s *localSource) UploadAsset(_ context.Context, _, name string, data []byte) error {
    80  	return os.WriteFile(filepath.Join(s.root, name), data, os.ModePerm)
    81  }
    82  
    83  func (s *localSource) DownloadAsset(_ context.Context, _, name string) ([]byte, error) {
    84  	path := filepath.Join(s.root, name)
    85  	if _, err := os.Stat(path); err == nil {
    86  		return os.ReadFile(path)
    87  	}
    88  
    89  	files, err := getFiles(s.path)
    90  	if err != nil {
    91  		return nil, err
    92  	}
    93  
    94  	for _, path := range files {
    95  		if filepath.Base(path) == name {
    96  			return os.ReadFile(path)
    97  		}
    98  	}
    99  
   100  	return nil, source.ErrAssetNotFound
   101  }
   102  
   103  func getFiles(path string) ([]string, error) {
   104  	if strings.ContainsRune(path, '*') {
   105  		return filepath.Glob(path)
   106  	}
   107  
   108  	fi, err := os.Stat(path)
   109  	if err != nil {
   110  		return nil, err
   111  	}
   112  
   113  	if !fi.IsDir() {
   114  		return []string{path}, nil
   115  	}
   116  
   117  	files, err := os.ReadDir(path)
   118  	if err != nil {
   119  		return nil, err
   120  	}
   121  
   122  	paths := make([]string, 0, len(files))
   123  	for _, file := range files {
   124  		if !file.IsDir() {
   125  			paths = append(paths, filepath.Join(path, file.Name()))
   126  		}
   127  	}
   128  
   129  	return paths, nil
   130  }
   131  
   132  func getRoot(path string) (string, error) {
   133  	if i := strings.IndexRune(path, '*'); i >= 0 {
   134  		return path[:i], nil
   135  	}
   136  
   137  	fi, err := os.Stat(path)
   138  	if err != nil {
   139  		return "", err
   140  	}
   141  
   142  	if !fi.IsDir() {
   143  		return filepath.Dir(path), nil
   144  	}
   145  
   146  	return path, nil
   147  }