Europa: integrate core packages, separate universe
Signed-off-by: Solomon Hykes <solomon@dagger.io>
This commit is contained in:
97
europa-universe/docker/build.cue
Normal file
97
europa-universe/docker/build.cue
Normal file
@@ -0,0 +1,97 @@
|
||||
package docker
|
||||
|
||||
import (
|
||||
"dagger.io/dagger"
|
||||
"dagger.io/dagger/engine/spec/engine"
|
||||
)
|
||||
|
||||
// Modular build API for Docker containers
|
||||
#Build: {
|
||||
steps: [#Step, ...#Step]
|
||||
output: #Image
|
||||
|
||||
// Generate build DAG from linerar steps
|
||||
dag: {
|
||||
for idx, step in steps {
|
||||
// As a special case, wrap #Run into a valid step
|
||||
if step.run != _|_ {
|
||||
"\(idx)": {
|
||||
input: _
|
||||
run: step & {
|
||||
image: input
|
||||
output: rootfs: _
|
||||
}
|
||||
output: {
|
||||
config: input.config
|
||||
rootfs: run.output.rootfs
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Otherwise, just use the step as is
|
||||
if step.run == _|_ {
|
||||
"\(idx)": {
|
||||
run: false
|
||||
step
|
||||
}
|
||||
}
|
||||
|
||||
// Either way, connect input to previous output
|
||||
if idx > 0 {
|
||||
"\(idx)": input: dag["\(idx-1)"].output
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(dag) > 0 {
|
||||
output: dag["\(len(dag)-1)"].output
|
||||
}
|
||||
}
|
||||
|
||||
// A build step is anything that produces a docker image
|
||||
#Step: {
|
||||
input?: #Image
|
||||
output: #Image
|
||||
...
|
||||
} | #Run
|
||||
|
||||
// Build step that copies files into the container image
|
||||
#Copy: {
|
||||
input: #Image
|
||||
contents: dagger.#FS
|
||||
source: string | *"/"
|
||||
dest: string | *"/"
|
||||
|
||||
// Execute copy operation
|
||||
copy: engine.#Copy & {
|
||||
"input": input.rootfs
|
||||
"source": {
|
||||
root: contents
|
||||
path: source
|
||||
}
|
||||
dest: copy.dest
|
||||
}
|
||||
|
||||
output: #Image & {
|
||||
config: input.config
|
||||
rootfs: copy.output
|
||||
}
|
||||
}
|
||||
|
||||
// Build step that executes a Dockerfile
|
||||
#Dockerfile: {
|
||||
// Source directory
|
||||
source: dagger.#FS
|
||||
|
||||
// FIXME: not yet implemented
|
||||
*{
|
||||
// Look for Dockerfile in source at default path
|
||||
path: "Dockerfile"
|
||||
} | {
|
||||
// Look for Dockerfile in source at a custom path
|
||||
path: string
|
||||
} | {
|
||||
// Custom dockerfile contents
|
||||
contents: string
|
||||
}
|
||||
}
|
205
europa-universe/docker/docker.cue
Normal file
205
europa-universe/docker/docker.cue
Normal file
@@ -0,0 +1,205 @@
|
||||
// Build, ship and run Docker containers in Dagger
|
||||
package docker
|
||||
|
||||
import (
|
||||
"list"
|
||||
|
||||
"dagger.io/dagger/engine/spec/engine"
|
||||
"dagger.io/dagger"
|
||||
)
|
||||
|
||||
// A container image
|
||||
#Image: {
|
||||
// Root filesystem of the image.
|
||||
rootfs: dagger.#FS
|
||||
|
||||
// Image config
|
||||
config: engine.#ImageConfig
|
||||
}
|
||||
|
||||
// Run a command in a container
|
||||
#Run: {
|
||||
run: true // FIXME
|
||||
image: #Image
|
||||
|
||||
always: bool | *false
|
||||
|
||||
// Filesystem mounts
|
||||
mounts: [name=string]: engine.#Mount
|
||||
|
||||
// Expose network ports
|
||||
ports: [name=string]: {
|
||||
frontend: dagger.#Service
|
||||
backend: {
|
||||
protocol: *"tcp" | "udp"
|
||||
address: string
|
||||
}
|
||||
}
|
||||
|
||||
// Command to execute
|
||||
cmd: {
|
||||
// Name of the command to execute
|
||||
// Examples: "ls", "/bin/bash"
|
||||
name: string
|
||||
|
||||
// Positional arguments to the command
|
||||
// Examples: ["/tmp"]
|
||||
args: [...string]
|
||||
|
||||
// Command-line flags represented in a civilized form
|
||||
// Example: {"-l": true, "-c": "echo hello world"}
|
||||
flags: [string]: (string | true)
|
||||
|
||||
_flatFlags: list.FlattenN([
|
||||
for k, v in flags {
|
||||
if (v & bool) != _|_ {
|
||||
[k]
|
||||
}
|
||||
if (v & string) != _|_ {
|
||||
[k, v]
|
||||
}
|
||||
},
|
||||
], 1)
|
||||
}
|
||||
|
||||
// Optionally pass a script to interpret
|
||||
// Example: "echo hello\necho world"
|
||||
script?: string
|
||||
if script != _|_ {
|
||||
// Default interpreter is /bin/sh -c
|
||||
cmd: *{
|
||||
name: "/bin/sh"
|
||||
flags: "-c": script
|
||||
} | {}
|
||||
}
|
||||
|
||||
// Environment variables
|
||||
// Example: {"DEBUG": "1"}
|
||||
env: [string]: string
|
||||
|
||||
// Working directory for the command
|
||||
// Example: "/src"
|
||||
workdir: string | *"/"
|
||||
|
||||
// Username or UID to ad
|
||||
// User identity for this command
|
||||
// Examples: "root", "0", "1002"
|
||||
user: string
|
||||
|
||||
// Optionally attach to command standard streams
|
||||
stdin: dagger.#Stream | *null
|
||||
stdout: dagger.#Stream | *null
|
||||
stderr: dagger.#Stream | *null
|
||||
|
||||
// Output fields
|
||||
{
|
||||
// Has the command completed?
|
||||
completed: bool & (_exec.exit != _|_)
|
||||
|
||||
// Was completion successful?
|
||||
success: bool & (_exec.exit == 0)
|
||||
|
||||
// Details on error, if any
|
||||
error: {
|
||||
// Error code
|
||||
code: _exec.exit
|
||||
|
||||
// Error message
|
||||
message: string | *null
|
||||
}
|
||||
|
||||
output: {
|
||||
rootfs?: dagger.#FS & _exec.output
|
||||
files: [path=string]: {
|
||||
contents: string
|
||||
contents: _read.contents
|
||||
|
||||
_read: engine.#ReadFile & {
|
||||
input: _exec.output
|
||||
"path": path
|
||||
}
|
||||
}
|
||||
directories: [path=string]: {
|
||||
contents: dagger.#FS
|
||||
contents: (dagger.#Subdir & {
|
||||
input: _exec.output
|
||||
"path": path
|
||||
}).output
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Actually execute the command
|
||||
_exec: engine.#Exec & {
|
||||
args: [cmd.name] + cmd._flatFlags + cmd.args
|
||||
input: image.rootfs
|
||||
"mounts": [ for mnt in mounts {mnt}]
|
||||
environ: [ for k, v in env {"\(k)=\(v)"}]
|
||||
"workdir": workdir
|
||||
"stdin": stdin
|
||||
// FIXME: user
|
||||
}
|
||||
}
|
||||
|
||||
// A ref is an address for a remote container image
|
||||
// Examples:
|
||||
// - "index.docker.io/dagger"
|
||||
// - "dagger"
|
||||
// - "index.docker.io/dagger:latest"
|
||||
// - "index.docker.io/dagger:latest@sha256:a89cb097693dd354de598d279c304a1c73ee550fbfff6d9ee515568e0c749cfe"
|
||||
#Ref: engine.#Ref
|
||||
|
||||
// Download an image from a remote registry
|
||||
#Pull: {
|
||||
// Source ref.
|
||||
source: #Ref
|
||||
|
||||
// Registry authentication
|
||||
// Key must be registry address, for example "index.docker.io"
|
||||
auth: [registry=string]: {
|
||||
username: string
|
||||
secret: dagger.#Secret
|
||||
}
|
||||
|
||||
_op: engine.#Pull & {
|
||||
"source": source
|
||||
"auth": [ for target, creds in auth {
|
||||
"target": target
|
||||
creds
|
||||
}]
|
||||
}
|
||||
|
||||
// Downloaded image
|
||||
image: #Image & {
|
||||
rootfs: _op.output
|
||||
config: _op.config
|
||||
}
|
||||
|
||||
// FIXME: compat with Build API
|
||||
output: image
|
||||
}
|
||||
|
||||
// Upload an image to a remote repository
|
||||
#Push: {
|
||||
// Destination ref
|
||||
dest: #Ref
|
||||
|
||||
// Complete ref after pushing (including digest)
|
||||
result: #Ref & _push.result
|
||||
|
||||
// Registry authentication
|
||||
// Key must be registry address
|
||||
auth: [registry=string]: {
|
||||
username: string
|
||||
secret: dagger.#Secret
|
||||
}
|
||||
|
||||
// Image to push
|
||||
image: #Image
|
||||
|
||||
_push: engine.#Push & {
|
||||
dest: dest
|
||||
input: image.rootfs
|
||||
config: image.config
|
||||
}
|
||||
}
|
15
europa-universe/docker/test/bash/bash.cue
Normal file
15
europa-universe/docker/test/bash/bash.cue
Normal file
@@ -0,0 +1,15 @@
|
||||
package docker
|
||||
|
||||
cmd: #Command & {
|
||||
script: "echo hello world"
|
||||
exec: {
|
||||
name: "/bin/bash"
|
||||
flags: {
|
||||
"-c": script
|
||||
"--noprofile": true
|
||||
"--norc": true
|
||||
"-e": true
|
||||
"-o": "pipefail"
|
||||
}
|
||||
}
|
||||
}
|
82
europa-universe/docker/test/build/build.cue
Normal file
82
europa-universe/docker/test/build/build.cue
Normal file
@@ -0,0 +1,82 @@
|
||||
package docker
|
||||
|
||||
import (
|
||||
"dagger.io/dagger"
|
||||
"universe.dagger.io/nginx"
|
||||
)
|
||||
|
||||
build0: #Build & {
|
||||
steps: [
|
||||
{
|
||||
output: #Image & {
|
||||
config: user: "foo"
|
||||
}
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
// Inventory of real-world build use cases
|
||||
//
|
||||
// 1. Build netlify image
|
||||
// - import alpine base
|
||||
// - execute 'yarn add netlify'
|
||||
|
||||
// 2. Build todoapp dev image
|
||||
// - import nginx base
|
||||
// - copy app directory into /usr/share/nginx/html
|
||||
|
||||
build2: {
|
||||
source: dagger.#FS
|
||||
|
||||
build: #Build & {
|
||||
steps: [
|
||||
nginx.#Build & {
|
||||
flavor: "alpine"
|
||||
},
|
||||
{
|
||||
// Custom step to watermark the image
|
||||
input: _
|
||||
output: input & {
|
||||
config: user: "42"
|
||||
}
|
||||
},
|
||||
#Copy & {
|
||||
contents: source
|
||||
dest: "/usr/share/nginx/html"
|
||||
},
|
||||
]
|
||||
}
|
||||
img: build.output
|
||||
|
||||
// Assert:
|
||||
img: config: user: "42"
|
||||
}
|
||||
|
||||
// 3. Build alpine base image
|
||||
// - pull from docker hub
|
||||
// - execute 'apk add' once per package
|
||||
|
||||
// 4. Build app from dockerfile
|
||||
|
||||
// 5. execute several commands in a row
|
||||
|
||||
build3: {
|
||||
build: #Build & {
|
||||
steps: [
|
||||
#Pull & {
|
||||
source: "alpine"
|
||||
},
|
||||
#Run & {
|
||||
script: "echo A > /A.txt"
|
||||
},
|
||||
#Run & {
|
||||
script: "echo B > /B.txt"
|
||||
},
|
||||
#Run & {
|
||||
script: "echo C > /C.txt"
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
result: build.output
|
||||
}
|
Reference in New Issue
Block a user