diff --git a/prospero-cli/src/main/java/org/wildfly/prospero/cli/commands/UpdateCommand.java b/prospero-cli/src/main/java/org/wildfly/prospero/cli/commands/UpdateCommand.java index 675181a3..3b9b62b5 100644 --- a/prospero-cli/src/main/java/org/wildfly/prospero/cli/commands/UpdateCommand.java +++ b/prospero-cli/src/main/java/org/wildfly/prospero/cli/commands/UpdateCommand.java @@ -29,6 +29,7 @@ import java.util.stream.Collectors; import org.apache.commons.io.FileUtils; +import org.eclipse.aether.artifact.Artifact; import org.jboss.galleon.ProvisioningException; import org.jboss.galleon.diff.FsDiff; import org.jboss.galleon.diff.FsEntry; @@ -39,6 +40,7 @@ import org.wildfly.channel.ChannelManifest; import org.wildfly.channel.ChannelManifestCoordinate; import org.wildfly.channel.Repository; +import org.wildfly.channel.version.VersionMatcher; import org.wildfly.prospero.ProsperoLogger; import org.wildfly.prospero.actions.ApplyCandidateAction; import org.wildfly.prospero.actions.SubscribeNewServerAction; @@ -60,6 +62,7 @@ import org.wildfly.prospero.api.TemporaryFilesManager; import org.wildfly.prospero.galleon.FeaturePackLocationParser; import org.wildfly.prospero.galleon.GalleonUtils; +import org.wildfly.prospero.metadata.ManifestVersionRecord; import org.wildfly.prospero.metadata.ProsperoMetadataUtils; import org.wildfly.prospero.model.InstallationProfile; import org.wildfly.prospero.updates.UpdateSet; @@ -120,7 +123,6 @@ public Integer call() throws Exception { log.tracef("Perform full update"); console.println(CliMessages.MESSAGES.updateHeader(installationDir)); - try (UpdateAction updateAction = actionFactory.update(installationDir, mavenOptions, console, repositories)) { performUpdate(updateAction, yes, console, installationDir, noConflictsOnly); } @@ -136,6 +138,17 @@ private boolean performUpdate(UpdateAction updateAction, boolean yes, CliConsole Path targetDir = null; try { targetDir = Files.createTempDirectory("update-candidate"); + try (InstallationMetadata installationMetadata = updateAction.getInstallationMetadata()) { + if (installationMetadata.getManifestVersions().isPresent()) { + List mavenManifests = installationMetadata.getManifestVersions().get().getMavenManifests(); + final List manifestUpdates = updateAction.findCurrentChannelSessionManifests(); + if (!isManifestDowngraded(mavenManifests, manifestUpdates)) { + console.println("Downgrade detected. Aborting update."); + return false; // Terminate the method if a downgrade is detected + } + } + } + if (buildUpdate(updateAction, targetDir, yes, console, () -> console.confirmUpdates())) { console.println(""); console.buildUpdatesComplete(); @@ -444,17 +457,17 @@ private FeaturePackLocation getFpl(InstallationProfile knownFeaturePack, String public UpdateCommand(CliConsole console, ActionFactory actionFactory) { super(console, actionFactory, CliConstants.Commands.UPDATE, List.of( - new UpdateCommand.PrepareCommand(console, actionFactory), - new UpdateCommand.ApplyCommand(console, actionFactory), - new UpdateCommand.PerformCommand(console, actionFactory), - new UpdateCommand.ListCommand(console, actionFactory), + new PrepareCommand(console, actionFactory), + new ApplyCommand(console, actionFactory), + new PerformCommand(console, actionFactory), + new ListCommand(console, actionFactory), new SubscribeCommand(console, actionFactory)) ); + } private static boolean buildUpdate(UpdateAction updateAction, Path updateDirectory, boolean yes, CliConsole console, Supplier confirmation) throws OperationException, ProvisioningException { final UpdateSet updateSet = updateAction.findUpdates(); - console.updatesFound(updateSet.getArtifactUpdates()); if (updateSet.isEmpty()) { return false; @@ -493,4 +506,37 @@ public static Path detectProsperoInstallationPath() throws ArgumentParsingExcept return Paths.get(modulePath).toAbsolutePath().getParent(); } + + public static boolean isManifestDowngraded(List mavenManifests, List manifestUpdates ) { + + for (ManifestVersionRecord.MavenManifest installedManifest : mavenManifests) { + Artifact updateArtifact = null; + + // Find the corresponding update artifact for the installedManifest + for (Artifact manifestUpdate : manifestUpdates) { + if (manifestUpdate.getGroupId().equals(installedManifest.getGroupId()) && + manifestUpdate.getArtifactId().equals(installedManifest.getArtifactId())) { + updateArtifact = manifestUpdate; + break; + } + } + + if (updateArtifact != null) { + // Compare versions + String installedVersion = installedManifest.getVersion(); + String availableVersion = updateArtifact.getVersion(); + if (VersionMatcher.COMPARATOR.compare(installedVersion, availableVersion) < 0) { + log.debugf("Upgrade available for %s:%s: %s -> %s", + installedManifest.getGroupId(), installedManifest.getArtifactId(), installedVersion, availableVersion); + return true; + } else if (VersionMatcher.COMPARATOR.compare(installedVersion, availableVersion) > 0) { + log.debugf("Downgrade detected for " + installedManifest.getArtifactId() + ": " + installedVersion + " -> " + availableVersion); + return false; + } else { + System.out.println(installedManifest.getArtifactId() + " is up to date."); + } + } + } + return true; + } } diff --git a/prospero-cli/src/test/java/org/wildfly/prospero/cli/commands/UpdateCommandTest.java b/prospero-cli/src/test/java/org/wildfly/prospero/cli/commands/UpdateCommandTest.java index 855a40f5..5f6433df 100644 --- a/prospero-cli/src/test/java/org/wildfly/prospero/cli/commands/UpdateCommandTest.java +++ b/prospero-cli/src/test/java/org/wildfly/prospero/cli/commands/UpdateCommandTest.java @@ -40,6 +40,7 @@ import org.wildfly.prospero.actions.UpdateAction; import org.wildfly.prospero.api.ArtifactChange; import org.wildfly.prospero.api.FileConflict; +import org.wildfly.prospero.api.InstallationMetadata; import org.wildfly.prospero.api.MavenOptions; import org.wildfly.prospero.cli.ActionFactory; import org.wildfly.prospero.cli.CliMessages; @@ -98,6 +99,7 @@ public void setUp() throws Exception { MetadataTestUtils.createInstallationMetadata(installationDir); MetadataTestUtils.createGalleonProvisionedState(installationDir, A_PROSPERO_FP); + when(updateAction.getInstallationMetadata()).thenReturn(InstallationMetadata.loadInstallation(installationDir)); } @After diff --git a/prospero-common/src/main/java/org/wildfly/prospero/actions/UpdateAction.java b/prospero-common/src/main/java/org/wildfly/prospero/actions/UpdateAction.java index 7b1e5c4c..f2a2a695 100644 --- a/prospero-common/src/main/java/org/wildfly/prospero/actions/UpdateAction.java +++ b/prospero-common/src/main/java/org/wildfly/prospero/actions/UpdateAction.java @@ -22,9 +22,13 @@ import java.nio.file.Path; import java.util.Collections; import java.util.List; +import java.util.stream.Collectors; import org.apache.commons.io.FileUtils; +import org.eclipse.aether.artifact.Artifact; +import org.eclipse.aether.artifact.DefaultArtifact; import org.jboss.galleon.util.PathsUtils; +import org.wildfly.channel.ChannelSession; import org.wildfly.channel.Channel; import org.wildfly.channel.Repository; import org.wildfly.prospero.ProsperoLogger; @@ -171,4 +175,18 @@ private ProsperoConfig addTemporaryRepositories(List repositories) { return new ProsperoConfig(channels, prosperoConfig.getMavenOptions()); } + + public List findCurrentChannelSessionManifests() throws ProvisioningException, OperationException { + try (GalleonEnvironment galleonEnv = getGalleonEnv(installDir); + ChannelSession channelSession = galleonEnv.getChannelSession()) { + + return channelSession.getRuntimeChannels().stream() + .map(runtimeChannel -> runtimeChannel.getChannelDefinition().getManifestCoordinate()) + .map(coordinate -> new DefaultArtifact(coordinate.getGroupId(), coordinate.getArtifactId(), coordinate.getExtension(), coordinate.getVersion())) + .collect(Collectors.toList()); + } + } + public InstallationMetadata getInstallationMetadata() { + return metadata; + } }