Add a build command#14
Conversation
It really doesn't need to be inside the init sub-command.
The project metadata allows us to reconstruct the project state at the time of its initialization. Closes: #9
A command that sets up a container for building the given Moonforge project, using the project metadata to find all the required components and files without having to specify them on the command line.
A handy way to set up the configuration per-project or per-user.
The "config" sub-command works similarly to "git config":
- there is a user configuration and a project configuration scope
- the project configuration, if found, takes precedence over the user
configuration
- if no scope is defined, the values are pooled together from project
and user scopes
- if no scope is defined, keys are read from the common pool and written
to the project scope
Examples:
# read from all scopes
moonforge config list
# read from project scope
moonforge config --project get container.engine
# write to the user scope
moonforge config --user set container.engine podman
# read from all scopes, write to the project scope
moonforge config set container.engine podman
Use the project metadata to determine the appropriate kas file to build, and the Moonforge configuration data for the container engine and cache directories.
Ideally, we want this description to be included in the help output. Right now, argparse is making it slightly more difficult than necessary.
If a command has an embedded long description, show it after the basic argument help screen, as a replacement for a manual page.
Kas allows specifying additional fragments alongside the main YAML file. The tricky bit is to normalize the path for each fragment so that its rooted under the volume we use to share the project directory inside the container.
Follow kas-container, and add --runtime-args for passing extra arguments when setting up the runtime.
Needed for maximum conformance.
We depend on Python 3.10 (EOL 2026-10-31), so we can't use typing.Self.
The utils.find_program() function can return None according to the signature, but we use error_if_not_found to ensure that we bail out if we can't find the binary specified inside container.engine in our PATH.
The long description for the command is allowed to go over the column limit.
Exactly like the build command, except: - mounts the repository volume as read-write - uses "kas shell" instead of "kas build"
We may be accessing project attributes, and we don't use anything else from other objects. The alternative would be to put it into utils, but then we'd need to access the Project class from utils.
Use Project.machine.name to expand @MACHINE_NAME@ in build paths.
tchx84
left a comment
There was a problem hiding this comment.
Looking good, but we really need a README with the basics now 🙏
Additionally, I left a few comments for minor things require fixing, and other questions.
|
|
||
|
|
||
| def add_args(parser): | ||
| parser.add_argument("--fragment", metavar="FILE", dest="fragments", |
There was a problem hiding this comment.
Maybe we can have an option to specify the image file?
There was a problem hiding this comment.
Not entirely a fan of the concept; the whole idea is to remove the need to know the image file, since its name is determined by the project name and machine name.
The only case in which I'd see a need for that is building different images for different machines, but currently we don't allow initializing a project with more than one machine. If that were the case, I'd likely add a --machine switch to the build and shell commands.
I understand that we have a bunch of layers that have multiple image files, but those are mainly examples; I don't think you want to have the same inside an actual project. If that were the case, we'd need to have a way to generate image files from additional tokens.
|
|
||
|
|
||
| def add_args(parser): | ||
| parser.add_argument("--fragment", metavar="FILE", dest="fragments", |
There was a problem hiding this comment.
Have you considered keeping kas' colon formatting for fragments?
There was a problem hiding this comment.
I did, but I find the foo:bar:baz format is a bit suspect, especially when the fragments have longer path components.
Point to "moonforge init".
Show how to use "moonforge config" to set various configuration options.
Since we might want to change the project metadata across revisions of moonforge-cli, we should have a way to specify the version that initialised the project, and a way to parse the project metadata depending on that version. Using Rust as an example, the version is called "edition", and its identifier uses a "YYYY.N" format. We use that identifier to determine which fields are known and valid.
There's no point, and it prevents us from transparently updating the defaults.
We start from the user configuration, as the baseline, and then we load
the project configuration, as an override.
If a configuration source does not exist, we skip it; to ensure that
we're using the most appropriate source, we update the configuration
source type when loading them all in sequence, so that:
1. we do not create unnecessary configuration values
2. we do not create unnecessary configuration files
This means that calling:
moonforge config set key value
Inside a project directory will set the project's configuration, while
calling it outside of a project directory will set the user's
configuration.
This way, calling `moonforge config` inside the project will access the project configuration, and we can pre-seed a project with the values we care about.
Allows us to replace our use of kas-container for building Moonforge projects.
Most of the build details can be controlled by the project metadata, and by a configuration file, instead of using environment variables. We can also do better validation of inputs than using a shell script.
Closes: #8