#go
1 messages · Page 2 of 1
thanks
Or am I misreading the wipe docs
If false (the default), the contents of the directory will be merged with any existing contents of the host directory, leaving any existing files on the host that aren't in the exported directory alone.
will be merged with any existing contents of the host directory implies to me that changes being exported would overwrite existing files (merge).
Hmmm .... https://docs.dagger.io/api/chaining/#export-directories-files-and-containers
says but it does not modify or delete any files that already exist at that host path.
That's correct. It just won't delete files on the host that aren't on the exported directory. That's what wipe is for. It's like a sync that makes sure the files on the host matches the ones in the exported directory.
Wipe wipes everythinhg though
so I can't use Diff(<original src>)
to export only changes overwritting local contents
If you diff, and only one file changed, then wipe will delete all other files because you're basically exporting a directory with a single file.
exactly
AFAICT I can't do what I was trying to do then.
@tawny carbon that wipes everything excluded though at least.
True, if you have a filtered directory.
I have to ... .git is ~1GB
and there are also other previous build stuff often in random locations not worth uploading.
Yeah, we'd need something more in the API to wipe using the same filters or base set of files to compare.
--overwrite as an option to export would suffice for me
Wait ... now it seems to be overwritting. WTh?
export --path=. vs export --path=./
I apparently have no idea what I'm doing
Interestingly export --path=. without the Diff(<original directory>) works and does overwrite local files the way I would expect. With Diff(<original directory>) it doesn't.
How do I construct a *dagger.Secret in go code?
https://pkg.go.dev/dagger.io/dagger#Client.SetSecret. In a module you can do dag.SetSecret()
Can I pass a default for a []string ? If so, how?
I guess I could take a csv string and split it
yes I believe +default=["foo","bar","baz"] as a special "pragma" comment will do it
doesn't seem to work
or at least I'm pretty sure I tried that
Another question though ... How do I debug print something?
I'm not talking about https://docs.dagger.io/features/debugging/
I need to see a value
normally a good old printf should work. It will show up in your trace.
-
dagger --no-exitto navigate the trace interactively even after the call completes -
dagger -wto open the trace interactively even after a web view
somehow this now works, when I'm sure it wasn't earlier.
I had to go through this same exercise when defaulting a slice of strings. It's not super intuitive because other defaults require it to be within quotes (valid json). Even a boolean has to be quoted. But the slice should not be. If you quote the slice you get a weird error. This is where I went to look or an example https://docs.dagger.io/api/arguments/#default-values but couldn't find one. I think there should be examples of each type of default there. I'll open an issue
@rocky karma the point was precisely to require valid json, to make it easier to remember:
- string: json-encoded string eg.
"foo" - array: json-encoded array eg.
["foo", "bar"]
Learning Go (with Dagger)... How do I print output to stdout from Go when the module doesn't error? Tried a few fmt. and nothing actually prints to stdout?
Seems to only show in cloud, not in terminal
It is included in the logs in the trace view. That's what you see in the terminal while the command is running. You can navigate the trace interactively with the keyboard, it's the same data as in the web view.
You can use dagger --no-exit or dagger -E to keep the trace view open even after the command completes
You can also dagger --progress=plain for a more traditional flat log
Didn't know about this flag, that's helpful
I'm getting this error unless I add the source arg to Build directly: ! required flag(s) "source" not set. Am I getting this wrong?
type App struct {Source *dagger.Directory}
func New(source *dagger.Directory) *App {return &App{Source: source}}
func (m *App) Build() *dagger.Container {
return dag.Container().
From("golang:1.23").
WithMountedDirectory("/src", m.Source)
}
I'm getting this error unless I add the
I guess maps aren't supported?
error calling ModuleMainSrc: failed to parse field type: unsupported type for named type reference *types.Map
No idea if it's gonna make sense, but I started something here: https://github.com/sagikazarmark/dagx
Contribute to sagikazarmark/dagx development by creating an account on GitHub.
Makes sense to me! For the pipeline one you've built so far, we have an issue for a similar proposal that I'm still hoping becomes a reality but it hasn't happened yet https://github.com/dagger/dagger/issues/5083
it make sense for me as well.
Thanks for sharing this! What are your thoughts on telemetry with respect to this? I have something similar that starts a span for each 'step'.
I guess that makes sense. I haven't had much thought on telemetry since the Pipeline command was removed, but it would be interesting to see how that concept could be built into telemetry.
It makes sense, indeed. Some time ago, I started a similar effort here: https://github.com/Excoriate/daggerx (it has a broader scope, though)
DaggerX is a Go package 📦 that helps you avoid DRY while developing Dagger modules. - Excoriate/daggerx
So, last night (EMEA) my Dagger pipelines started failing again.
Error: bootstrap package: existing go.mod has unsupported version 1.22.5 (highest supported version is 1.22.3)
I pinned my CI image version to golang:1.22.2-alpine and dagger to DAGGER_VERSION=0.11.6.
I'm building with [attached screenshot] and getting the error (see screenshot)
What's changed? In the evening (8:00pm UTC) pipelines were OK. During the night (1:15am UTC) AMER folks started complaining. Nothing changed on my side (I'm vacation)
What happened and how do I recover?
So, last night (EMEA) my Dagger
Im using dagger in conjunction with mage.
Running the following command is returning an error:
dagger run -d go run -mod=mod mage.go -v release:all
invalid argument "mod" for "-d, --debug" flag: strconv.ParseBool: parsing "mod": invalid syntax
It seems dagger does not like the "-mod=mod" go run option.
Hopefully someone else has run into this before. Any help/insight would be great.
Does this work?
dagger run -d -- go run -mod=mod mage.go -v release:all
Thanks Solomon, that did work locally. However I ended up installing mage in my pipeline and executing the mage binary and that fixed the issue. 
hi i got my gitlab pipeline #gitlab message
-
using own dagger engine very simple setting ENV proxy
-
im behind corporate proxy with no access to internet
-
my problem was described on image1.png and later in that log was error with connect to proxy.golang.org image2.png
-
i thought if im using typescript SDK module then ill be not using GO but it seems yes
-
okay so i googled a bit and i needed GOPROXY to download deps because i have no access to proxy.golang.org
-
so i created my nexus proxy repo for golang
-
i set _DAGGER_ENGINE_SYSTEMENV_GOPROXY=nexus.proxy.dev/repo/golang-something
-
it started using proxy and downloaded some packages which are present in nexus proxy repo
-
which moved my error a bit further image3.png
-
in nexus documentation i found i can do 2 things either set GOSUMDB param to go environment https://help.sonatype.com/en/go-repositories.html#sumdb
-
or use GOPRIVATE env variable https://go.dev/ref/mod#environment-variables
my problem is i need to set it for go like :
go env -w GOPROXY=https://nexus.example.com/repository/golang-proxy
go env -w 'GOSUMDB=sum.golang.org https://nexus.example.com/repository/golang-sum-proxy'
go env -w 'GOPRIVATE=golang.org/*'
but all my attempts to set it to go inside dagger engine are not working because as i see it right dagger engine handles only env variable _DAGGER_ENGINE_SYSTEMENV_GOPROXY
Am i missing something ?
my Dockerfile which is building dagger engine
FROM harbor.company/proxy-dagger/engine:v0.14.0
# Set Go environment variables
ENV GOPROXY=https://nexus.company/repository/go-proxy
ENV _DAGGER_ENGINE_SYSTEMENV_GOPROXY=https://nexus.company/repository/go-proxy
ENV GOSUMDB='sum.golang.org https://nexus.company/repository/golang-sum-proxy'
#ENV GOPRIVATE=golang.org/*
ENV http_proxy=http://proxy.company:8080
ENV https_proxy=http://proxy.company:8080
ENV no_proxy=company.dev
hey guys! I'm new to Dagger, and as a part of a college class, I'm defining a pipeline to test, format and run code coverage for a Rust application (I'm re-writing the GitHub pipeline from the 'Zero to Production in Rust' book). I started with just the test stage, as you can see on the images below, and when I try to run the installation of the sqlx-cli, the pipeline cannot grab the environment variables previously defined. How can I use them properly on the pipeline?
Hey! Welcome, is there a reason you're not writing a dagger module? (i.e. the thing you would get from dagger init)
The biggest benefit of dagger modules is that they support interactive debugging, so you'd be able to call this function and pipe terminal into it and see what environment variables are set
If you do use a module, then I'd suggest using a constructor to create these config values, this way they are available any subsequent function. You can set defaults and then override them if needed later on
👋 seems like we need to add the GOPRIVATE and GOSUMDB (and potentially other) variables here https://github.com/marcosnils/dagger/blob/8c0cefb0e8d3f16307e7c93c2a11e9095d501fed/core/schema/sdk.go?plain=1#L781 . @stray halo happy to help you building a patched version of the engine next week if that's an option for you to continue your tests until we can officially release this change 🙏
lacking a lot of basics of Dagger… thanks for the guidance, the only reason was me not getting familiar with it, I will do this
No problem at all, we're here to help! Please don't hesitate to ask any other questions you run into.
lovely, thanks!
Hi eveyone should we push the daggers auto generate bindings present inside the internal/ folder to the VCS?
I think its safe to ignore this, its going to be recreated when dagger runs and is ignored by default in the .gitignore. Unless you have a specific reason you want to include these, I would leave the default behavior to ignore these.
Yeah, it's a matter of personal taste. The default is to ignore them as Lev said. You can safely un-ignore them if you want, either way the Dagger runtime will re-generate them in the container. The decision only affects your own dev workflow.
Thanks 😊
i have a pattern question related to long streams of args and chaining command.
I'm guessing i don't really have a better option than having multiple functions sharing the same stream of args: ?
// Build returns a go binary that can fetch private deps
func (m Module) Build (src *dagger.Directory, username, pwd *dagger.Secret, goprivate []string) *dagger.File
// DockerBuild returns a configured fresh alpine docker container with the binary
func (m Module) DockerBuild(binary *dagger.File) *dagger.Container
// Here i have to call all the parameters from the build command to effectively chain the build and the docker build command
func (m Module) DockerBuildButIHaveToChainEverything(src *dagger.Directory, username, pwd *dagger.Secret, goprivate []string) *dagger.Container{
b := m.Build(src,username,pwd,goprivate)
db := m.DockerBuild(b)
}
Actual usage:
username=riri password=fifi dagger call docker-build-but-i-have-to-chain-everything src=. username=env:username password=env:password goprivate=loulou
I could use a bespoke OptBuildOption struct but then i would loose the ability to call the function from the cli if i ever want to extract the binary on the host and i would then probably stop exporting the build command all together...:
username=riri password=fifi dagger call build src=. username=env:username password=env:password goprivate=loulou export path=./my_bin
You can attach values to the state of your custom types (including your Module type), then all your functions can use the fields, like regular object programming.
You can set the arguments in the module's constructor: func New(/* args go here */) Module { /* initialize fields here */)
oh that's super neat
i was kinda scratching my head a little bit thinking of how i would implement default values like
- source should by default be the root of the git repo
- output of a build should go in $PWD/bin
i would end up with a makefile for dagger which sounds like an antipattern when you think about the tool
Also note that you can make arguments optional, when it makes sense. So you don't have to specify src=. every time. You can reference a default path for src, it can be any path within the same git repo as your module
awesome thanks
func New(
// +optional
// +defaultPath="."
// +ignore=["node_modules", "bin/*"]
src *dagger.Directory,
) Module {
return Module{
Src: Src,
}
}
This will default src to the root directory of the module (the directory containing dagger.json). You can also ignore certain paths with +ignore
that's really really good
been away from dagger for a couple months, the doc made leaps forward
If you want to look at a production module, this one is pretty good: https://github.com/dagger/dagger/blob/main/modules/go/main.go
It has a good balance of cleanness (recently refactored) and utility (we use it to build dagger)
thanks a lot :D
yeah i was browsing the daggerverse for ideas but this also fits nicely
You can also maintain a separate struct/s to pass around data instead of passing each argument. The nice thing about that is you can actually attach dagger functions to that secondary struct. That way you can enforce certain patterns within your code by chaining dagger objects. Here's an example https://github.com/dagger/dagger/blob/main/modules/golangci/lint.go#L43.
HI, i have an issue with building typescript project
package main
import (
)
type MyProject struct{}
func (m *MyProject) BuildEnv(source *Directory) *Container {
return dag.Container().
From("node:14.15.5").
WithDirectory("/src", source).
WithWorkdir("/src").
WithExec([]string{"npm", "install"})
}
func (m *MyProject) BuildDist(source *Directory, env string) *Directory {
return m.BuildEnv(source).
WithExec([]string{"npm", "run", "build-" + env})
WithExec([]string{"mkdir", "./zip"}).
WithExec([]string{"tar", "-czvf", "./zip/front_artifact.tar.gz", "-C", "dist", "."}).
Directory("./zip")
}
Without dagger there is no problem
But with dagger :
DeprecationWarning: 'createExpressionStatement' has been deprecated since v4.0.0. Use
┃ (node:64) UnhandledPromiseRejectionWarning: Error: write EPIPE
┃ at process.target._send (internal/child_process.js:832:20)
┃ at process.target.send (internal/child_process.js:703:19)
┃ at file:///src/node_modules/@angular/compiler-cli/bundles/chunk-D5CHHDFQ.js:4995:1
┃ at new Promise (<anonymous>)
┃ at sendMessageToMaster (file:///src/node_modules/@angular/compiler-cli/bundles/chu
┃ at Worker.<anonymous> (file:///src/node_modules/@angular/compiler-cli/bundles/ngcc
┃ at Worker.emit (events.js:315:20)
┃ at process.<anonymous> (internal/cluster/worker.js:33:12)
┃ at process.emit (events.js:315:20)
┃ at emit (internal/child_process.js:903:12)
┃ (Use `node --trace-warnings ...` to show where the warning was created)
┃ (node:64) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error or
┃ handled with .catch(). To terminate the node process on unhandled promise rejection, u
┃ ejection id: 1)
┃ (node:64) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. I
┃ (node:75) UnhandledPromiseRejectionWarning: Error: write EPIPE
┃ at process.target._send (internal/child_process.js:832:20)
┃ at process.target.send (internal/child_process.js:703:19)
┃ at file:///src/node_modules/@angular/compiler-cli/bundles/chunk-D5CHHDFQ.js:4995:1
┃ at new Promise (<anonymous>)
┃ at sendMessageToMaster (file:///src/node_modules/@angular/compiler-cli/bundles/chu
┃ at Worker.<anonymous> (file:///src/node_modules/@angular/compiler-cli/bundles/ngcc
┃ at Worker.emit (events.js:315:20)
┃ at process.<anonymous> (internal/cluster/worker.js:33:12)
┃ at process.emit (events.js:315:20)
┃ at emit (internal/child_process.js:903:12)
Could you help me to fix this issue ?
After some search its not coming from dagger !
Hello, just read the article about migrating to go-app. Can someone explain me that part please?
We tried to perform Brotli compression on-the-fly in our CDN but the file was too large, so eventually we just included the compression step into our build process.
Who compresses and decompresses the wasm file and where it is happening?
Is it the browser who decompresses brotil by itself? And your cdn is who returns compressed wasm file?
I'm curious as well; I occasionally see v3 traces eat my CPU alive (full spec M1 MAX) (though I am using firefox).
Yeah - our CI job compresses and uploads it, and our CDN serves it and your browser decompresses it via the usual content encoding headers
Unlikely to be compression related, but viewing a running trace is still pretty cpu intensive ATM depending on how many spans/calls are visible
Hello !
I am trying to walk a Directory hierarchy with
entries, err := dir.Entries(ctx)
But I cannot know whether an entry refers to a directory or a regular file 😐
Is there a way to achieve a file hierarchy walk? thanks.
ahhh i also had this problem 🙂 i tried proposing this: https://github.com/dagger/dagger/pull/9118
i'm still a bit on the fence as to whether the idea is good - wdyt?
I'd still love to have it 🙂
yeah 😦 i think my motivation for it died in a hole of fixing all the tests that rely on it
probably just need to power through
Thanks a lot Jed! Sorry for the late reply.
I am glad to see I am not the only one asking for this.
Regarding your PR, it is fine by me, but the question is "would this API change break things for some existing pipelines, and if yes, are we ok with it?"
TBH I did not find the time to ponder this yet, but would it be a good idea to have an .Entries() alternative that returns an array of "info" structs instead of an array of strings?
🤔
yeaaa, we can break a few things i think - i probably just to revive it, i might spend a little time this week on it
returning an info array would be cool - the problem is, under our current model, it'll be horribly inefficient 😦
so probably needs a bit more thought
🤔 🤔 @tawny carbon @pure flare wdyt about the idea of marking certain fields in the graphql schema as "pre-fetchable" (using a graphql directive) - an sdk codegen could then add those to the query out of the box, and just attach them as fields (instead of as functions that need await/context).
then, we could have this little info struct that could be efficiently returned
unrelated, but typescript compiler is now written in go instead of typescript for performance. I wonder if that has any performance improvements on the typescript sdk?
🤔 probably one for @tender marsh 👀
I'm guessing the runtime is more of a bottleneck than the compiler but thought of sharing anyway
Anders Hejlsberg, lead architect of TypeScript and Technical Fellow at Microsoft, introduces a new port of TypeScript that will deliver the next generation of high-performance developer tooling.
Hello
I’m wondering what is the best way to handle go mod cache in a project with go sdk.
I have currently 3 dagger function
-
Buildenv: which create the container with mounted cache.etc
-
Lint: which do the go vet
-
Build: which go build the app
All chained
My issue is that any modification of the src code is relaunching go vet (expected) but it re pull every dependendies every time.
Hello! I recommend taking a look at our own implementation (we use it to build dagger) https://github.com/dagger/dagger/blob/main/modules/go/main.go
Thanks Solomon. I will have a look
Hey there! Is it possible to compose a dagger modules from another one using go struct embedding?
I've tried:
type Gateway struct {
//+private
*dagger.Go
}
But in order to have functions available at the Gateway level, I need to redefine them. It's not a blocker, it's just a bit repetitive, and I'm pretty sure I'm missing something obvious to achieve this pattern.
you can't do that today, but it has been proposed! https://github.com/dagger/dagger/issues/7528
Well, I should rtfm before asking question already answered 😅 . Sorry I looked up here but not on GitHub. Subscribed, thanks!
nah, no worries, i just have a good memory for what issues "exist" in the github somewhere 😛
Is support for go 1.24 planned? I couldnt find it anywhere and want to upgrade as soon as possible since snyk gives us quite some critical vulns on 1.23.8
yes we do need this 😦 unfortunately, we need https://github.com/golang/go/issues/73144
without this, the engine segfaults very reliably 😦
so we're blocked on a 1.24.3 release
actually. 🤔 looks like alpine has backported the fix
doesn't seem like wolfi currently does though, which is what we're using for our build (though maybe we might be able to switch)
no, 1.24.0-1.24.2 are broken with this bug - it's fixed on trunk, and marked for cherry-pick into 1.24.3, but 1.24.3 has not been released yet
aha ok
That means ill have to wait for 1.24.3 to be released before fixing my vulnerabilities
some more context in https://github.com/dagger/dagger/issues/9759
I'm facing an issue where all the values I provide on module level via arguments end up as empty.
type Platform struct {
terraformVersion string
awsAccessKeyID *dagger.Secret
awsSecretAccessKey *dagger.Secret
awsSessionToken *dagger.Secret
}
func New(
// the version of the Terraform image to use
// +default="1.5.7"
terraformVersion string,
// the AWS access key ID
awsAccessKeyID *dagger.Secret,
// the AWS secret access key
awsSecretAccessKey *dagger.Secret,
// the AWS session token
awsSessionToken *dagger.Secret,
) (*Platform, error) {
p := &Platform{
terraformVersion: terraformVersion,
awsAccessKeyID: awsAccessKeyID,
awsSecretAccessKey: awsSecretAccessKey,
awsSessionToken: awsSessionToken,
}
return p, nil
}
// AwsContainer returns a container with the AWS CLI installed.
func (m *Platform) AwsContainer(
ctx context.Context,
// +default="latest"
awsCliVersion string,
env *dagger.Directory,
) (*dagger.Container, error) {
slog.Info("AWS CLI version", slog.String("version", awsCliVersion))
return dag.Container().
From(fmt.Sprintf("amazon/aws-cli:%s", awsCliVersion)).
WithEnvVariable("AWS_DEFAULT_REGION", "us-east-1").
WithEnvVariable("TERRAFORM_VERSION", m.terraformVersion).
// WithSecretVariable("AWS_ACCESS_KEY_ID", m.awsAccessKeyID).
// WithSecretVariable("AWS_SECRET_ACCESS_KEY", m.awsSecretAccessKey).
// WithSecretVariable("AWS_SESSION_TOKEN", m.awsSessionToken).
WithMountedDirectory("/env", env).
WithWorkdir("/env"), nil
}
Now when I call the module like this it just fails as all the arguments and the defaults are not set on my module
dagger call --aws-access-key-id=env://AWS_ACCESS_KEY_ID --aws-secret-access-key=env://AWS_SECRET_ACCESS_KEY --aws-session-token=env://AWS_SESSION_TOKEN aws-container --env environments terminal
I'm running using the latest dagger cli dagger v0.18.6 (docker-image://registry.dagger.io/engine:v0.18.6) darwin/arm64
What am I doing wrong? I want to have those settings globally because I want to have multiple functions that depend on the same secrets. All the secrets are nil and the terraformVersion is an empty string"".
dagger call --help
✔ connect 0.1s
✔ load module 0.7s
✔ parsing command line arguments 0.0s
Call one or more functions, interconnected into a pipeline
USAGE
dagger call [options] [arguments] <function>
FUNCTIONS
aws-container AwsContainer returns a container with the AWS CLI installed.
terraform-container -
terraform-environment -
ARGUMENTS
--aws-access-key-id Secret the AWS access key ID
[required]
--aws-secret-access-key Secret the AWS secret access key
[required]
--aws-session-token Secret the AWS session token
[required]
--terraform-version string
the version of the Terraform image to use
(default "1.5.7")
I also filed it as a issue on the repo https://github.com/dagger/dagger/issues/10347 maybe it is a mistake from my side, but might be very well a bug on dagger side as well 🤔
responded to your issue, might be a simple fix https://github.com/dagger/dagger/issues/10347#issuecomment-2859014774
What happened? What did you expect to happen? I have following module. type Platform struct { terraformVersion string awsAccessKeyID *dagger.Secret awsSecretAccessKey *dagger.Secret awsSessionToken...
I just realize that Socket type in https://github.com/dagger/dagger/blob/main/sdk/go/dagger.gen.go#L9342 has no UnmarshalJSON method but it has in dagger.gen.go that generated from Dagger module (dagger develop, dagger init). Is it a bug?
Hi everybody, long time no see! 👋
Is there a pattern for module development where you augment a container through a method.
Let's say : I have a *dagger.Container but I'd like to add some more things to it (files, exec some commands, etc) and return the augmented *dagger.Container.
Right now, I'm doing
func (m *Module) WithAndroidSDK(ctr *dagger.Container) *dagger.Container {}
func main() {
ctr := dag.Container().From("golang:1.24)
ctrWithAndroid := dag.Module().WithAndroidSDK(ctr)
I'd love to be able to chain this like
dag.Container().From("golang:1.24").WithAndroidSDK(ctr)
But that would mean it would extend the Container API, not just the *dagger.Client
I'm experimenting with it, but I'm not completely satisfied with my current API.
Forget about me. It's Container.With that would suit it best 🙂. Asking the question triggered a memory.
I guess rubber duck FTW.
@astral lotus good to see you!
Quick reminder that Container.With is SDK-specific so only for internal use inside your module. You can't eg. return an extended container to another module. The with also won't show up in traces as an operation.
Thanks, good to know!
I got surprised trying to modularize a dagger script. And for that, I was chaining operation that would return a new struct
type Ubuntu struct{}
func (u *Ubuntu) WithGo() *Go { /* ... */ }
type Go struct{}
func (g *Go) WithAndroid() *Android { /* ... */ }
type Android struct{}
func (a *Android) BuildAPK() *dagger.File { /* ... */ }
But this didn't work because the subsequent calls were from a nil pointer. So
dagger call with-go with-android build-apk
failed because WithAndroid was called with (g *Go) being nil
As I wanted to create a module for Go, and a module for Android, how would you make them composable in that idea?
Hey 👋 That structure looks right, so maybe there's another detail missing?
I've done this type of chaining and it works. in your case @astral lotus , if your module is named Ubuntu you won't be able to chain call Android without first using Ubuntu as entrypoint. Intermediate structs can only be called if they were returned first from the main module. If that makes sense. But looks like that's what you are doing so, it should work.
Ok, there clearly must have been a mistake somewhere then 🙂
Anyway, I'm using With and it seems to work between modules ( is that was not supported @violet cosmos ?)
With takes a https://pkg.go.dev/dagger.io/dagger#WithContainerFunc. You can't return a WithContainerFunc from one module and use it in another. Dagger doesn't know how to serialize it.
Oh, I see!
Well I guess I didn't use it the wrong way then 🙂
Ok, I've refactored everything I needed to build my app and now, I can build a full android app with Fyne (native mobile app in Go)
return dag.Fyne().BuildApk(
source,
"<appID>",
"android/arm64",
"./cmd/app/",
"./cmd/app/app.apk",
)
And all I need is in https://github.com/dolanor/daggerverse/
How do you pass a directory arg in Go? In Python it's just a string that automagically becomes a dir, but doing the same in Go results in cannot use "./fixtures" (untyped string constant) as *dagger.Directory value
normally, it's just a string.
Is this fixtures in your repository or your build context ?
Repository
is it an optional parameter? Or is it positional?
Can you do a
dagger call my-function --help
?
It is optional with a default value yes
do you have a code snippet?
func (m *DockerBuilder) BuildImage(
// Dockerfile path
Dir *dagger.Directory,
// Dockerfile name
// +default="Dockerfile"
File string,
) (*dagger.Container, error) {
ctr := Dir.DockerBuild(dagger.DirectoryDockerBuildOpts{
Dockerfile: File,
})
return ctr, nil
}
_, err := dag.DockerBuilder().BuildImage("./fixtures")
-> cannot use "./fixtures" (untyped string constant) as *dagger.Directory value in argument to dag.DockerBuilder().BuildImage compiler (IncompatibleAssign) [22, 43]
(I'm quite new to the Go SDK having moved over from Python, I may be making rookie mistakes)
(Possibly related issue: assignment mismatch: 2 variables but dag.DockerBuilder().BuildImage returns 1 value compiler (WrongAssignCount) [22, 12] -> BuildImage returns two values, not sure why this isn't working, see #general message. The second snippet dag.DockerBuilder... is in a test submodule)
Even for a string type?
It works in a Dagger shell with build-image ./tests/fixtures Dockerfile.other | stdout with
func (m *DockerBuilder) BuildImage(
// Dockerfile path
Dir *dagger.Directory,
// Dockerfile name
File string,
) (*dagger.Container, error) {
ctr := Dir.DockerBuild(dagger.DirectoryDockerBuildOpts{
Dockerfile: File,
})
return ctr, nil
}
It just doesn't work when calling the function in code?
a similar issue here: https://github.com/dagger/dagger/issues/8483
the issue is that the scheme for setting default args from the cli/shell is different from within code
// +defaultPath is required for a default dir arg
It is possible to assign a default path for a Directory or File argument in a Dagger Function. Dagger will automatically use this default path when no value is specified for the argument. The Directory or File loaded in this manner is not merely a string, but the actual filesystem state of the directory or file.
I don't think that's relevant here? The Dockerfile attribute requires a string value (https://pkg.go.dev/dagger.io/dagger#DirectoryDockerBuildOpts) so the type for the File parameter is string, and since it's not Directory/File it uses +default? Am I misunderstanding?
_, err := dag.DockerBuilder().BuildImage(
"./fixtures",
"Dockerfile.other",
)
That doesn't work, I've not progressed with it since
right okay, that's because "./fixtures" is a string
it needs to be a *dagger.Directory
i'd recommend using your IDE, with the output from dagger develop - it's a compile time error
dagger develop runs fine as-is
✔ connect 0.2s
✔ moduleSource(refString: ".", requireKind: LOCAL_SOURCE): ModuleSource! 0.1s
✔ .localContextDirectoryPath: String! 0.0s
✔ develop 3.4s
✔ ModuleSource.sourceRootSubpath: String! 0.0s
yeah, but if you load up the file in your IDE, it should be showing you errors?
It is - cannot use "./fixtures" (untyped string constant as *dagger.Directory...
right, so you need to use a dagger.Directory?
I'm either misremembering or getting this wrong entirely, in Python you can just pass strings to become dagger.Directory automatically?
No, you need DefaultPath(). See https://docs.dagger.io/api/default-paths.
I think I've been confusing this with CLI inputs somewhere.
Calling this module from the CLI is simple, just pass a path and it loads that path as a dagger.Directory. How do I do that in code?
You need +defaulPath, assuming what you want is to set a default, and that the path in question is within your git repo.
I'm thinking about the test
How do I pass that directory to the test in code
I'm happy with the function itself, it's using *dagger.Directory, no need for +defaultPath, but how do I test that function in a submodule
dag.CurrentModule().Source().Directory("./fixtures") perhaps?
Just call it without passing a value for it. Otherwise +defaultPath is ignored. It's only set when you don't pass a value yourself.
I don't have/need +defaultPath
Ok, if it's within your module then you can use dag.CurrentModule(), yes.
To extend the question, if the file wasn't part of the current module is that possible, and if so how?
You need to make sure it's included in dagger.json if it's outside the module.
Ok, that's new to me, got a link documenting that I can read/search for?
But + defaultPath is a simpler solution imo.
I'm not sure about putting a default path for test fixtures in a module for broad use, but I do see the point: provide a path or it'll just run the test path
I was suggesting putting it in the test module. Then pass that to the module under test.
Ahhh
Like this?
func (m *Tests) OtherDockerfileBuild(
ctx context.Context,
// +defaultPath="./fixtures"
Path *dagger.Directory,
) error {
_, err := dag.DockerBuilder().BuildImage(Path, "Dockerfile.other")
return err
}
Yes 🙂
How should a default value for a []string be formatted? // +default="linux/amd64,linux/arm64" errors
Seems like ["linux/amd64","linux/arm64"] works
Hey all, just getting started with dagger and wondering if there is something I need to do to have neovim correctly run auto complete for dagger modules in projects?
Pretty sure just running dagger develop will do it
Do I need to run that in a project that already has dagger setup but I've just freshly cloned?
You just need a dagger.json file
I have that 👍
The issue I have is files in .dagger don't auto complete the dag variable or the dagger module
I've setup the go work files as the docs suggest, it doesn't seem to have made a difference
How is your neovim gopls plugin set up? Autocomplete was automatic for me once I'd run dagger develop
Good question, I have just got vim-go installed via Lazy with no configuration options set
It is installed though and just running an update now
There was an update but it hasn't fixed this
@warm nacelle if you don't mind sharing, how is your gopls setup?
🤔 yeah, so dagger develop needs setting up
are you using https://github.com/neovim/nvim-lspconfig ? tbf, while using nvim, i don't really know how it's all configured, i know it's Meson doing all the work under the hood
i also use lazy, this might be helpful? https://github.com/jedevc/dots/tree/master/modules/nvim/config
^ my config
Mine is default
Use Mason to install the Go extra and it all just worked
Yeah, using that
Thanks will take a look
Think maybe I'll build my config up again and see what happens
So dagger develop needs to be run in order to put the .dagger/internal pkg in place, as this dir is in the .gitignore this fixes the issue I had
I'm trying to export a file from the Container into the project directory with .File("/tst.md").Export(ctx, "./tst.md") bit the output of running dagger call shows the path as being /scratch/tst.md, what's the right way to do this?
Essentially I'm trying to get a cover report to attached to gitlab merge requests.
you can't programatically export from within dagger to the host. You have to do it with the -o flag on the dagger CLI. So, your dagger function will return a File or a Directory, the CLI can then export that to host.
Yes correct, it's json formatting
Thanks, will check that out
Got that working but have hit another issue, trying to use gocover-cobertura < cover.out > coverage.xml it seems that the > is ignored and the file coverage.xml is not created, anyone seen this before?
Running as sh -c "gocover-cobertura < cover.out > coverage.xml" did the trick
That works 🙂 If you want, there are also optional arguments to withExec for redirecting the command's standard streams
Thanks, I did see those and tried it but found I preferred adding the file and using it in the command like that than getting the contents of the file and putting into the exec option input string.
I am quite liking the dagger system so far though
@vestal hatch I think you hit the need for this: https://github.com/dagger/dagger/issues/9150
Then you could have done:
ctr.
WithExec([]string{"gocover-cobertura", dagger.ContainerWithExecOpts{StdinFile: "cover.out", RedirectStdout: "coverage.xml"})
Oh man I forgot about that!
We should try again, with a Dagger-powered agent 🙂
Yeah, much nicer than grabbing the content to push in
How good is the dagger ai stuff?
Early but very fun to use. It's built on the existing primitives, so the foundation is robust.
The most underrated feature IMO is the interactive CLI. There's basically a codex-style interactive chat baked in the dagger CLI.
that's interesting, will take a look when I can
quite new to dagger
maybe someone could help me 🙂
trying to build from dockerfile
then i want to get the sha of the build to use it for further flows
maybe someone can refer me to where and how : )
`func (m *EcsProject) BuildImageFromDockerfile(
ctx context.Context,
// location of directory containing Dockerfile
src *dagger.Directory,
) (string, error) {
ref, err := src.
DockerBuild().
Publish(ctx, "ttl.sh/image-name:latest")
if err != nil {
return "", err
}
return ref, nil
}
`
yeah, the ref you get at the end should actually have a digest in it
so it'll look like ttl.sh/image-name:latest@sha256:... - you just need to parse that to extract the sha
what i want is to, for example print the sha between the build and the publish lines
Do all the properties and methods on a struct in a dagger pipeline need to be public?
oh i see! yeah, hm. the problem is, the way that dagger works, we don't actually "bundle" the container into it's final form for the registry until publish.
so there's actually no sha of the image in-between.
you could export it using AsTarball, then somehow extract the digest from the oci tarball? then publish it from that, but that's definitely a tricky flow
yes 🙂 that's just the nature of how json-serialization and such work in go, so to access those we need them to be public
So dagger is doing some serialization of the struct in order to have it work with dagger call?
So I have func (t *Test) Lint(ctx context.Context) (string, error) {...} and within that I'm calling a private method and using a private property, this isn't possible with dagger?
you can call a private method definitely! that's a nice way of having a function entirely internally, and not having exposed over the dagger api
but for properties, those don't get persisted between calls - you can definitely use them, but they're gonna get set to zero values between calls
Between call, meaning you can't use the dagger cli to do GenCoverOut | PrintCoverOut where cover out is stored in a private property? But I should expect that property to persist within the one dagger call lint?
Sorry the issue I have is that I have tried cleaning up my dagger call -h output and it is panicing with an invalid memory address
Is there a way to hide properties from the help output if making them private isn't the way?
Made one of the properties public again and it's working as expected, thanks for the help @regal seal
Looks like adding // +private is what I need
Oh nice, after reconsideration that's actually better since we want to scan the image before pushing it 🙂
Thanks!
I have some folks on my team that like to regularly run individual tests by clicking on the function name in vscode using its test integration. Since moving some of our tests to run inside dagger they can't do this. I don't use vscode personally, is there a way to configure the vscode test integration so that it'll run dagger call ... when running these tests? Or is there another way folks have made it easier to do this while still using dagger?
I think https://github.com/dagger/dagger/issues/5993 could potentially help here. I noticed its closed as completed?
Hey all, just looking at the files generated via dagger develop --sdk go, I see there is a .gitignore and .gitattributes, is there a reason for having both?
yes - lots of tooling follows .gitattributes to know if a file is generated
e.g. vscode will warn you if you try and edit a file that has the linguist-generated property (which we set)
.gitignore is because we don't want the file to be committed
Ah okay, didn't think it was used outside of git, good to know 👍
I have a command flox containerize that can return a tarball. Is there any way to load this tarball as a dagger.Container ? Or to use it in dagger am I going to need to do something like this https://docs.dagger.io/cookbook/#build-and-load-a-container-image-into-the-host-docker-engine to load and push it to my registry with docker and then pull it from my registry again with dagger?
😮💨 Of course I ask and go and check the docs one more time and see https://pkg.go.dev/dagger.io/dagger#Container.Import so I guess I'm good 🙂
Hi, Im trying to use a private go proxy and gosumdb, any news on this topic ?
Engine wide GOPRIVATE and GOSUMDB
Want to double check this because it's either working or silently failing. Function parameter with a default and an enum type. I'm assuming as long as the default parameter value is a valid enum value then it works as you'd expect?
const (
Plan TerraformCommand = "plan"
Apply TerraformCommand = "apply"
)
with
// Terraform command
// +default="plan"
command TerraformCommand,
Enum default
So I have a function that returns a service, the important part is
func (m *NatsAuthCallout) NatsAuthCalloutSvc(ctx context.Context) (*dagger.Service, error) {
<snip>
natsSvc := dag.Nats().NatsSvc(userPublic, accountPublic)
authCalloutCtr.
<snip>
WithServiceBinding("nats", natsSvc).
AsService(
dagger.ContainerAsServiceOpts{
Args: []string{
"/nats-auth-callout",
"--config-file", "/tmp/auth-callout-config.yaml",
},
}).Start(ctx)
return natsSvc, nil
My issue is that I end up with 2 instances of natsSvc running, one that does not have my authCalloutCtr hooked up to it. So every other request from my host hits the "bad" service.
I'm running it with dagger call -m dagger/auth-callout nats-auth-callout-svc up .
I know that WithServiceBinding will start the service. I'm not sure what to do differently here so that there's only one instance of natsSvc running?
You have Start(ctx) and also up in the CLI. I think both of those do the same thing. If you are using it with the CLI, you can remove the .Start(ctx). Then it won't run it twice.
If I do that then the authCalloutCtr never gets started. I've tried to do natsSvc := dag.Nats().NatsSvc(userPublic, accountPublic).Start(ctx) as well but I still end up with two instances of natsSvc.
Hmm I think this might be a situation to use https://github.com/kpenfound/dagger-modules/tree/main/proxy
oh, why not return authCalloutCtr?
because I need the actual nats container exposed, the auth callout container does expose an API or anything, it just needs to run in the background
ah.. yes I think you'd need that proxy for exposing multiple services
Yeah I would prefer not to have to expose both but I don't know how else to get around doing that due to how WithServiceBinding works
oh you don't want to expose both? Hm, I don't think you need the proxy then. @signal mantle probably knows a better way to approach this.
Oh yeah... proxy isn't gonna help. Really I want something like WithBoundService("nats") which would give me the "right" nats container
Oh, maybe something more like https://docs.dagger.io/cookbook/#create-interdependent-services is what I need. I thought service binding was the only way to connect services
Yeah i was checking this too - https://github.com/dagger/dagger/pull/8641
That's what supports the cookbook entry
yeah that sounds like the way to go. Somehow I haven't run into that kind of service dependency yet!
Can I use dagger to run my e2e tests and debug them with delve? I assume this should be possible, are there any examples?
Hi friends, I am making some changes in one of my modules that has a function that returns a custom type like this
type AttestationResult struct {
OutputTerminal string
// Attestation state
OutputStatement string
// Attestation bundle
OutputBundle string
}
this means that after calling this method I need to chain with the property i.e dagger call my-function output-terminal. My question is, is there any way to tell the engine to by default return one of the properties while still have the flexibility provided by the custom type?
The background of this requirement is because currently our function returns a string and if we move to returning a custom-object we break backwards compatibility, so I am wondering if I could have the best of the two worlds, chaining enabled function + default returned value.
Thanks!
hey Miguel. We don't have such a feature, but one thing you could do is change the name of the new function returning an object; then keep your original function returning a string, but make it an alias to the corresponding string field in the object.
Then if you want, you can use the +deprecated pragma to have the engine warn clients that the alias is deprecated.
Hey Solomon, do you have a simple example of this? I am not sure I understand what you mean by "make it an alias to the corresponding string field"
Well if you initially had:
func (m *MyModule) Result() string {
// ...
}
And now you want to 1) return an object instead of a string, while 2) not breaking backwards compat. You can do:
func (m *MyModule) FullResult() AttestationResult {
// ...
}
type AttestationResult {
// ...
}
func (r AttestationResult) Description() string {
// ...
}
// This is the alias
func (m *MyModule) Result string {
return m.FullResult().Description()
}
It'a not a Dagger-specific pattern, you could do the same thing in eg. a Go package
Ah! Right.. I got confused with the word "alias" and thought it's some dagger thing I missed. Thank you for the example, this makes sense
needed a way to authenticate with ECR and came across this dagger module
https://daggerverse.dev/mod/github.com/lukemarsden/dagger-aws@19e25f1a18d46f97f2d01b2338f3810d11943689#module-about
turns out it prints the login token to stdout.
has anyone find a better apporach beside managing it myself ?
I let my instance profile do most of the work in AWS, locally I'll just copy a short lived session in from my identity service
I've use this module: https://daggerverse.dev/mod/github.com/mjb141/daggerverse/aws-ecr@5b9948571394a9210a5b82989841ac5479472e1d#AwsEcr.withCredentials
HI there ! where could I find the list of all struct tags applicable to dagger functions / properties ?
Hello! To my knowledge our Go SDK does not define any custom struct tags. It does define pragmas (comments like // +optional or // +default="foo"
those two i know. i know also defaultPath for *dagger.Directory. I remember seing something like // +internal-use-only but couldnt find anything in the docs
mmm that doesn't ring a bell. I know @restive hollow is working on +deprecated
I think +internal-use-only was perhaps a fake pragma to scare LLMs into not using a function
yeah i think it was in the context of a module used by an LLM
i think we also have the +ignore , +private (for the struct though)
what is your use-case / need ? 😇
@restive hollow no specific use case here i was just searching for what's available 🙂
@restive hollow i actually do remember now what i was looking for. Is there a way to override the name of the CLI argument so it differs from the property name in the module function ? my use case is the following
If i have an array as an argument, it make sense that in the code it's pluralized ( e.g args) . But when i call the CLI i want have the arg as singular dagger call build --arg foo --arg bar
func (m *MyModule) Build(
// i want to rename this cli argment
args []string,
) {
...
}
unfortunately you can't expose an argument as a different cli flag name. FYI you can pass comma-separated values as an array, eg --args=foo,bar
thanks @violet cosmos i'll stick to the comma-separated values 🙂
Go module names for Dagger modules
I'm starting to look at some of the Dagger modules my team has developed, with the intent to apply our standard Go linting rules and styleguide across them. One of the things that has come up here is the module naming that Dagger creates; module dagger/{name} leads to the packages not meeting the expectations for Go module names (https://go.dev/ref/mod#module-path), where the repository name, and path to the module root apply. This also leads to inconsistencies in import ordering, where because the modules don't use a repository root path, they are treated as if they are part of the Go standard library, and ordered alongside the stdlib imports, while other linters expect them to be split from stdlib imports. These linters are all part of GolangCI Lint, not custom tooling for the organisation.
I've been able to successfully refactor (seemingly - more testing required) the existing Dagger modules to add in the repository root and paths to the module name and imports, however, this doesn't apply to new module creation, which continues to use dagger/{name}. My first question then is whether anything relies on the dagger/{name} module naming that prevents using fully qualified modules names? And secondly, whether it is possible to configure Dagger to create modules with fully qualified module names?
@violet cosmos , @restive hollow David is one of the principal engineers at Nine. Just wondering if we could get a look in at his question here 🙂
Hey @green terrace, taking a look a bit later or tomorrow 🙏 Thanks for the ping I missed it
From my experience, you can safely change the name of that go module yourself, it's not load-bearing in any dagger-specific way. If the go tooling is happy, then the dagger sdk will be happy
@half vessel for example, the dagger module at the root of our own repo is named github.com/dagger/dagger/.dagger (which is the actual path of the go module)
https://github.com/dagger/dagger/blob/main/.dagger/go.mod#L1
That name is not load-bearing either - it was just a subjective preference of one of the dagger maintainers at some point (I don't know the exact history)
I vaguely recall it was introduced due to name collisions. For example: if you had a module called go, it would collide with the stdlib go package? Or the go keyword? I'm not sure, bit it was something like that.
I had that same dilemma when the naming convention was introduced.
There are cases where it doesn't really matter (for example: when maintaining a daggerverse repo: https://github.com/sagikazarmark/daggerverse/). It did bother me for a while, but there are no practical implications and the maintenance cost outweighs the benefits.
For actual application, though, I usually just rename the module to match the repository path.
whether it is possible to configure Dagger to create modules with fully qualified module names?
It probably is, but it isn't necessarily worth the cost. Dagger would have to take vanity imports and all kinds of stuff into account for this to work.
if you had a module called go, it would collide with the stdlib go package? Or the go keyword?
This applies based on the last element of the module name regardless, given the current module naming is dagger/{name} ? I assume previously the dagger/ part wasn't included in the name here, so these were just module {name} like module go, which I can see being a problem. If this was github.com/{org}/{repo}/parent/path/{name} conflicts on the last element would be unchanged, but would represent a fully qualified module name. With this being a fully qualified URL path, it would not be misclassified as a package from the SDK (which applies for dagger/{name} due to the root dagger/ part of the path not being a domain).
It's interesting that https://github.com/dagger/dagger/blob/main/.dagger/go.mod#L1 is using a module name with a . in the path. I know I hit an issue with applying this approach to some of our other modules which are written in python, and use a dot prefixed folder in their path. I'll have to check what that issue was; I suspect it was in a parent path rather than the final element.
Given the advice here is that the module paths aren't load bearing, I'll continue to rename our modules to use fully qualified names. In our internal tooling, we'll need to have an extra step after the dagger init command for the new module to rename the Go module (to match the fully qualified url path).
This applies based on the last element of the module name regardless
I don't mean at the call site, but when importing the package. strings for example collides with the stdlib package name (AND import path). But dagger/strings is a valid module name AND import path.
Right, yes. I can see how that prevents a collision with the SDK package paths 👍 This matches the advise from the official docs: https://go.dev/ref/mod#module-path
A module that will never be fetched as a dependency of any other module may use any valid package path for its module path, but must take care not to collide with paths that may be used by the module’s dependencies or the Go standard library
This also suggests that it should be ok to use such package names starting with dagger/ for locally resolved modules.
The very next sentence covers where the dagger/ module path prefix is getting confused with SDK packages:
The Go standard library uses package paths that do not contain a dot in the first path element, and the go command does not attempt to resolve such paths from network servers
This is then tripping up linters/formatters, which treat dagger/{name} as an SDK package, not a 3rd party or local one, and order it with the SDK group. Other linters know the valid SDK packages, and want it not in the SDK group.
Yeah, in those cases, manually rewritting the import path is the right thing to do. Fortunately, it works, and it's an easy thing to do (may not even need text replacing, you can use go mod edit).
Frankly, I never had an issue with linters, but I probably just ignore dagger code in my linter config.
In any case, in most of my projects (not my daggerverse repo), I also rewrite the import path. Never had any issue with that.
Its possibly to use go modules as both "module" and golang "library" at same time?
My idea was to create a golan module, for building/testing/pushing etc.. whole pipeline..
And then for some repos use it as remote modules..
And for some use it as library while allowing to modify some steps..
Is that feasible in golang?
Seems not easy.. right now I have bumped into
go get github.com/org/dagger-modules/{module}
error: package dagger/{module}/internal/dagger is not in std
Its possibly to use go modules as both "
Is there a guide on any of the "gotchas" with Go and Dagger? I just ran into having an unexported member on a module struct that wasn't surviving between chain calls causing a panic: I think this happens since JSON unmarshal won't perserve those unexported fields in structs between chains.
I'm not 100% sure to see the issue, but my gut feeling is you should export the field (make it public) but add the +private pragma. This pragma will allow the field to be part of the serialization while not been exposed publicly (no getter created on the field). https://docs.dagger.io/extending/state/?sdk=go
you should export the field (make it public) but add the +private pragma.
Right, that's basically what I did. It's just goofy since my "Go instinct" is to keep it unexported (i.e., lowercase) and not have to provide any metadata.
Seems that dagger's interpreter should "just work ™ " by setting the +private on unexported fields. Why wouldn't you want that?
It's almost like a double negative to have it exported in the Go code (so other API users of the module could in theory access it) while there's a +private that is a special dagger thing for just it's internal serialization.
Hey everyone! 👋 Before I file an official bug, I want to sanity-check a potential regression regarding private Go modules and SSH authentication.
The Issue:
Since v0.20.4 (tested up to v0.20.6), my Dagger module fails during code generation when building. It works in v0.20.3.
It appears the codegen container is no longer respecting the host’s Git configuration or SSH agent, causing go get to fail when it hits a private repository.
Symptoms:
dagger call fails during the "needs another pass..." stage of codegen.
Error: fatal: could not read Username for 'https://github.com': terminal prompts disabled.
I’ve detailed my configuration and suspected PRs in the thread below. Am I missing a new config requirement for v0.20.4+, or is this a genuine regression?