clade

package module
v0.0.0-...-762437e Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 13, 2024 License: Apache-2.0 Imports: 21 Imported by: 0

README

CLade

test Go Report Card codebeat badge codecov

Keep your container images up to date.

CLade allows you to manage multiple Dockerfiles as a dependency tree and list images older than the upstream image.

Installation

$ go install github.com/lesomnus/clade/cmd/clade@latest

Usage

Command clade reads Port files named port.yaml in the directories of ports directory to construct a dependency tree. Port file describes what an image's tag is and which image that tag depends on.

$ mkdir -p ports/my-gcc
$ code ports/my-gcc/port.yaml
# ports/my-gcc/port.yaml
name: ghcr.io/my_name/my-gcc

images:
  - tags: ['my-tag']
    from: registry.hub.docker.com/library/gcc:latest

The above Port file describes that ghcr.io/my_name/my-gcc:my-tag is built from the registry.hub.docker.com/library/gcc:latest. Let's see if this parses well:

$ clade tree
registry.hub.docker.com/library/gcc:latest
        ghcr.io/my_name/my-gcc:my-tag

This is the most basic usage of CLade. How can we create a new image with that version name whenever a new version of GCC is updated? Probably the simplest way would be to populate a list of images for all versions. Alternatively, there is a way to have CLade fetch tags from the remote repository. Updates our Port file as:

# ports/my-gcc/port.yaml
name: ghcr.io/my_name/my-gcc

images:
  - tags: ( printf "%d.%d" $.Major $.Minor )
    from:
      name: registry.hub.docker.com/library/gcc
      tagd: ( tags | semverLatest )
$ clade tree
registry.hub.docker.com/library/gcc:12.2
        ghcr.io/my_name/my-gcc:12.2

What happened? Where did 12.2 come from? Let's find out one by one. First, what ( remoteTags | semverLatest ) is? This is pipeline expression. The result of the previous function becomes the argument of the next function. So it means, fetch the tags from registry.hub.docker.com, then take the latest semver. That would be 12.2 at this point. The result of the pipeline is Semver type and it is passed to pipeline in tags as a data and the result of the pipeline become result tags.

If there is more than one result of the from pipeline, CLade generates that many images. Let's create my-gcc:12.X for all gcc 12 versions using semverMajorN which filters last N major versions. Also if there are more than one tag or tag pipeline is provided, multiple tags will be created from the same image.

# ports/my-gcc/port.yaml
name: ghcr.io/my_name/my-gcc

images:
  - tags:
      - ( printf "%d.%d" $.Major $.Minor )
      - ( printf "%d"    $.Major         )
    from:
      name: registry.hub.docker.com/library/gcc
      tags: ( tags | semverMajorN 1 )
$ clade tree
registry.hub.docker.com/library/gcc:12
        ghcr.io/my_name/my-gcc:12.0
registry.hub.docker.com/library/gcc:12.1
        ghcr.io/my_name/my-gcc:12.1
registry.hub.docker.com/library/gcc:12.2
        ghcr.io/my_name/my-gcc:12.2
        ghcr.io/my_name/my-gcc:12

You can now track upstream container images. To build, you can use the clade build command. Before that, let's create a Dockerfile first.

code ports/my-gcc/Dockerfile
# ports/my-gcc/Dockerfile
ARG BASE
FROM ${BASE}

ARG USERNAME=my_name
ARG USER_UID=${UID:-1000}
ARG USER_GID=${GID:-${USER_UID}}
RUN groupadd ${USER_GID} --gid ${USER_GID} \
	&& useradd \
		--create-home ${USERNAME} \
		--shell /bin/bash \
		--uid ${USER_UID} \
		--gid ${USER_GID}

WORKDIR /home/${USERNAME}

USER ${USERNAME}

Note that argument BASE is remote container image reference. The command for the default option, clade build simply spawns docker command with proper arguments. Let's see what CLade runs:

$ clade build --dry-run ghcr.io/my_name/my-gcc:12
[/usr/bin/docker build --file /path/to/ports/my-gcc/port.yaml/Dockerfile --tag ghcr.io/my_name/my-gcc:12.2 --tag ghcr.io/my_name/my-gcc:12 --build-arg BASE=registry.hub.docker.com/library/gcc@sha256:9c9194913f48efd4c74ad2cd669b843bdea6325df71f6a32ac04fdd343bec0e0 /path/to/ports/my-gcc]

Materials

Documentation

Index

Constants

View Source
const AnnotationDerefId = "clade.deref.id"

Variables

This section is empty.

Functions

func CalcDerefId

func CalcDerefId(dgsts ...[]byte) string

func DeduplicateBySemver

func DeduplicateBySemver(lhs *[]string, rhs *[]string) error

func ResolvePath

func ResolvePath(base string, path string, fallback string) (string, error)

ResolvePath returns an absolute representation of joined path of `base` and `path`. If the joined path is not absolute, it will be joined with the current working directory to turn it into an absolute path. If the `path` is empty, the `base` is joined with `fallback`.

