Skip to content

Commit

Permalink
Merge pull request #482 from spyrkob/JBEAP-25910
Browse files Browse the repository at this point in the history
[JBEAP-25910] Check that folder is empty before creating candidate through the API.
  • Loading branch information
spyrkob authored Oct 18, 2023
2 parents 45531f2 + 325f8f9 commit efe70c7
Show file tree
Hide file tree
Showing 8 changed files with 158 additions and 12 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@
import java.util.Optional;

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;

Expand Down Expand Up @@ -356,6 +357,42 @@ public void displayChanges() throws Exception {
assertEquals("Not all expected changes were listed", 0, expected.size());
}

@Test
public void candidateFolderHasToBeEmpty() throws Exception {
channelsFile = MetadataTestUtils.prepareChannel(CHANNEL_BASE_CORE_19);
final Path modulesPaths = outputPath.resolve(Paths.get("modules", "system", "layers", "base"));
final Path wildflyCliModulePath = modulesPaths.resolve(Paths.get("org", "jboss", "as", "cli", "main"));
final Path candidate = temp.newFolder().toPath();

final ProvisioningDefinition provisioningDefinition = defaultWfCoreDefinition()
.setChannelCoordinates(channelsFile.toString())
.build();
installation.provision(provisioningDefinition.toProvisioningConfig(),
provisioningDefinition.resolveChannels(CHANNELS_RESOLVER_FACTORY));

MetadataTestUtils.prepareChannel(outputPath.resolve(MetadataTestUtils.INSTALLER_CHANNELS_FILE_PATH), CHANNEL_COMPONENT_UPDATES, CHANNEL_BASE_CORE_19);
updateAction().performUpdate();
Optional<Artifact> wildflyCliArtifact = readArtifactFromManifest("org.wildfly.core", "wildfly-cli");
assertEquals(UPGRADE_VERSION, wildflyCliArtifact.get().getVersion());
assertTrue("Updated jar should be present in module", wildflyCliModulePath.resolve(UPGRADE_JAR).toFile().exists());

Optional<ManifestVersionRecord> manifestVersionRecord = ManifestVersionRecord.read(
outputPath.resolve(ProsperoMetadataUtils.METADATA_DIR).resolve(ProsperoMetadataUtils.CURRENT_VERSION_FILE));
assertTrue("Manifest version record should be present", manifestVersionRecord.isPresent());
assertEquals("Manifest version record should contain base and update channels",
2, manifestVersionRecord.get().getUrlManifests().size());

final InstallationHistoryAction historyAction = new InstallationHistoryAction(outputPath, new AcceptingConsole());
final List<SavedState> revisions = historyAction.getRevisions();

Files.writeString(candidate.resolve("dirty.txt"), "foobar");

final SavedState savedState = revisions.get(1);
assertThatThrownBy(() -> historyAction.prepareRevert(savedState, mavenOptions, Collections.emptyList(), candidate))
.isInstanceOf(IllegalArgumentException.class)
.message().contains("Can't install into a non empty directory");
}

