diff --git a/.tools/cmd/updater/updater.go b/.tools/cmd/updater/updater.go index a9214a8..4e63f5d 100644 --- a/.tools/cmd/updater/updater.go +++ b/.tools/cmd/updater/updater.go @@ -132,8 +132,9 @@ func entrypoint(cmd *cobra.Command, args []string) error { } executor := steps.NewExecutor(log, ceSteps, &steps.ExecutorInput{ - OriginalEbuild: e, - LatestVersion: latestVersion, + OriginalEbuild: e, + ExistingEbuilds: ebuilds, + LatestVersion: latestVersion, }) res, err := executor.Run(ctx) if err != nil { diff --git a/.tools/internal/ebuild/ebuild.go b/.tools/internal/ebuild/ebuild.go index a1e7c93..dd32449 100644 --- a/.tools/internal/ebuild/ebuild.go +++ b/.tools/internal/ebuild/ebuild.go @@ -45,6 +45,9 @@ type Ebuild struct { // Raw is the raw ebuild file as it was read from the filesystem. Raw []byte + // RawName is the raw name of the ebuild as derived from the filename. + RawName string + // EAPI is the EAPI[1] of the ebuild. Only 8 is currently supported. // // [1]: https://wiki.gentoo.org/wiki/EAPI @@ -181,6 +184,7 @@ func parse(fileName string, b []byte) (*Ebuild, error) { // create the ebuild structure from known variables. ebuild := &Ebuild{ Raw: b, + RawName: filepath.Base(fileName), EAPI: eapiInt, Name: name, Category: filepath.Base(filepath.Dir(filepath.Dir(fileName))), diff --git a/.tools/internal/steps/ebuild_step.go b/.tools/internal/steps/ebuild_step.go index b06b3c2..2788bef 100644 --- a/.tools/internal/steps/ebuild_step.go +++ b/.tools/internal/steps/ebuild_step.go @@ -57,7 +57,9 @@ func (e EbuildStep) Run(ctx context.Context, env Environment) (*StepOutput, erro env.log.Info("generating manifest") if err := stepshelpers.RunCommandInContainer(ctx, env.containerID, - "bash", "/generate-manifest.sh", env.in.OriginalEbuild.Category+"/"+env.in.OriginalEbuild.Name, e.path, env.in.LatestVersion, + "bash", "/generate-manifest.sh", + env.in.OriginalEbuild.Category+"/"+env.in.OriginalEbuild.Name, e.path, + WellKnownExistingEbuilds, env.in.LatestVersion, ); err != nil { return nil, fmt.Errorf("failed to generate manifest: %w", err) } diff --git a/.tools/internal/steps/embed/generate-manifest.sh b/.tools/internal/steps/embed/generate-manifest.sh index e93c356..cef11d3 100644 --- a/.tools/internal/steps/embed/generate-manifest.sh +++ b/.tools/internal/steps/embed/generate-manifest.sh @@ -21,17 +21,18 @@ EBUILD_NAME="$1" # EBUILD_PATH is the path to the ebuild file that should be used. EBUILD_PATH="$2" +EXISTING_EBUILDS_PATH="$3" + # EBUILD_LATEST_VERSION is the latest version of the ebuild. -EBUILD_LATEST_VERSION="$3" +EBUILD_LATEST_VERSION="$4" # MANIFEST_WRITE_PATH is the path to the manifest file that will be # written to and read out of by the updater. MANIFEST_WRITE_PATH="/.well-known/Manifest" -portdir="/src/fake_portdir/$EBUILD_NAME" -mkdir -p "$portdir" +portdir="/src/fake_portdir" +mkdir -p "$portdir/$EBUILD_NAME" "$portdir/metadata" -mkdir -p "$portdir/metadata" # TODO(jaredallard): This should match the repo. cat >"$portdir/metadata/layout.conf" </dev/null || exit 1 -ebuild_path="$(basename "$EBUILD_NAME")-$EBUILD_LATEST_VERSION.ebuild" -cp "$EBUILD_PATH" "$ebuild_path" -chown -R portage:portage . -ebuild "$ebuild_path" manifest +pushd "$portdir/$EBUILD_NAME" >/dev/null || exit 1 + +new_ebuild_path="$(basename "$EBUILD_NAME")-$EBUILD_LATEST_VERSION.ebuild" + +# Setup the dir to match what was on the host. +cp "$EBUILD_PATH" "$new_ebuild_path" +cp -v "$EXISTING_EBUILDS_PATH"/* . +chown -R portage:portage "$portdir" + +# Generate manifest for each ebuild. +for ebuild in *.ebuild; do + echo " :: Generating manifest for $ebuild" + ebuild "$ebuild" manifest +done + +# Write to the manifest file to be read out of later. mkdir -p "$(dirname "$MANIFEST_WRITE_PATH")" cp Manifest "$MANIFEST_WRITE_PATH" + popd >/dev/null || exit 1 diff --git a/.tools/internal/steps/executor.go b/.tools/internal/steps/executor.go index 40583dc..920f274 100644 --- a/.tools/internal/steps/executor.go +++ b/.tools/internal/steps/executor.go @@ -29,6 +29,13 @@ import ( dockerclient "github.com/docker/docker/client" ) +const ( + // WellKnownExistingEbuilds is the path in the container where + // existing ebuilds are stored for a package. These are older versions + // of the current ebuild. + WellKnownExistingEbuilds = "/.well-known/existing-ebuilds" +) + // Executor runs the provided steps inside of a Docker container. type Executor struct { log *logger.Logger @@ -57,6 +64,10 @@ type ExecutorInput struct { // generating a new one. OriginalEbuild *ebuild.Ebuild + // ExistingEbuilds is a list of existing ebuilds that are already + // present that AREN'T the original ebuild. + ExistingEbuilds []*ebuild.Ebuild + // LatestVersion is the latest version of the package. LatestVersion string } diff --git a/.tools/internal/steps/original_ebuild_step.go b/.tools/internal/steps/original_ebuild_step.go index 1742491..2ea9dec 100644 --- a/.tools/internal/steps/original_ebuild_step.go +++ b/.tools/internal/steps/original_ebuild_step.go @@ -25,6 +25,8 @@ import ( // OriginalEbuildStep is a step that writes the source ebuild into the // filesystem of the container at the provided path. +// +// Also populates the existing ebuilds directory for usage later. type OriginalEbuildStep struct { // path is the path to write the ebuild to in the container. path string @@ -47,5 +49,19 @@ func (e OriginalEbuildStep) Run(ctx context.Context, env Environment) (*StepOutp outputPath = filepath.Join(env.workDir, e.path) } - return nil, stepshelpers.CopyFileBytesToContainer(ctx, env.containerID, env.in.OriginalEbuild.Raw, outputPath) + if err := stepshelpers.CopyFileBytesToContainer(ctx, env.containerID, env.in.OriginalEbuild.Raw, outputPath); err != nil { + return nil, fmt.Errorf("failed to copy ebuild to container: %w", err) + } + + // Best effort create the existing ebuilds directory. + stepshelpers.RunCommandInContainer(ctx, env.containerID, "mkdir", "-p", WellKnownExistingEbuilds) + + for _, e := range env.in.ExistingEbuilds { + env.log.With("ebuild", e.RawName).Debug("copying existing ebuild to container") + if err := stepshelpers.CopyFileBytesToContainer(ctx, env.containerID, e.Raw, filepath.Join(WellKnownExistingEbuilds, e.RawName)); err != nil { + return nil, fmt.Errorf("failed to copy existing ebuild to container: %w", err) + } + } + + return &StepOutput{}, nil } diff --git a/Dockerfile b/Dockerfile index 6b4aa91..4ab6f3a 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,7 +1,9 @@ # Used as the base image for elint and updater. FROM gentoo/stage3 WORKDIR "/src/updater" -ENTRYPOINT [ "/usr/local/bin/updater" ] -RUN emerge-webrsync -RUN emerge -v dev-vcs/git && ACCEPT_KEYWORDS="~amd64 ~arm64" emerge -v app-portage/pycargoebuild \ No newline at end of file +RUN emerge-webrsync && \ + emerge -v dev-vcs/git && \ + ACCEPT_KEYWORDS="~amd64 ~arm64" emerge -v app-portage/pycargoebuild && \ + emerge -v app-portage/gentoolkit && \ + eclean --deep packages && eclean --deep distfiles