github.com/octohelm/wagon@v0.0.0-20240308040401-88662650dc0b/pkg/engine/plan/task/core/image.go (about)

     1  package core
     2  
     3  import (
     4  	"dagger.io/dagger"
     5  	"fmt"
     6  	"github.com/octohelm/wagon/pkg/engine/daggerutil"
     7  	"golang.org/x/net/context"
     8  )
     9  
    10  func init() {
    11  	DefaultFactory.Register(&Image{})
    12  }
    13  
    14  type Image struct {
    15  	Rootfs   FS          `json:"rootfs"`
    16  	Config   ImageConfig `json:"config"`
    17  	Platform string      `json:"platform,omitempty"`
    18  }
    19  
    20  func (img *Image) Type() string {
    21  	return "oci"
    22  }
    23  
    24  func (img *Image) CanExport() bool {
    25  	return img.Rootfs.CanExport()
    26  }
    27  
    28  func (img *Image) ExportTo(ctx context.Context, localPath string) error {
    29  	return daggerutil.Do(ctx, func(c *dagger.Client) error {
    30  		rootfs := img.Rootfs.LoadDirectory(c)
    31  
    32  		ct := c.Container(dagger.ContainerOpts{
    33  			Platform: DefaultPlatform(img.Platform),
    34  		}).WithRootfs(rootfs)
    35  
    36  		ct = img.Config.ApplyTo(ct)
    37  
    38  		_, err := ct.Export(ctx, localPath)
    39  		return err
    40  	})
    41  }
    42  
    43  type ImageConfig struct {
    44  	WorkingDir string            `json:"workdir" default:""`
    45  	Env        map[string]string `json:"env"`
    46  	Labels     map[string]string `json:"label"`
    47  	Entrypoint []string          `json:"entrypoint"`
    48  	Cmd        []string          `json:"cmd"`
    49  	User       string            `json:"user" default:""`
    50  }
    51  
    52  func (p ImageConfig) ApplyTo(c *dagger.Container) *dagger.Container {
    53  	for k := range p.Env {
    54  		c = c.WithEnvVariable(k, p.Env[k])
    55  	}
    56  
    57  	for k := range p.Labels {
    58  		c = c.WithLabel(k, p.Labels[k])
    59  	}
    60  
    61  	if vv := p.User; vv != "" {
    62  		c = c.WithUser(vv)
    63  	}
    64  
    65  	if vv := p.WorkingDir; vv != "" {
    66  		c = c.WithWorkdir(vv)
    67  	}
    68  
    69  	if vv := p.Entrypoint; len(vv) != 0 {
    70  		c = c.WithEntrypoint(vv)
    71  	}
    72  
    73  	if vv := p.Cmd; len(vv) != 0 {
    74  		c = c.WithDefaultArgs(vv)
    75  	}
    76  
    77  	return c
    78  }
    79  
    80  func (p ImageConfig) Merge(config ImageConfig) ImageConfig {
    81  	final := ImageConfig{}
    82  
    83  	final.WorkingDir = p.WorkingDir
    84  	if config.WorkingDir != "" {
    85  		final.WorkingDir = config.WorkingDir
    86  	}
    87  
    88  	final.User = p.User
    89  	if config.WorkingDir != "" {
    90  		final.User = config.User
    91  	}
    92  
    93  	final.Entrypoint = p.Entrypoint
    94  	if len(config.Entrypoint) != 0 {
    95  		final.Entrypoint = config.Entrypoint
    96  	}
    97  
    98  	final.Cmd = p.Cmd
    99  	if len(config.Cmd) != 0 {
   100  		final.Cmd = config.Cmd
   101  	}
   102  
   103  	final.Env = mergeMap(p.Env, config.Env)
   104  	final.Labels = mergeMap(p.Labels, config.Labels)
   105  
   106  	return final
   107  }
   108  
   109  func (p *ImageConfig) Resolve(ctx context.Context, c *dagger.Client, id dagger.ContainerID) error {
   110  	ret := struct {
   111  		Container daggerutil.Container
   112  	}{}
   113  
   114  	err := daggerutil.Query(ctx, c, &ret, fmt.Sprintf(`
   115  query { 
   116      container(id: %q) {
   117  		id
   118  		entrypoint
   119  		defaultArgs
   120  		workdir
   121  		user
   122  		labels {
   123  			value
   124  			name
   125  		}
   126  		envVariables {
   127  			value
   128  			name
   129  		}
   130  		rootfs {
   131  			id
   132  		}
   133      }
   134  }
   135  `, id))
   136  	if err != nil {
   137  		return err
   138  	}
   139  
   140  	p.WorkingDir = ret.Container.Workdir
   141  	p.Entrypoint = ret.Container.Entrypoint
   142  	p.Cmd = ret.Container.DefaultArgs
   143  	p.User = ret.Container.User
   144  
   145  	p.Env = map[string]string{}
   146  	for _, e := range ret.Container.EnvVariables {
   147  		p.Env[e.Name] = e.Value
   148  	}
   149  
   150  	p.Labels = map[string]string{}
   151  	for _, e := range ret.Container.Labels {
   152  		p.Labels[e.Name] = e.Value
   153  	}
   154  
   155  	return nil
   156  }
   157  
   158  func mergeMap[K comparable, V any](a map[K]V, b map[K]V) map[K]V {
   159  	m := make(map[K]V)
   160  
   161  	for k := range a {
   162  		m[k] = a[k]
   163  	}
   164  
   165  	for k := range b {
   166  		m[k] = b[k]
   167  	}
   168  
   169  	return m
   170  }