Skip to content

Replace Spec with RecipeSpec and PackageSpec#1295

Merged
jrray merged 4 commits intomainfrom
recipe-and-package-specs
Dec 10, 2025
Merged

Replace Spec with RecipeSpec and PackageSpec#1295
jrray merged 4 commits intomainfrom
recipe-and-package-specs

Conversation

@jrray
Copy link
Collaborator

@jrray jrray commented Nov 25, 2025

This is the first step towards having separate types for the different variations of specs that are valid in specific contexts. These changes will be done in a series of PRs to limit the diff size of each change.

In this PR the focus is on embedded packages. In a recipe, an embedded package spec in a recipe spec is expected to be given a VersionIdent, as in:

install:
  embedded:
    - pkg: example/1.0.0

It is now illegal to specify a build id for an embedded package in a recipe.

When the package is built, the embedded package in a package spec is a BuildIdent to reflect the idea that the embedded package is "built", such as:

install:
  embedded:
    - pkg: example/1.0.0/embedded

Test content has been updated appropriately since this was not enforced previously.

What is allowed in the build: and install: sections of an embedded package is different from a regular package, so EmbeddedRecipeSpec and EmbeddedPackageSpec model those differences. These contain EmbeddedBuildSpec and EmbeddedInstallSpec.

An EmbeddedInstallSpec does not contain an embedded field, making it impossible to nest embedded packages.

EmbeddedPackagesList gained a generic parameter for the type of spec it contains so it can be reused for the two flavors of embedded specs.

Package::components() was moved to its own trait to make is possible to not have Package implemented for embedded packages. Note that when embedded packages are turned into stubs, the stubs are normal packages that implement Package.

All the new types were created in the v0 module since they are part of the v0/package API. The types like BuildSpec and InstallSpec should arguably have been defined in v0 as well.

These new types were created by copying and modifying the existing types (and tests) and I haven't (at this point) done the work to remove duplicate or unused code.

@jrray jrray self-assigned this Nov 25, 2025
@jrray jrray added the maintenance Cleanup, upgrades, etc label Nov 25, 2025
@jrray jrray force-pushed the recipe-and-package-specs branch from 8f67468 to 77f8db0 Compare November 25, 2025 19:53
@jrray jrray force-pushed the recipe-and-package-specs branch from 77f8db0 to d1dc29f Compare November 25, 2025 20:32
@jrray
Copy link
Collaborator Author

jrray commented Nov 25, 2025

@rydrman this got a bit gory but is a design change that has come up in the meeting more than once. Like how #1294 enables this, this change is something I wanted to do to make yet another thing I'm working on easier to implement.

@jrray jrray force-pushed the recipe-and-package-specs branch from 5de59ee to 6e44792 Compare November 29, 2025 06:53
jrray added a commit that referenced this pull request Nov 30, 2025
This takes advantage of the work in #1295 in order to guarantee via
types that var requirements have values in the context of a package
requirements.

The `PinnableRequest` type is what was previously called `Request`. This
models what can appear in the install.requirements section of a recipe,
as in:

```yaml
# in a recipe
install:
  requirements:
    - var: foo
      fromBuildEnv: true
```

When the package is built then a value must have been provided via
options somewhere, and so the var becomes "pinned":

```yaml
# in a package
install:
  requirements:
    - var: foo/bar
```

While previously all code that operated on a `Request` would have to
contend with the type allowing for the value to be missing (or not yet
pinned), now a `PinnedRequest` is used that guarantees the value is
present.

This change also enforces via the type system that when a recipe is
turned into a package that all the requirements are pinned.

`PinnedRequest` did not get a different type for its `Pkg` variant
(yet?), but it also has a similar pinned/unpinned concept.

Signed-off-by: J Robert Ray <jrray@jrray.org>
@jrray jrray force-pushed the recipe-and-package-specs branch from 6e44792 to 8292908 Compare November 30, 2025 10:22
jrray added a commit that referenced this pull request Nov 30, 2025
This takes advantage of the work in #1295 in order to guarantee via
types that var requirements have values in the context of a package
requirements.

The `PinnableRequest` type is what was previously called `Request`. This
models what can appear in the install.requirements section of a recipe,
as in:

```yaml
# in a recipe
install:
  requirements:
    - var: foo
      fromBuildEnv: true
```

When the package is built then a value must have been provided via
options somewhere, and so the var becomes "pinned":

```yaml
# in a package
install:
  requirements:
    - var: foo/bar
```