private UpdateAction updateAction() throws ProvisioningException, OperationException {
return new UpdateAction(outputPath, mavenOptions, new AcceptingConsole(), Collections.emptyList());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@
import java.util.stream.Collectors;

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.wildfly.prospero.updates.MarkerFile.UPDATE_MARKER_FILE;
Expand Down Expand Up @@ -208,6 +209,40 @@ public void updateRequiresOnlyChangedArtifacts() throws Exception {
assertEquals(UPGRADE_VERSION, wildflyCliArtifact.get().getVersion());
}

@Test
public void candidateFolderHasToBeEmpty() throws Exception {
// deploy manifest file
File manifestFile = new File(MetadataTestUtils.class.getClassLoader().getResource(CHANNEL_BASE_CORE_19).toURI());
deployManifestFile(mockRepo.toURI().toURL(), manifestFile, "1.0.0");

// provision using manifest gav
final ProvisioningDefinition provisioningDefinition = defaultWfCoreDefinition()
.setChannelCoordinates(buildConfigWithMockRepo().toPath().toString())
.setOverrideRepositories(Collections.emptyList()) // reset overrides from defaultWfCoreDefinition()
.build();
installation.provision(provisioningDefinition.toProvisioningConfig(),
provisioningDefinition.resolveChannels(CHANNELS_RESOLVER_FACTORY));

// update manifest file
final URL tempRepo = mockTemporaryRepo(true);
final File updatedChannel = upgradeTestArtifactIn(manifestFile);
deployManifestFile(tempRepo, updatedChannel, "1.0.1");

// offline MSM will disable http(s) repositories and local maven cache
final MavenOptions offlineOptions = MavenOptions.OFFLINE_NO_CACHE;

// update installation
final Path candidateFolder = temp.newFolder("candidate").toPath();
Files.writeString(candidateFolder.resolve("dirty.txt"), "foobar");

assertThatThrownBy(
() -> new UpdateAction(outputPath, offlineOptions, new AcceptingConsole(),
List.of(new Repository("temp", tempRepo.toExternalForm())))
.buildUpdate(candidateFolder))
.isInstanceOf(IllegalArgumentException.class)
.message().contains("Can't install into a non empty directory");
}

private File upgradeTestArtifactIn(File manifestFile) throws IOException, MetadataException {
final ChannelManifest manifest = ManifestYamlSupport.parse(manifestFile);
final List<Stream> streams = manifest.getStreams().stream().map(s -> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,11 @@ private static boolean isWritable(final Path path) {
if (Files.exists(absPath)) {
return Files.isWritable(absPath);
} else {
return isWritable(absPath.getParent());
if (absPath.getParent() == null) {
return false;
} else {
return isWritable(absPath.getParent());
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -347,4 +347,7 @@ public interface ProsperoLogger extends BasicLogger {

@Message(id = 259, value = "Requested configuration %s/%s is not available in the feature packs.")
String galleonConfigNotFound(String model, String name);

@Message(id = 260, value = "The selected folder %s cannot be created.")
IllegalArgumentException dirMustBeWritable(Path directory);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/*
* Copyright 2023 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.wildfly.prospero.actions;

import org.wildfly.prospero.ProsperoLogger;

import java.nio.file.Files;
import java.nio.file.Path;

class InstallFolderUtils {

static void verifyIsWritable(Path directory) {
if (!isWritable(directory)) {
throw ProsperoLogger.ROOT_LOGGER.dirMustBeWritable(directory);
}
}

static void verifyIsEmptyDir(Path directory) {
if (directory.toFile().isFile()) {
// file exists and is a regular file
throw ProsperoLogger.ROOT_LOGGER.dirMustBeDirectory(directory);
}
if (!isEmptyDirectory(directory)) {
throw ProsperoLogger.ROOT_LOGGER.cannotInstallIntoNonEmptyDirectory(directory);
}
}

private static boolean isWritable(final Path path) {
Path absPath = path.toAbsolutePath();
if (Files.exists(absPath)) {
return Files.isWritable(absPath);
} else {
if (absPath.getParent() == null) {
return false;
} else {
return isWritable(absPath.getParent());
}
}
}

private static boolean isEmptyDirectory(Path directory) {
String[] list = directory.toFile().list();
return list == null || list.length == 0;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,12 @@ public void rollback(SavedState savedState, MavenOptions mavenOptions, List<Repo

public void prepareRevert(SavedState savedState, MavenOptions mavenOptions, List<Repository> overrideRepositories, Path targetDir)
throws OperationException, ProvisioningException {
if (Files.exists(targetDir)) {
InstallFolderUtils.verifyIsEmptyDir(targetDir);
} else {
InstallFolderUtils.verifyIsWritable(targetDir);
}

try (InstallationMetadata metadata = InstallationMetadata.loadInstallation(installation)) {
ProsperoLogger.ROOT_LOGGER.revertCandidateStarted(installation);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@

import java.io.IOException;
import java.net.MalformedURLException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Collections;
Expand Down Expand Up @@ -243,18 +244,11 @@ private List<Channel> enforceChannelNames(List<Channel> newChannels) {
}

private static void verifyInstallDir(Path directory) {
if (directory.toFile().isFile()) {
// file exists and is a regular file
throw ProsperoLogger.ROOT_LOGGER.dirMustBeDirectory(directory);
if (Files.exists(directory)) {
InstallFolderUtils.verifyIsEmptyDir(directory);
} else {
InstallFolderUtils.verifyIsWritable(directory);
}
if (!isEmptyDirectory(directory)) {
throw ProsperoLogger.ROOT_LOGGER.cannotInstallIntoNonEmptyDirectory(directory);
}
}

private static boolean isEmptyDirectory(Path directory) {
String[] list = directory.toFile().list();
return list == null || list.length == 0;
}

private ArtifactResolutionException wrapAetherException(org.eclipse.aether.resolution.ArtifactResolutionException e) throws ArtifactResolutionException {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,10 +104,17 @@ public List<FileConflict> performUpdate() throws OperationException, Provisionin
* @throws OperationException
*/
public boolean buildUpdate(Path targetDir) throws ProvisioningException, OperationException {
if (Files.exists(targetDir)) {
InstallFolderUtils.verifyIsEmptyDir(targetDir);
} else {
InstallFolderUtils.verifyIsWritable(targetDir);
}

if (findUpdates().isEmpty()) {
ProsperoLogger.ROOT_LOGGER.noUpdatesFound(installDir);
return false;
}

ProsperoLogger.ROOT_LOGGER.updateCandidateStarted(installDir);
try (PrepareCandidateAction prepareCandidateAction = new PrepareCandidateAction(installDir, mavenSessionManager, prosperoConfig);
GalleonEnvironment galleonEnv = getGalleonEnv(targetDir)) {
Expand Down

0 comments on commit efe70c7

Please sign in to comment.