#Simplify code with custom type
1 messages · Page 1 of 1 (latest)
Sorry if I misunderstood what you want to do. For maximum simplicity, personally I would do this:
type RedhatMinimal struct {}
func (*RedhatMinimal) Container(base *Container, packages []string) *Container {
return base.
WithExec(append([]string{"microdnf", "install", "--nodocs", "--setopt", "install_weak_deps=0", "--assumeyes"}, packages...)).
WithExec([]string{"microdnf", "clean", "all"})
}
For maximum convenience, you can add default values for both base and packages.
type RedhatMinimal struct {}
// Build a minimal Red Hat container
func (*RedhatMinimal) Container(
// Custom base image
// +optional
base *Container,
// System packages to install
// +optional
packages []string,
) *Container {
if base == nil {
base = dag.Container().From("docker.io/redhat/ubi8")
}
if packages == nil {
return base
}
return base.
WithExec(append([]string{"microdnf", "install", "--nodocs", "--setopt", "install_weak_deps=0", "--assumeyes"}, packages...)).
WithExec([]string{"microdnf", "clean", "all"})
}
Here's an example of a module I wrote (Wolfi) that follows the same pattern: https://daggerverse.dev/mod/github.com/shykes/daggerverse/wolfi
Usage example
dagger call -m github.com/shykes/daggerverse/wolfi \
container --packages=git,openssh \
terminal
Hi @paper fjord, thanks for your detailed answer! That’s the approach I tested first, but I found it not that flexible for what I’d like to do. For a better view of what I’m currently doing, here is my Daggerverse: https://github.com/camptocamp/daggerverse. I’ve a Redhat module to get UBI images and customize them, a Nodejs module to install Node.js on an UBI image, a Golang module to install Go on an UBI image, and a Documentation module which uses the Nodejs and Golang modules to install Node.js and Go on an UBI image. My current approach allows me to use chaining: https://github.com/camptocamp/daggerverse/blob/0eee0f9a9db5df12b7900819d9b4df83cb39c8a7/documentation/main.go#L51-L58 and https://github.com/camptocamp/daggerverse/blob/0eee0f9a9db5df12b7900819d9b4df83cb39c8a7/nodejs/main.go#L24-L30. However, I don’t know if this is good nor idiomatic Dagger code.
Ah, I see!
Two things here:
-
It's fair to say we're all still figuring out best practices for this platform, so as long as your approach works for you, that's enough to call it good 🙂
-
Speaking for myself: in your situation, where you want to carry a little more state around, and not just pass everything as arguments every time (like I did in my example): I think I would create custom types wrapping a
Container, one for each specialized container. Then when I need to access the raw container object, simply have a function return that.
I'm busy right now, but later today I'll try to write a quick example of what I mean
I personally try to avoid relying on With(), because it doesn't actually use the Dagger API, it's an SDK-specific convenience. I find that with Functions, I no longer feel the need for it