While previously all code that operated on a `Request` would have to
contend with the type allowing for the value to be missing (or not yet
pinned), now a `PinnedRequest` is used that guarantees the value is
present.

This change also enforces via the type system that when a recipe is
turned into a package that all the requirements are pinned.

`PinnedRequest` did not get a different type for its `Pkg` variant
(yet?), but it also has a similar pinned/unpinned concept.

Signed-off-by: J Robert Ray <jrray@jrray.org>
@jrray jrray force-pushed the recipe-and-package-specs branch from 8292908 to cf80ac3 Compare December 1, 2025 09:07
Copy link
Collaborator

@rydrman rydrman left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll mention that I didn't review much in the way of logic here, based on the copy-pasting notes that you made above. But if you were particularly nervous about anything let me know. Otherwise, I looked mostly at the structs, fields and new limitation in the embedded specs.

Comment on lines +70 to +72

#[derive(Debug, Clone, Hash, PartialEq, Eq, Ord, PartialOrd, Serialize)]
pub struct PackageSpec {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just noting that some of these "top-level" structs don't have any descriptions, might be a useful addition if you are feeling inclined

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah yes, the "source material" for the new content didn't have doc strings either, but no doubt it would be good to have.

Thanks for the approval. I'm not nervous yet about this effort because I believe all of these changes are backwards compatible. My priority is getting #1296 merged so I can keep my promise of delivering that feature by the end of the year.

@jrray jrray force-pushed the recipe-and-package-specs branch 2 times, most recently from 80f5787 to 3de2d63 Compare December 10, 2025 20:20
This is the first step towards having separate types for the different
variations of specs that are valid in specific contexts. These changes
will be done in a series of PRs to limit the diff size of each change.

In this PR the focus is on embedded packages. In a recipe, an embedded
package spec in a recipe spec is expected to be given a `VersionIdent`,
as in:

```yaml
install:
  embedded:
    - pkg: example/1.0.0
```

It is now illegal to specify a build id for an embedded package in a
recipe.

When the package is built, the embedded package in a package spec is a
`BuildIdent` to reflect the idea that the embedded package is "built",
such as:

```yaml
install:
  embedded:
    - pkg: example/1.0.0/embedded
```

Test content has been updated appropriately since this was not enforced
previously.

What is allowed in the `build:` and `install:` sections of an embedded
package is different from a regular package, so `EmbeddedRecipeSpec`
and `EmbeddedPackageSpec` model those differences. These contain
`EmbeddedBuildSpec` and `EmbeddedInstallSpec`.

An `EmbeddedInstallSpec` does not contain an `embedded` field, making it
impossible to nest embedded packages.

`EmbeddedPackagesList` gained a generic parameter for the type of spec
it contains so it can be reused for the two flavors of embedded specs.

`Package::components()` was moved to its own trait to make is possible
to not have `Package` implemented for embedded packages. Note that when
embedded packages are turned into stubs, the stubs are normal packages
that implement `Package`.

All the new types were created in the `v0` module since they are part of
the `v0/package` API. The types like `BuildSpec` and `InstallSpec`
should arguably have been defined in `v0` as well.

These new types were created by copying and modifying the existing types
(and tests) and I haven't (at this point) done the work to remove
duplicate or unused code.

Signed-off-by: J Robert Ray <jrray@jrray.org>
Eliminate some duplicate code.

Signed-off-by: J Robert Ray <jrray@jrray.org>
Coverage testing shows that this is unused.

Signed-off-by: J Robert Ray <jrray@jrray.org>
As seen from coverage tests.

Signed-off-by: J Robert Ray <jrray@jrray.org>
@jrray jrray force-pushed the recipe-and-package-specs branch from 3de2d63 to 11ce6cb Compare December 10, 2025 20:47
@jrray jrray merged commit e35f540 into main Dec 10, 2025
9 checks passed
@jrray jrray deleted the recipe-and-package-specs branch December 10, 2025 21:20
jrray added a commit that referenced this pull request Dec 10, 2025
This takes advantage of the work in #1295 in order to guarantee via
types that var requirements have values in the context of a package
requirements.

The `PinnableRequest` type is what was previously called `Request`. This
models what can appear in the install.requirements section of a recipe,
as in:

```yaml
# in a recipe
install:
  requirements:
    - var: foo
      fromBuildEnv: true
```

When the package is built then a value must have been provided via
options somewhere, and so the var becomes "pinned":

```yaml
# in a package
install:
  requirements:
    - var: foo/bar
```

While previously all code that operated on a `Request` would have to
contend with the type allowing for the value to be missing (or not yet
pinned), now a `PinnedRequest` is used that guarantees the value is
present.

This change also enforces via the type system that when a recipe is
turned into a package that all the requirements are pinned.

`PinnedRequest` did not get a different type for its `Pkg` variant
(yet?), but it also has a similar pinned/unpinned concept.

Signed-off-by: J Robert Ray <jrray@jrray.org>
jrray added a commit that referenced this pull request Dec 10, 2025
This takes advantage of the work in #1295 in order to guarantee via
types that var requirements have values in the context of a package
requirements.

The `PinnableRequest` type is what was previously called `Request`. This
models what can appear in the install.requirements section of a recipe,
as in:

```yaml
# in a recipe
install:
  requirements:
    - var: foo
      fromBuildEnv: true
```

When the package is built then a value must have been provided via
options somewhere, and so the var becomes "pinned":

```yaml
# in a package
install:
  requirements:
    - var: foo/bar
```

While previously all code that operated on a `Request` would have to
contend with the type allowing for the value to be missing (or not yet
pinned), now a `PinnedRequest` is used that guarantees the value is
present.

This change also enforces via the type system that when a recipe is
turned into a package that all the requirements are pinned.

`PinnedRequest` did not get a different type for its `Pkg` variant
(yet?), but it also has a similar pinned/unpinned concept.

Signed-off-by: J Robert Ray <jrray@jrray.org>
jrray added a commit that referenced this pull request Dec 10, 2025
This takes advantage of the work in #1295 in order to guarantee via
types that var requirements have values in the context of a package
requirements.

The `PinnableRequest` type is what was previously called `Request`. This
models what can appear in the install.requirements section of a recipe,
as in:

```yaml
# in a recipe
install:
  requirements:
    - var: foo
      fromBuildEnv: true
```

When the package is built then a value must have been provided via
options somewhere, and so the var becomes "pinned":

```yaml
# in a package
install:
  requirements:
    - var: foo/bar
```

While previously all code that operated on a `Request` would have to
contend with the type allowing for the value to be missing (or not yet
pinned), now a `PinnedRequest` is used that guarantees the value is
present.

This change also enforces via the type system that when a recipe is
turned into a package that all the requirements are pinned.

`PinnedRequest` did not get a different type for its `Pkg` variant
(yet?), but it also has a similar pinned/unpinned concept.

Signed-off-by: J Robert Ray <jrray@jrray.org>
jrray added a commit that referenced this pull request Dec 11, 2025
This takes advantage of the work in #1295 in order to guarantee via
types that var requirements have values in the context of a package
requirements.

The `PinnableRequest` type is what was previously called `Request`. This
models what can appear in the install.requirements section of a recipe,
as in:

```yaml
# in a recipe
install:
  requirements:
    - var: foo
      fromBuildEnv: true
```

When the package is built then a value must have been provided via
options somewhere, and so the var becomes "pinned":

```yaml
# in a package
install:
  requirements:
    - var: foo/bar
```

While previously all code that operated on a `Request` would have to
contend with the type allowing for the value to be missing (or not yet
pinned), now a `PinnedRequest` is used that guarantees the value is
present.

This change also enforces via the type system that when a recipe is
turned into a package that all the requirements are pinned.

`PinnedRequest` did not get a different type for its `Pkg` variant
(yet?), but it also has a similar pinned/unpinned concept.

Signed-off-by: J Robert Ray <jrray@jrray.org>
jrray added a commit that referenced this pull request Dec 17, 2025
This takes advantage of the work in #1295 in order to guarantee via
types that var requirements have values in the context of a package
requirements.

The `PinnableRequest` type is what was previously called `Request`. This
models what can appear in the install.requirements section of a recipe,
as in:

```yaml
# in a recipe
install:
  requirements:
    - var: foo
      fromBuildEnv: true
```

When the package is built then a value must have been provided via
options somewhere, and so the var becomes "pinned":

```yaml
# in a package
install:
  requirements:
    - var: foo/bar
```

While previously all code that operated on a `Request` would have to
contend with the type allowing for the value to be missing (or not yet
pinned), now a `PinnedRequest` is used that guarantees the value is
present.

This change also enforces via the type system that when a recipe is
turned into a package that all the requirements are pinned.

`PinnedRequest` did not get a different type for its `Pkg` variant
(yet?), but it also has a similar pinned/unpinned concept.

Signed-off-by: J Robert Ray <jrray@jrray.org>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

maintenance Cleanup, upgrades, etc

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants