cpybkc
image as a step in somebody else's pipeline, for a caller who would rather notwrite a Dockerfile.
dagger call -m github.com/Zaba505/cpybkc/daggerverse/cpybkc \
with-generator --name hello --image ghcr.io/example/cpybkc-gen-hello:v1 \
generate --source . export --path .
Nothing is installed on the host and no Dockerfile is written: the published
images are pulled, composed, and run.
# An interface of its own, and why it still gets no SPEC.md
This module is the cpybkc CLI daggerized (#253): a caller who reaches for it
should be able to do what `cpybkc` does, by name. That makes it something a
third party builds against rather than a convenience they could equally well
do without — a function name, an argument and a default here are public API
for as long as the directory this module is published under exists, which is
for as long as the directory exists at all.
It gets no SPEC.md all the same, and the reason is not that there would be
nothing to specify. It is that everything there would be to specify is
specified already: what a flag means is docs/cli/SPEC.md's, what the image
promises is docs/container/SPEC.md's, and what a generator is handed is
docs/plugin/SPEC.md's. A document here would be a second reading of those
three, in another vocabulary and on another schedule, which is the drift the
mapping is checked for rather than a defence against it. What is this module's
own is the mapping — which function carries which flag — and that is written
down in this repository's pipeline, where `dagger call cli-surface` fails on
it, rather than in a document nothing can check (docs/CONVENTIONS.md, "What
belongs here").
Everything here can still be written by hand as
`docker run --rm ghcr.io/zaba505/cpybkc:v0` or as a `COPY --from`, and a
caller who prefers either is not on a lesser path. What the stance changes is
what it means when the CLI can do something this module cannot: that is a gap
to be filed, not a curation working as designed.
It states nothing about the plugin CLI contract either. `cpybkc-gen-`,
the argument vector and the exit codes are docs/plugin/SPEC.md's, they hold
with no container anywhere in the picture, and the only thing this module will
ever know about them is the filename a generator is installed under.
# The module ref is permanent public API
This module is published as `github.com/Zaba505/cpybkc/daggerverse/cpybkc`,
and a Dagger module ref is a directory path inside a tag of this repository.
Renaming the directory would not deprecate the old ref, it would delete it:
every caller pinning `…/daggerverse/cpybkc@v0.3.1` resolves that path inside
the tag they named, so a rename breaks every unpinned caller at once and
strands every pinned one on a path that will never move again. There is no
redirect to leave behind and no deprecation period to serve.
The name is therefore chosen once and kept. `daggerverse/` is the
house layout — it is where `github.com/z5labs/devex` publishes the two modules
this repository's pipeline already depends on — and the directory is named for
what the module drives rather than for what it does, so that a second module
shipping from here later needs no rename of this one to sit beside it.
The `.dagger/` module at the repository root is a different thing entirely: it
runs this repository's own pipeline, it is published for nobody, and it knows
about a checkout of cpybkc that this module never sees. What holds the two to
one Dagger `engineVersion` is the local dependency edge the root `dagger.json`
declares on this directory — an engine bump is then one commit touching both
files, rather than two files nothing requires to agree.
# Composing a generator, and the Dockerfile it replaces
The base image carries the CLI and no generator at all, so an image that
generates anything is a composition. WithGenerator is that composition:
dagger call -m github.com/Zaba505/cpybkc/daggerverse/cpybkc \
with-generator --name hello --image ghcr.io/example/cpybkc-gen-hello:v1 \
generate --source . export --path .
and the two lines it stands for are the final stage of
docs/container/SPEC.md's worked example, written by hand:
FROM ghcr.io/zaba505/cpybkc:v0
COPY --from=ghcr.io/example/cpybkc-gen-hello:v1 --chown=65532:65532 --chmod=0755 \
/usr/local/bin/cpybkc-gen-hello /usr/local/bin/cpybkc-gen-hello
They are the same two instructions and the comparison is the point: the
mechanism is `COPY --from`, this is not a second way of extending cpybkc, and
a caller who prefers the Dockerfile is not on a lesser path. What the module
saves is the build context, the registry to push the derived image to, and a
Dockerfile to keep in step with a cpybkc release — a project whose manifest
names three generators is three calls and one image that is never pushed
anywhere.
Two differences from that COPY line are deliberate rather than incidental.
The module sets no owner where the Dockerfile writes `--chown=65532:65532`:
the mode is what makes the file runnable, by the image's own UID and by any
UID a caller overrides it with, while the owner is a property of the image
this module was given rather than one it may assume. The Dockerfile can name
65532 because it also names the base image it is deriving from; a module
handed a container through --image knows no such thing. And --image may be
omitted, in which case the generator image is the one this project publishes
beside the CLI — `-gen-:`, resolved against the same
--repository and --version the CLI image came from, so a generator from one
release never lands beside a CLI from another.
WithGeneratorExecutable is the other half, and it takes a File rather than an
image: a generator that has not been published yet, most often one the caller
has just built in the same pipeline. A generator author needs it to check
their plugin against a real cpybkc run before there is anything of theirs to
pull.
# Multi-platform derived builds
A compos
Installation
dagger install github.com/Zaba505/cpybkc/daggerverse/cpybkc@v0.0.2Entrypoint
Return Type
Cpybkc !Arguments
| Name | Type | Default Value | Description |
|---|---|---|---|
| version | String | "v0" | The tag of the published cpybkc image to run. It defaults to the moving major tag "v0", which follows every release in that major version: a caller who passes nothing keeps up with fixes and stays inside the base-image contract's compatibility guarantees. Escalate deliberately — "v0" follows releases, "v0.3.1" pins one release, and only a digest pins the bytes. A digest is not a tag, so it goes to --image rather than here. |
| repository | String | "ghcr.io/zaba505/cpybkc" | The registry repository the image is pulled from, as `<host>/<path>` with no tag. It is an argument because where the image lives is not something the base-image contract promises — a mirror, an internal registry or an air-gapped copy serving the same digests satisfies every requirement in that document identically, and a caller behind one should not have to give up this module to use it. Companion images derive from it by the rule this project publishes them under, so redirecting this redirects the family rather than the base image alone. |
| image | Container | - | Run in this container instead of pulling one, replacing it entirely. It has to keep the promises the base-image contract makes — cpybkc as the entrypoint, the plugin directory on PATH, a user that can execute what is in it — because that is all this module drives it through. Nothing here checks that, and nothing could: a container is not required to have come from a registry at all. This is how cpybkc's own pipeline checks the module against the image it just built rather than against the last release (#64), how a caller tries a change to cpybkc before it ships, and how a build pins the image by digest — a reference no tag argument can express, and the only one that pins bytes. It pins this image and nothing else. A generator pulled afterwards by with-generator follows --version, which defaults to the moving "v0" tag and does not track whatever was pinned here, so a build that pins the CLI by digest and wants the pairing to hold still passes --version beside it. |
| platform | String | - | Pull the image for this platform, as `GOOS/GOARCH`, instead of for the engine's own. It is what makes a derived image for another architecture reachable at all: a composition is one platform, and without this an amd64 engine could only ever compose an amd64 image. Every generator composed in afterwards follows it, so the platform is stated once, here, rather than on each call that could contradict the last. A multi-platform derived image is therefore one composition per platform, published as variants of one index — see this module's comment. That loop belongs to the caller because the index does: which platforms a derived image serves is a property of who will run it. Empty is the engine's own platform, which is what makes an ordinary `dagger call` from a checkout do the obvious thing. |
Example
dagger -m github.com/Zaba505/cpybkc/daggerverse/cpybkc@0540e3da826efb9d038330e4f4291ee10065f2c7 call \
func (m *MyModule) Example() *dagger.Cpybkc {
return dag.
Cpybkc()
}@function
def example() -> dagger.Cpybkc:
return (
dag.cpybkc()
)@func()
example(): Cpybkc {
return dag
.cpybkc()
}Types
Cpybkc 🔗
Cpybkc is one cpybkc image, plus the coordinates for resolving images related to it.
A function on it is a builder returning a new Cpybkc, a terminal that runs something, or an accessor handing back what was resolved, so a call chain reads as the image being assembled and then used; nothing here mutates.
emitIr() 🔗
EmitIr writes the run’s resolved descriptor and hands back the file:
dagger call -m github.com/Zaba505/cpybkc/daggerverse/cpybkc \
emit-ir --source . export --path descriptor.binpb
It is cpybkc --emit-ir, and the name is that flag rather than a word of this
module’s own for the reason Init’s is the CLI’s verb: somebody who read
docs/cli/SPEC.md should find what they read about here, under the name they
read it under.
The descriptor is what to attach to a bug report, against cpybkc or against
any generator, and the call above is the one that produces it: in the default
encoding it is exactly the bytes a plugin was handed — the equality the plugin
contract rests reproducibility on — so reading it settles in one step whether
a fault is the producer’s or the consumer’s. The JSON is a rendering of that
same descriptor rather than the bytes themselves, so it belongs beside the
binary file in an issue rather than instead of it. It is also available from
the run that is broken: an emission is terminal, so no generator is resolved,
nothing is merged into the project’s tree and nothing is pruned from it
(docs/cli/SPEC.md, “Emitting replaces generation”), which is why a project
whose generate fails inside a generator can still emit the descriptor that
generator was given.
Nothing is written to the host, exactly as with Init: the File that comes back is a value, and exporting it is the caller’s separate step. This module writes it to a path of its own inside the container, outside the mounted project and where nothing was mounted, so the run cannot land on something the caller already has.
The one spelling this does not offer is --emit-ir -, which stays Run’s for
the reason --out - does — a File-returning function has no stream to hand
back — and which is a spelling rather than a flag:
dagger call -m github.com/Zaba505/cpybkc/daggerverse/cpybkc \
run --source . --args=--emit-ir,- stdout
The illegal pairing docs/cli/SPEC.md names — --emit-ir-format without
--emit-ir — is unstateable here rather than enforced. This function is the
emission and the format is its argument, so there is no call that names a
format without asking for one, and there is nothing left for the module to
check.
Return Type
File !Arguments
| Name | Type | Default Value | Description |
|---|---|---|---|
| source | Directory ! | - | The project to emit the descriptor of: the directory holding the manifest, the layout it names and the copybooks that layout names. It is mounted whole rather than filtered down to what the run reads, for Generate’s reason: which copybooks are read is a property of the layout, and a module guessing at that set would be a second, weaker answer to a question docs/cli/SPEC.md answers exactly. |
| manifest | String | - | The project manifest to read, relative to the root of source. It is taken the way Generate takes it, and it is not a convenience: a run resolves one descriptor, from the layout the manifest names and the copybooks that layout names (docs/cli/SPEC.md, “Which descriptor is emitted”), so which descriptor is emitted is exactly which manifest was read. A project keeping its manifest somewhere else would otherwise be able to generate through this module and not to emit what it generated from. It defaults to nothing, which leaves cpybkc reading |
| format | String | - | The encoding the descriptor is written in: It defaults to nothing, which is not a third encoding: an unnamed format
reaches the CLI as no –emit-ir-format at all, so what arrives is whatever
docs/cli/SPEC.md’s default is — A value that is neither spelling is passed through and refused by the CLI, which names the spellings there are from the parser that decides them. That is deliberate for the reason Run validates nothing: a second reading of that contract out here is one that drifts, and this one would drift the day a third encoding landed. |
Example
dagger -m github.com/Zaba505/cpybkc/daggerverse/cpybkc@0540e3da826efb9d038330e4f4291ee10065f2c7 call \
emit-ir --source DIR_PATHfunc (m *MyModule) Example(source *dagger.Directory) *dagger.File {
return dag.
Cpybkc().
Emitir(source)
}@function
def example(source: dagger.Directory) -> dagger.File:
return (
dag.cpybkc()
.emitir(source)
)@func()
example(source: Directory): File {
return dag
.cpybkc()
.emitIr(source)
}generate() 🔗
Generate runs cpybkc over a project and hands back the project as it should now be committed:
dagger call -m github.com/Zaba505/cpybkc/daggerverse/cpybkc \
generate --source . export --path .
Nothing is written to the host. The Directory that comes back is a value like any other, and exporting it is the caller’s separate, explicit step — which is also what disposes of the ownership problem a bind mount has, where generated files land owned by whichever UID the container ran as and a host user who is not that UID owns none of their own project. Dagger’s export writes as the person running it, so the image’s pinned user never reaches the host.
What comes back is the whole project directory, not only the files a
generator produced. A generator’s output lands where the manifest says, which
is ordinarily inside the source tree, and a run also prunes what a previous
run generated and no longer would — so the generated files alone cannot
express half of what a run did. generate --source . export --path . is
therefore the ordinary use, and it is a full statement of the run rather than
an overlay that leaves deletions behind.
Return Type
Directory !Arguments
| Name | Type | Default Value | Description |
|---|---|---|---|
| source | Directory ! | - | The project to generate over: the directory holding the manifest, the layout it names and the copybooks that layout names. It is mounted whole rather than filtered down to what a run reads, because which copybooks a run reads is a property of the layout — the manifest carries no input list — and a module guessing at that set would be a second, weaker answer to a question docs/cli/SPEC.md answers exactly. |
| manifest | String | - | The project manifest to read, relative to the root of source. It defaults to nothing, which leaves cpybkc reading A relative path resolves against that project root, because that is the directory the CLI resolves a path typed on the command line against. It cannot be “-”: a manifest’s own paths are relative to the directory holding it, and a manifest arriving on a stream is in no directory. |
Example
dagger -m github.com/Zaba505/cpybkc/daggerverse/cpybkc@0540e3da826efb9d038330e4f4291ee10065f2c7 call \
generate --source DIR_PATHfunc (m *MyModule) Example(source *dagger.Directory) *dagger.Directory {
return dag.
Cpybkc().
Generate(source)
}@function
def example(source: dagger.Directory) -> dagger.Directory:
return (
dag.cpybkc()
.generate(source)
)@func()
example(source: Directory): Directory {
return dag
.cpybkc()
.generate(source)
}image() 🔗
Image is the image this module resolved and composed, for a caller who wants to do something with it other than what this module offers — run a cpybkc subcommand by hand, look at what is in it, publish a derived image holding their generators, or make it one variant of a multi-platform index:
dagger call -m github.com/Zaba505/cpybkc/daggerverse/cpybkc \
image with-exec --use-entrypoint --args=--version stdout
Note the –use-entrypoint. The image’s entrypoint is the CLI and the literal value of it is not part of the contract (docs/container/SPEC.md, “The CLI’s own path is not part of the contract”), so an exec that named a path instead would be reaching for the one thing that document reserves the right to move.
Publishing the image elsewhere is a reasonable thing to do — it is the same image the registry served — but a copy is not a release of cpybkc and carries none of the signatures or attestations one does (docs/container/SPEC.md, “What a tag carries besides the image”), because those are attached to the digest this project published and not to the bytes.
Return Type
Container ! Example
dagger -m github.com/Zaba505/cpybkc/daggerverse/cpybkc@0540e3da826efb9d038330e4f4291ee10065f2c7 call \
imagefunc (m *MyModule) Example() *dagger.Container {
return dag.
Cpybkc().
Image()
}@function
def example() -> dagger.Container:
return (
dag.cpybkc()
.image()
)@func()
example(): Container {
return dag
.cpybkc()
.image()
}init() 🔗
Init scaffolds a layout from copybooks and hands back the file to edit:
dagger call -m github.com/Zaba505/cpybkc/daggerverse/cpybkc \
init --source . --copybook posting.cpy export --path ledger.sexpr
It is the first thing an adopter runs, before there is a manifest, a layout or a generator to speak of, and it is the run that made the case for mapping cpybkc’s commands by name at all (#228): the one invocation somebody has nothing to copy from is a poor place to make them assemble an argument vector by hand.
What comes back is not a valid layout and is not meant to be. init
writes what the copybooks decide — a record per 01-level, an alternative per
REDEFINES — and leaves the half no copybook holds as commented forms for a
person to answer: which field discriminates, and in what order the records
come. docs/cli/SPEC.md’s init section is what that file says and what it
deliberately does not.
Nothing is written to the host, exactly as with Generate: the File that comes
back is a value, and exporting it is the caller’s separate step. What it is
called is theirs — this module writes the scaffold to a path of its own inside
the container, outside the mounted project and where nothing was mounted, so
the run cannot land on something the caller already has, and the name it takes
in their tree is the one they give export.
Where it goes is theirs within one constraint, and it is the one thing here
a caller cannot infer from the signature. The scaffold names each copybook by
the path it was given, which is relative to the root of source, and a layout’s
own paths are relative to the layout — so the file belongs at that root, beside
the copybooks it names. Exported into a subdirectory it is a layout whose
copybook paths resolve nowhere, and nothing at export time will say so. A
project that keeps its layout somewhere else moves the paths as it moves the
file; they are the adopter’s to edit, like the rest of what init leaves
blank.
The destination this module supplies is a file rather than a stream, so
--out - is not offered here. A caller who wants the scaffold on standard
output still has Run, which is the same arrangement –emit-ir has:
dagger call -m github.com/Zaba505/cpybkc/daggerverse/cpybkc \
run --source . --args=init,--copybook,posting.cpy,--out,- stdout
Return Type
File !Arguments
| Name | Type | Default Value | Description |
|---|---|---|---|
| source | Directory ! | - | The project the copybooks are in: the directory their paths are relative to, mounted at /src and made the working directory. It is required, unlike Run’s, because a scaffolding run reads files by definition. The whole directory is mounted rather than the named copybooks alone, because that is what makes the paths below resolve as the adopter typed them: –source is already how every other function on this module takes the caller’s tree, and a mount holding only the named files would be a second, weaker answer to where a relative path points. |
| copybook | [String ! ] ! | - | A copybook to read, as a path relative to the root of source. Repeat it once per copybook, in the order the scaffold should hold their records in. Paths rather than files, because the path is data: docs/cli/SPEC.md has the scaffold record each copybook’s path as it was typed, and a layout’s own paths are relative to the layout. A file handed over on its own would have cpybkc write a container path the adopter cannot find anywhere in their tree. At least one is required, and none may be “-”: a copybook on a stream has no path for the scaffold to state. Everything else is the CLI’s to refuse — a value naming a directory is a run that failed rather than a line that was wrong, and it says so with a diagnostic naming the path. One boundary belongs to the command line rather than to cpybkc: |
Example
dagger -m github.com/Zaba505/cpybkc/daggerverse/cpybkc@0540e3da826efb9d038330e4f4291ee10065f2c7 call \
init --source DIR_PATH --copybook string1 --copybook string2func (m *MyModule) Example(source *dagger.Directory, copybook []string) *dagger.File {
return dag.
Cpybkc().
Init(source, copybook)
}@function
def example(source: dagger.Directory, copybook: List[str]) -> dagger.File:
return (
dag.cpybkc()
.init(source, copybook)
)@func()
example(source: Directory, copybook: string[]): File {
return dag
.cpybkc()
.init(source, copybook)
}run() 🔗
Run is the fallback: cpybkc invoked with an argument vector this module has no opinion about, in a container handed back whole.
dagger call -m github.com/Zaba505/cpybkc/daggerverse/cpybkc \
run --source . --args=--emit-ir,- stdout
dagger call -m github.com/Zaba505/cpybkc/daggerverse/cpybkc \
run --args=--help stdout
It is not the intended route for anything. This module mirrors the CLI, so a
capability’s ordinary answer is an argument on the function named for the
command it belongs to (#253), and three kinds of thing are left over for this
function. A flag this module has not caught up with is reachable through it in
the meantime, which is what keeps a gap an inconvenience rather than a wall. A
spelling no Dagger type can express is reachable through it permanently: a
destination that is a stream rather than a file — --out -, --emit-ir - —
which a File-returning function cannot hand back. And a flag whose question
has a Dagger-native answer that is not a function here stays on purpose, which
is –version, –help and -h and is meant to be the whole of that class.
Which flags arrive here today is stated in this module’s package comment and
recorded where a check can fail on it, in the root pipeline’s
companionRunExceptions: dagger call cli-surface fails when the CLI grows a
flag that neither a named function nor an argued exception covers, so a flag
landing on this function quietly is the one thing that cannot happen.
A container rather than a directory, because the uncurated invocations are the ones whose answer is not a tree. –emit-ir may write to standard output, and –version and –help write nothing else at all; a Directory return would make the escape hatch unable to reach exactly the flags it exists for. A caller who does want the tree takes it from the container, where the project is still mounted at /src:
dagger call -m github.com/Zaba505/cpybkc/daggerverse/cpybkc \
run --source . --args=--manifest,build/cpybkc.json \
directory --path=/src export --path .
Nothing here is validated. A vector this module checked would be a second, unversioned reading of a contract the CLI already implements, and its diagnostics are better than anything guessed at from out here: what an unrecognised flag is, whether a flag may repeat and what a usage error exits with are all docs/cli/SPEC.md’s, and the exec’s failure carries them back verbatim.
Return Type
Container !Arguments
| Name | Type | Default Value | Description |
|---|---|---|---|
| args | [String ! ] ! | - | The argument vector, passed to the CLI exactly as written. The entrypoint is the CLI itself, so this is everything after the command name and it never names the command. |
| source | Directory | - | The project to run over, mounted at /src and made the working directory. It is optional because half the reason this function exists is the
invocations that have no project — |
Example
dagger -m github.com/Zaba505/cpybkc/daggerverse/cpybkc@0540e3da826efb9d038330e4f4291ee10065f2c7 call \
run --args string1 --args string2func (m *MyModule) Example(args []string) *dagger.Container {
return dag.
Cpybkc().
Run(args)
}@function
def example(args: List[str]) -> dagger.Container:
return (
dag.cpybkc()
.run(args)
)@func()
example(args: string[]): Container {
return dag
.cpybkc()
.run(args)
}withEnvVariable() 🔗
WithEnvVariable states one environment variable every run through this module is started with, and therefore one every generator it starts is handed:
dagger call -m github.com/Zaba505/cpybkc/daggerverse/cpybkc \
with-env-variable --name SOURCE_DATE_EPOCH --value "$SOURCE_DATE_EPOCH" \
with-generator --name hello --image ghcr.io/example/cpybkc-gen-hello:v1 \
generate --source . export --path .
The variable this exists for
SOURCE_DATE_EPOCH, and the reason is a promise made elsewhere. cpybkc passes
its own environment through to a generator unchanged — it adds no variable,
removes none and names none — and that pass-through is how
docs/plugin/SPEC.md propagates the timestamp its determinism requirement rests
on (#47). A generator honouring it produces the same bytes on every run; a
build that has already set it for its other tools has set it for every
generator cpybkc runs. Until this function existed that sentence was false for
a build going through this module, and there was no way to make it true
without dropping out of the module to edit a container (#252) — which is not a
chain dagger call can express, so it meant an SDK program or nothing.
Any variable, rather than that one
This takes a name and a value instead of a typed –source-date-epoch, which is the wider of the two shapes #252 put up and the one the mirroring stance settles on. The CLI has no flag for this: it reads its whole environment and hands it on, so the capability to mirror is an environment and not a timestamp (#253). A single typed argument would have been this module deciding which variables may reach a generator, which is a reading of docs/plugin/SPEC.md kept out here where it would drift — the same reason the format argument passes an unknown encoding through to be refused by the parser that decides them rather than screening it first.
It also would not have been the narrower thing it looks like. A caller who
wants any other variable still has image and a container of their own; what
a typed argument buys is not that the door is shut but that the ordinary route
through it is missing, which is how a promise ends up kept for one variable and
broken for the build that needed a second.
What the wide shape does not do is make the environment a place to configure a generator. docs/cli/SPEC.md and docs/plugin/SPEC.md both forbid a plugin to require a variable for its normal work — everything that configures its output arrives as –opt, because the manifest is the reviewable record of how a project’s code was generated and a setting living in the environment is absent from it. That prohibition binds generator authors and is unaffected by this function: cpybkc has always passed the whole environment through, so the door this opens is one the CLI already had, and a module refusing it would make a generator no more compliant while making the mirror less honest.
Which runs it reaches, and which of them start a generator
Every function on this module, because the variable is set on the container they all run in rather than passed to one of them. That is the CLI’s own arrangement — cpybkc is started with an environment, not a command — and it is stated here rather than left to fall out of the implementation.
Generate is the one where it matters, because it is the one that starts a
generator. Init runs none at all (docs/cli/SPEC.md, “init reads no
manifest”), and EmitIr resolves none either, since an emission is terminal
(“Emitting replaces generation”); Run starts one exactly when the vector it was
handed asks for a generation. So on three of the four the variable reaches
cpybkc and stops there, which is what “the environment cpybkc was started with”
means and is why they are not carved out: a builder that refused to set a
variable for a run that would not have read it would be inventing a rule the
CLI does not have, and the caller would have to know which functions resolve
generators to predict it.
Repeated calls compose, in the order they are written, and a name given twice takes the second value — a container’s environment is a mapping, and the last write to a key wins.
One variable is worth naming, because its failure lands a long way from the call that caused it. PATH is how the CLI finds a generator, and in a composed image it is the plugin directory WithGenerator installed into — so a caller who states PATH here is overwriting an arrangement this module made, and the symptom is a generation failing with cpybkc reporting that a generator the manifest plainly names cannot be found. That is not a reason to refuse the name: a module deciding which variables may reach a generator is what the section above rejects, and the same is true of anything else the image’s entrypoint depends on. It is a reason to say so here, so that a caller who does it can recognise what they did.
The name is checked for the shapes that are not a name in any environment
(empty, or carrying = or NUL) and the value for the one shape that is not a
value in any environment (NUL, which truncates the string it is in). Nothing
else about either is this module’s business — in particular a value may
contain =. See internal/env.
Return Type
Cpybkc !Arguments
| Name | Type | Default Value | Description |
|---|---|---|---|
| name | String ! | - | The variable’s name, as a generator would read it — SOURCE_DATE_EPOCH for the reproducible timestamp that is this function’s reason to exist. |
| value | String ! | - | The value it is set to. It is passed through as written and never interpreted here: what a variable means is the generator’s, and even SOURCE_DATE_EPOCH is a count of seconds this module has no business parsing — a value cpybkc would have carried is one this module carries. |
Example
dagger -m github.com/Zaba505/cpybkc/daggerverse/cpybkc@0540e3da826efb9d038330e4f4291ee10065f2c7 call \
with-env-variable --name string --value stringfunc (m *MyModule) Example(name string, value string) *dagger.Cpybkc {
return dag.
Cpybkc().
Withenvvariable(name, value)
}@function
def example(name: str, value: str) -> dagger.Cpybkc:
return (
dag.cpybkc()
.withenvvariable(name, value)
)@func()
example(name: string, value: string): Cpybkc {
return dag
.cpybkc()
.withEnvVariable(name, value)
}withGenerator() 🔗
WithGenerator adds one generator to the image by copying its executable out of a generator image:
dagger call -m github.com/Zaba505/cpybkc/daggerverse/cpybkc \
with-generator --name hello --image ghcr.io/example/cpybkc-gen-hello:v1 \
generate --source . export --path .
This is the whole of adding a generator without writing a Dockerfile. The file
is taken out of the image at the path the base-image contract promises, which
is what COPY --from does, and it works just as well for a generator image
this project has never heard of — that is what image is for. Repeated calls
compose, so a project whose manifest names three generators is three calls and
one image.
With no image, the generator this project publishes for name is pulled:
<repository>-gen-<name>:<version>, against the same coordinates the CLI image
came from. A generator from one release beside a CLI from another is a pairing
nobody tested, and defaulting to it is how somebody would end up in one without
having said so.
The generator is pulled for the platform the container being composed into was resolved for, not for the engine’s. That is the whole of what this module does about multi-platform: composing an amd64 generator into an arm64 image produces an image that builds and pushes and then fails at exec with the kernel’s message rather than cpybkc’s, which is a long way from the call that caused it.
Return Type
Cpybkc !Arguments
| Name | Type | Default Value | Description |
|---|---|---|---|
| name | String ! | - | The generator to add, by the |
| image | Container | - | Take the executable from this image instead of pulling the published generator image for name. Any image carrying the generator in the plugin directory will do, including one that was never published. It has to be for the same platform as the image being composed into, which is checked, because a mismatch here is checkable and its exec-time failure is not legible. |
Example
dagger -m github.com/Zaba505/cpybkc/daggerverse/cpybkc@0540e3da826efb9d038330e4f4291ee10065f2c7 call \
with-generator --name stringfunc (m *MyModule) Example(name string) *dagger.Cpybkc {
return dag.
Cpybkc().
Withgenerator(name)
}@function
def example(name: str) -> dagger.Cpybkc:
return (
dag.cpybkc()
.withgenerator(name)
)@func()
example(name: string): Cpybkc {
return dag
.cpybkc()
.withGenerator(name)
}withGeneratorExecutable() 🔗
WithGeneratorExecutable adds one generator to the image from an executable file, for a generator that ships no image — most often one the caller has just built in the same pipeline:
dagger call -m github.com/Zaba505/cpybkc/daggerverse/cpybkc \
with-generator-executable --name hello --executable ./cpybkc-gen-hello \
generate --source . export --path .
It is the generator author’s path, before there is anything of theirs to pull. Checking a plugin against a real cpybkc run is the first thing they need and the last thing a published image can give them.
The file lands as cpybkc-gen- whatever it was called before, because discovery is by filename and nothing inside the executable is consulted.
It has to be a statically linked native executable for the image’s platform,
and that is the caller’s to meet rather than this module’s to check: it is the
same requirement docs/container/SPEC.md’s worked example states as
CGO_ENABLED=0, a File says nothing about what it is, and a dynamically linked
or foreign-architecture generator fails at exec time with the kernel’s message
rather than cpybkc’s. WithGenerator can check the platform half of that because
a container states one; here there is nothing to read.
Return Type
Cpybkc !Arguments
| Name | Type | Default Value | Description |
|---|---|---|---|
| name | String ! | - | The generator’s |
| executable | File ! | - | The generator executable. |
Example
dagger -m github.com/Zaba505/cpybkc/daggerverse/cpybkc@0540e3da826efb9d038330e4f4291ee10065f2c7 call \
with-generator-executable --name string --executable file:pathfunc (m *MyModule) Example(name string, executable *dagger.File) *dagger.Cpybkc {
return dag.
Cpybkc().
Withgeneratorexecutable(name, executable)
}@function
def example(name: str, executable: dagger.File) -> dagger.Cpybkc:
return (
dag.cpybkc()
.withgeneratorexecutable(name, executable)
)@func()
example(name: string, executable: File): Cpybkc {
return dag
.cpybkc()
.withGeneratorExecutable(name, executable)
}