Skip to content

Commit

Permalink
feat(compute/build): Support 'upper bound' constraints on Rust versions.
Browse files Browse the repository at this point in the history
Changes planned in the upcoming Rust 1.84 release may not be
compatible with the Fastly Compute platform (until further analysis is
done, which may result in the need for platform changes). To ensure
that customers do not build Compute packages which do not operate
correctly in the platform, this PR adds a toolchain version constraint
"upper bound" in addition to the existing "lower bound", only for
Rust.

The upper bound is currently set to "<1.84.0", so any versions
currently available, plus all releases of Rust 1.83.x, will be
permitted. Because this is a hard requirement of the platform, the
check has been changed to report an error (not a warning), if the
version of Rust in use does not meet the requirements. While this is
potentially a breaking change (since the 'fastly compute build'
process will stop, instead of continuing), it can only affect users
with Rust versions older than 1.56.1, which are not actually usable at
this time anyway.

In addition, this PR changes the messages generated for both Go and
Rust version-constraint failures to include the details of how the
check failed.
  • Loading branch information
kpfleming committed Nov 20, 2024
1 parent 3c7d993 commit 1ad7fac
Show file tree
Hide file tree
Showing 3 changed files with 28 additions and 17 deletions.
2 changes: 1 addition & 1 deletion .fastly/config.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ toolchain_constraint = ">= 1.21" # Go toolchain constraint for use wit
toolchain_constraint_tinygo = ">= 1.18" # Go toolchain constraint for use with TinyGo.

[language.rust]
toolchain_constraint = ">= 1.56.1"
toolchain_constraint = ">= 1.56.1, <1.84.0"
wasm_wasi_target = "wasm32-wasi"

[wasm-tools]
Expand Down
6 changes: 4 additions & 2 deletions pkg/commands/compute/language_go.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package compute

import (
"bufio"
"errors"
"fmt"
"io"
"os"
Expand Down Expand Up @@ -315,7 +316,8 @@ func (g *Go) toolchainConstraint(toolchain, pattern, constraint string) {
return
}

if !c.Check(v) {
text.Warning(g.output, "The %s version '%s' didn't meet the constraint '%s'\n\n", toolchain, version, constraint)
valid, errs := c.Validate(v)
if !valid {
text.Warning(g.output, "The %s version requirement was not satisfied: %s", toolchain, errors.Join(errs...))
}
}
37 changes: 23 additions & 14 deletions pkg/commands/compute/language_rust.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package compute
import (
"bytes"
"encoding/json"
"errors"
"fmt"
"io"
"os"
Expand Down Expand Up @@ -157,7 +158,10 @@ func (r *Rust) Build() error {
text.Info(r.output, "No [scripts.build] found in %s. The following default build command for Rust will be used: `%s`\n\n", r.manifestFilename, r.build)
}

version := r.toolchainConstraint()
version, err := r.toolchainConstraint()
if err != nil {
return err
}

if version != nil {
err := r.checkCargoConfigFileName(version)
Expand Down Expand Up @@ -296,12 +300,8 @@ func (r *Rust) modifyCargoPackageName(noBuildScript bool) error {
return nil
}

// toolchainConstraint warns the user if the required constraint is not met.
//
// NOTE: We don't stop the build as their toolchain may compile successfully.
// The warning is to help a user know something isn't quite right and gives them
// the opportunity to do something about it if they choose.
func (r *Rust) toolchainConstraint() *semver.Version {
// toolchainConstraint generates an error if the toolchain constraint is not met.
func (r *Rust) toolchainConstraint() (*semver.Version, error) {
if r.verbose {
text.Info(r.output, "The Fastly CLI requires a Rust version '%s'.\n\n", r.config.ToolchainConstraint)
}
Expand All @@ -318,31 +318,40 @@ func (r *Rust) toolchainConstraint() *semver.Version {
stdout, err := cmd.Output()
output := string(stdout)
if err != nil {
return nil
return nil, err
}

versionPattern := regexp.MustCompile(`cargo (?P<version>\d[^\s]+)`)
match := versionPattern.FindStringSubmatch(output)
if len(match) < 2 { // We expect a pattern with one capture group.
return nil
return nil, fmt.Errorf("unable to obtain a version number from the 'cargo' command")
}
version := match[1]

v, err := semver.NewVersion(version)
if err != nil {
return nil
return nil, fmt.Errorf("the version string '%s' reported by the 'cargo' command is not a valid version number", version)
}

c, err := semver.NewConstraint(r.config.ToolchainConstraint)
if err != nil {
return nil
return nil, fmt.Errorf("the 'toolchain_constraint' value '%s' (from the config.toml file) is not a valid version constraint", r.config.ToolchainConstraint)
}

if !c.Check(v) {
text.Warning(r.output, "The Rust version '%s' didn't meet the constraint '%s'\n\n", version, r.config.ToolchainConstraint)
valid, errs := c.Validate(v)
if !valid {
for _, err = range errs {
// if an 'upper bound' constraint was
// violated, generate an error message
// specific to that situation
if strings.Contains(err.Error(), "is greater than") {
return nil, fmt.Errorf("version '%s' of Rust has not been validated for use with Fastly Compute", v)
}
}
return nil, fmt.Errorf("the Rust version requirement was not satisfied: '%w'", errors.Join(errs...))
}

return v
return v, nil
}

func (r *Rust) checkCargoConfigFileName(rustVersion *semver.Version) error {
Expand Down

0 comments on commit 1ad7fac

Please sign in to comment.