Types

type BaseImage

type BaseImage struct {
	Primary     *ImageReference
	Secondaries []*ImageReference
}

func (*BaseImage) UnmarshalYAML

func (i *BaseImage) UnmarshalYAML(node *yaml.Node) error

type BoolAlgebra

type BoolAlgebra boolal.Expr

func (*BoolAlgebra) Expr

func (a *BoolAlgebra) Expr() *boolal.Expr

func (*BoolAlgebra) UnmarshalYAML

func (a *BoolAlgebra) UnmarshalYAML(node *yaml.Node) error

type BuildGraph

type BuildGraph struct {
	*graph.Graph[*ResolvedImage]
	// contains filtered or unexported fields
}

func NewBuildGraph

func NewBuildGraph() *BuildGraph

func (*BuildGraph) Put

func (g *BuildGraph) Put(image *ResolvedImage) ([]*graph.Node[*ResolvedImage], error)

func (*BuildGraph) Snapshot

func (g *BuildGraph) Snapshot() graph.Snapshot

func (*BuildGraph) TagsByName

func (g *BuildGraph) TagsByName(named reference.Named) ([]string, bool)

type BuildPlan

type BuildPlan struct {
	Iterations [][][]string `json:"iterations"`
}

func NewBuildPlan

func NewBuildPlan(bg *BuildGraph) BuildPlan

type DependencyGraph

type DependencyGraph struct {
	*graph.Graph[[]*Image]
}

func NewDependencyGraph

func NewDependencyGraph() *DependencyGraph

func (*DependencyGraph) Put

func (g *DependencyGraph) Put(image *Image) *graph.Node[[]*Image]

func (*DependencyGraph) Snapshot

func (g *DependencyGraph) Snapshot() graph.Snapshot

type Image

type Image struct {
	reference.Named `yaml:"-"`

	Skip bool                `yaml:"skip"`
	Tags []Pipeline          `yaml:"tags"`
	From BaseImage           `yaml:"from"`
	Args map[string]Pipeline `yaml:"args"`

	Dockerfile  string       `yaml:"dockerfile"`
	ContextPath string       `yaml:"context"`
	Platform    *BoolAlgebra `yaml:"platform"`
}

type ImageReference

type ImageReference struct {
	reference.Named
	Tag   *Pipeline
	Alias string
}

func (*ImageReference) FromNameTag

func (r *ImageReference) FromNameTag(name string, tag string) error

func (*ImageReference) UnmarshalYAML

func (r *ImageReference) UnmarshalYAML(node *yaml.Node) error

type Namespace

type Namespace interface {
	Repository(named reference.Named) (distribution.Repository, error)
}

type Pipeline

type Pipeline pl.Pl

func (*Pipeline) AsPl

func (p *Pipeline) AsPl() *pl.Pl

func (*Pipeline) UnmarshalYAML

func (p *Pipeline) UnmarshalYAML(node *yaml.Node) error

type Port

type Port struct {
	Name reference.Named   `yaml:"-"`
	Args map[string]string `yaml:"args"`

	Skip        bool         `yaml:"skip"`
	Dockerfile  string       `yaml:"dockerfile"`
	ContextPath string       `yaml:"context"`
	Platform    *BoolAlgebra `yaml:"platform"`

	Images []*Image
}

func ReadPort

func ReadPort(path string) (*Port, error)

ReadPort parses port file at given path. It fills empty fields in children by using fields in parent if possible according to Port rules. For example, if .Images[].Dockerfile empty, it will use .Dockerfile.

func ReadPortsFromFs

func ReadPortsFromFs(ctx context.Context, path string) ([]*Port, error)

func (*Port) UnmarshalYAML

func (p *Port) UnmarshalYAML(n *yaml.Node) error

type PortLoader

type PortLoader struct {
	Registry Namespace
}

func (*PortLoader) Expand

func (l *PortLoader) Expand(ctx context.Context, image *Image, bg *BuildGraph) ([]*ResolvedImage, error)

func (*PortLoader) Load

func (l *PortLoader) Load(ctx context.Context, bg *BuildGraph, ports []*Port) error

type ResolvedBaseImage

type ResolvedBaseImage struct {
	Primary     ResolvedImageReference
	Secondaries []ResolvedImageReference
}

func (*ResolvedBaseImage) All

type ResolvedImage

type ResolvedImage struct {
	reference.Named

	Skip bool
	Tags []string
	From *ResolvedBaseImage
	Args map[string]string

	Dockerfile  string
	ContextPath string
	Platform    *BoolAlgebra
}

func (*ResolvedImage) Tagged

func (i *ResolvedImage) Tagged() (reference.NamedTagged, error)

type ResolvedImageReference

type ResolvedImageReference struct {
	reference.NamedTagged
	Alias string
}

Directories

Path Synopsis
cmd
internal

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL