build(lint): first pass at linter without requiring volume mounts
All checks were successful
Test / elint (push) Successful in 38s
All checks were successful
Test / elint (push) Successful in 38s
act, much like CircleCI, doesn't allow us to have easily accessible volume mounts between the CI system and the Docker host. So, much like the build of the updater, the linter now no longer requires volume mounts to lint ebuilds. This implementation is decently ineffecient and will be improved over time.
This commit is contained in:
parent
21e1d47d5f
commit
c4274316fa
2 changed files with 90 additions and 23 deletions
|
@ -4,7 +4,7 @@
|
|||
#
|
||||
# Valid exit codes are:
|
||||
# 0 - Manifest is up-to-date and valid
|
||||
# 1 - General error ocurring during validation
|
||||
# 1 - General error occurring during validation
|
||||
# 2 - Manifest is invalid or out-of-sync
|
||||
#
|
||||
# Usage: verify-manifest.sh [package-dir]
|
||||
|
|
|
@ -16,10 +16,17 @@
|
|||
package ebuild
|
||||
|
||||
import (
|
||||
"context"
|
||||
_ "embed"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/fs"
|
||||
"os/exec"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/jaredallard/overlay/.tools/internal/steps/stepshelpers"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
|
@ -27,7 +34,7 @@ import (
|
|||
// Manifest files.
|
||||
//
|
||||
//go:embed embed/verify-manifest.sh
|
||||
var manifestValidationScript string
|
||||
var manifestValidationScript []byte
|
||||
|
||||
// gentooImage is the docker image used for validating Manifest files.
|
||||
var gentooImage = "ghcr.io/jaredallard/overlay:updater"
|
||||
|
@ -39,29 +46,89 @@ var (
|
|||
ErrManifestInvalid = errors.New("manifest is out of date or invalid")
|
||||
)
|
||||
|
||||
// ValidateManifest ensures that the manifest at the provided path is
|
||||
// valid for the given ebuild. This requires docker to be installed on
|
||||
// the host and running.
|
||||
func ValidateManifest(stdout, stderr io.Writer, packageDir, packageName string) error {
|
||||
cmd := exec.Command(
|
||||
"docker", "run",
|
||||
// Ensures we can use the network-sandbox feature.
|
||||
"--privileged",
|
||||
// Run bash and mount the ebuild repository at a predictable path.
|
||||
"--rm", "--entrypoint", "bash", "-v"+packageDir+":/ebuild/src:ro",
|
||||
gentooImage, "-c", manifestValidationScript, "", packageName,
|
||||
)
|
||||
cmd.Stdout = stdout
|
||||
cmd.Stderr = stderr
|
||||
if err := cmd.Run(); err != nil {
|
||||
var exitErr *exec.ExitError
|
||||
if errors.As(err, &exitErr) {
|
||||
if exitErr.ExitCode() == 2 {
|
||||
return ErrManifestInvalid
|
||||
}
|
||||
// copyDirectoryIntoContainer copies all files in the srcPath/ into
|
||||
// destPath/ in the container.
|
||||
func copyDirectoryIntoContainer(ctx context.Context, containerID, srcPath, destPath string) error {
|
||||
directories := make(map[string]struct{})
|
||||
|
||||
if err := filepath.WalkDir(srcPath, func(path string, d fs.DirEntry, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return errors.Wrap(err, "unknown error while validating manifest")
|
||||
// We skip directories.
|
||||
if d.IsDir() {
|
||||
return nil
|
||||
}
|
||||
|
||||
relPath, err := filepath.Rel(srcPath, path)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not create relative path for %q: %w", path, err)
|
||||
}
|
||||
|
||||
dir := filepath.Dir(relPath)
|
||||
if _, ok := directories[dir]; !ok {
|
||||
if err := stepshelpers.RunCommandInContainer(ctx, containerID, "mkdir", "-p", filepath.Join(destPath, dir)); err != nil {
|
||||
return fmt.Errorf("failed to ensure directory %q: %w", dir, err)
|
||||
}
|
||||
directories[dir] = struct{}{}
|
||||
}
|
||||
|
||||
if err := stepshelpers.CopyFileToContainer(ctx, containerID, filepath.Join(srcPath, relPath), filepath.Join(destPath, relPath)); err != nil {
|
||||
return fmt.Errorf("failed to copy %q into container: %w", relPath, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}); err != nil {
|
||||
return fmt.Errorf("failed to walk srcDir: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ValidateManifest ensures that the manifest at the provided path is
|
||||
// valid for the given ebuild. This requires docker to be installed on
|
||||
// the host and running.
|
||||
func ValidateManifest(stdout, stderr io.Writer, overlayDir, packageName string) error {
|
||||
ctx := context.TODO()
|
||||
|
||||
bid, err := exec.Command(
|
||||
"docker", "run", "-d", "--rm", "--entrypoint", "sleep", gentooImage, "infinity",
|
||||
).Output()
|
||||
if err != nil {
|
||||
var execErr *exec.ExitError
|
||||
if errors.As(err, &execErr) {
|
||||
return fmt.Errorf("failed to run container: %s", string(execErr.Stderr))
|
||||
}
|
||||
|
||||
return fmt.Errorf("failed to run container: %w", err)
|
||||
}
|
||||
containerID := strings.TrimSpace(string(bid))
|
||||
defer exec.Command("docker", "stop", containerID) //nolint:errcheck // Why: best effort
|
||||
|
||||
lclPkgDir := filepath.Join(overlayDir, packageName)
|
||||
|
||||
containerOverlayDir := "/ebuild/src"
|
||||
containerPkgDir := path.Join(containerOverlayDir, packageName)
|
||||
|
||||
if err := copyDirectoryIntoContainer(ctx, containerID, lclPkgDir, containerPkgDir); err != nil {
|
||||
return fmt.Errorf("failed to copy ebuild contents into container: %w", err)
|
||||
}
|
||||
|
||||
if err := copyDirectoryIntoContainer(ctx, containerID, filepath.Join(overlayDir, "metadata"), "/ebuild/src/metadata"); err != nil {
|
||||
return fmt.Errorf("failed to copy metadata directory into container: %w", err)
|
||||
}
|
||||
|
||||
if err := stepshelpers.CopyFileBytesToContainer(ctx, containerID, manifestValidationScript, "/verify-manifest.sh"); err != nil {
|
||||
return fmt.Errorf("failed to copy validation script into container: %w", err)
|
||||
}
|
||||
|
||||
if err := stepshelpers.RunCommandInContainer(ctx, containerID, "chmod", "+x", "/verify-manifest.sh"); err != nil {
|
||||
return fmt.Errorf("failed to mark validation script as executable: %w", err)
|
||||
}
|
||||
|
||||
if err := stepshelpers.RunCommandInContainer(ctx, containerID, "/verify-manifest.sh", packageName); err != nil {
|
||||
return fmt.Errorf("ebuild failed to lint: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
|
|
Loading…
Add table
Reference in a new issue