Skip to content

Commit

Permalink
Merge pull request #739 from spyrkob/JBEAP-27267
Browse files Browse the repository at this point in the history
Record licenses accepted when adding a feature pack
  • Loading branch information
spyrkob authored Jul 26, 2024
2 parents 483e29d + 9fe3d90 commit db28ae1
Show file tree
Hide file tree
Showing 5 changed files with 182 additions and 19 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@

package org.wildfly.prospero.actions;

import static org.wildfly.prospero.licenses.LicenseManager.LICENSES_FOLDER;

import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import org.jboss.galleon.ProvisioningDescriptionException;
Expand All @@ -43,6 +45,7 @@
import org.wildfly.prospero.galleon.GalleonEnvironment;
import org.wildfly.prospero.licenses.License;
import org.wildfly.prospero.licenses.LicenseManager;
import org.wildfly.prospero.metadata.ProsperoMetadataUtils;
import org.wildfly.prospero.model.FeaturePackTemplateManager;
import org.wildfly.prospero.model.FeaturePackTemplate;
import org.wildfly.prospero.model.ProsperoConfig;
Expand Down Expand Up @@ -89,13 +92,13 @@ public class FeaturesAddAction {
public FeaturesAddAction(MavenOptions mavenOptions, Path installDir, List<Repository> repositories, Console console) throws MetadataException, ProvisioningException {
this(mavenOptions, installDir, repositories, console,
new DefaultCandidateActionsFactory(installDir),
new FeaturePackTemplateManager());
new FeaturePackTemplateManager(), new LicenseManager());
}

// used for testing
FeaturesAddAction(MavenOptions mavenOptions, Path installDir,
List<Repository> repositories, Console console, CandidateActionsFactory candidateActionsFactory,
FeaturePackTemplateManager featurePackTemplateManager)
FeaturePackTemplateManager featurePackTemplateManager, LicenseManager licenseManager)
throws MetadataException, ProvisioningException {
this.installDir = InstallFolderUtils.toRealPath(installDir);

Expand All @@ -110,7 +113,7 @@ public FeaturesAddAction(MavenOptions mavenOptions, Path installDir, List<Reposi

this.featurePackTemplateManager = featurePackTemplateManager;

this.licenseManager = new LicenseManager();
this.licenseManager = licenseManager;
}

/**
Expand Down Expand Up @@ -346,12 +349,18 @@ private void install(String featurePackCoord, GalleonProvisioningConfig newConfi
ProsperoLogger.ROOT_LOGGER.updateCandidateCompleted(installDir);
}

if (!pendingLicenses.isEmpty()) {
try {
try {
// copy licenses from the original server to the candidate to preserve accepted licenses record
final Path existingLicenses = installDir.resolve(ProsperoMetadataUtils.METADATA_DIR).resolve(LICENSES_FOLDER);
if (Files.exists(existingLicenses)) {
FileUtils.copyDirectory(existingLicenses.toFile(), candidate.resolve(ProsperoMetadataUtils.METADATA_DIR).resolve(LICENSES_FOLDER).toFile());
}
if (!pendingLicenses.isEmpty()) {
// accept additional licenses appending to the record
licenseManager.recordAgreements(pendingLicenses, candidate);
} catch (IOException e) {
throw ProsperoLogger.ROOT_LOGGER.unableToWriteFile(candidate.resolve(LicenseManager.LICENSES_FOLDER), e);
}
} catch (IOException e) {
throw ProsperoLogger.ROOT_LOGGER.unableToWriteFile(candidate.resolve(LICENSES_FOLDER), e);
}
}

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

package org.wildfly.prospero.licenses;

import org.apache.commons.io.FileUtils;
import org.jboss.logging.Logger;
import org.wildfly.prospero.metadata.ProsperoMetadataUtils;

Expand All @@ -26,7 +27,6 @@
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
import java.nio.file.StandardOpenOption;
import java.time.LocalDateTime;
import java.util.ArrayList;
Expand All @@ -35,7 +35,6 @@
import java.util.Locale;
import java.util.Objects;
import java.util.Optional;
import java.util.Properties;
import java.util.Set;
import java.util.stream.Collectors;

Expand Down Expand Up @@ -128,7 +127,7 @@ public void recordAgreements(List<License> licenses, Path targetServer) throws I
Files.createDirectory(licenseFolder);
}
final Path licenseAcceptFile = licenseFolder.resolve(LICENSE_AGREEMENT_FILENAME);
final Properties licenseApproveProperties = new Properties();
final SortedProperties licenseApproveProperties = new SortedProperties();
if (Files.exists(licenseAcceptFile)) {
try (FileInputStream inStream = new FileInputStream(licenseAcceptFile.toFile())) {
licenseApproveProperties.load(inStream);
Expand Down Expand Up @@ -163,17 +162,14 @@ public void recordAgreements(List<License> licenses, Path targetServer) throws I
}

public void copyIfExists(Path sourceServer, Path targetServer) throws IOException {
final Path sourceLicenses = sourceServer.resolve(ProsperoMetadataUtils.METADATA_DIR).resolve(LICENSES_FOLDER).resolve(LICENSE_AGREEMENT_FILENAME);
final Path targetLicenses = targetServer.resolve(ProsperoMetadataUtils.METADATA_DIR).resolve(LICENSES_FOLDER).resolve(LICENSE_AGREEMENT_FILENAME);
if (!Files.exists(sourceLicenses)) {
return;
}

if (!Files.exists(targetLicenses.getParent())) {
Files.createDirectory(targetLicenses.getParent());
final Path licencesDir = Path.of(ProsperoMetadataUtils.METADATA_DIR, LICENSES_FOLDER);
if (!Files.exists(sourceServer.resolve(licencesDir))) {
return;
}

Files.copy(sourceLicenses, targetLicenses, StandardCopyOption.REPLACE_EXISTING);
// copy all licenses files
FileUtils.copyDirectory(sourceServer.resolve(licencesDir).toFile(), targetServer.resolve(licencesDir).toFile());
}

private static URL getLicensesFile() {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/*
* Copyright 2024 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.licenses;

import java.util.Collections;
import java.util.Comparator;
import java.util.Enumeration;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.TreeSet;

class SortedProperties extends Properties {
@Override
public Enumeration<Object> keys() {
return Collections.enumeration(keySet());
}

@Override
public Set<Object> keySet() {
final Set<Object> keyList = new TreeSet<>(Comparator.comparing(Object::toString));
keyList.addAll(super.keySet());
return keyList;
}

@Override
public Set<Map.Entry<Object, Object>> entrySet() {
final TreeSet<Map.Entry<Object, Object>> treeSet = new TreeSet<>((o1, o2) -> o1.getKey().toString().compareTo(o2.toString()));
treeSet.addAll(super.entrySet());
return treeSet;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.junit.MockitoJUnitRunner;
import org.wildfly.channel.Channel;
import org.wildfly.channel.ChannelManifest;
Expand All @@ -46,20 +47,24 @@
import org.wildfly.prospero.api.exceptions.MetadataException;
import org.wildfly.prospero.api.exceptions.OperationException;
import org.wildfly.prospero.galleon.FeaturePackLocationParser;
import org.wildfly.prospero.licenses.License;
import org.wildfly.prospero.licenses.LicenseManager;
import org.wildfly.prospero.model.FeaturePackTemplateManager;
import org.wildfly.prospero.model.FeaturePackTemplate;
import org.wildfly.prospero.model.ProsperoConfig;
import org.wildfly.prospero.test.MetadataTestUtils;
import org.wildfly.prospero.utils.MavenUtils;
import org.wildfly.prospero.wfchannel.MavenSessionManager;

import java.io.FileInputStream;
import java.io.IOException;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Collections;
import java.util.List;
import java.util.Properties;
import java.util.Set;
import java.util.stream.Collectors;

Expand Down Expand Up @@ -101,6 +106,8 @@ public class FeaturesAddActionTest {
private FeaturesAddAction.CandidateActionsFactory candidateActionsFactory;
@Mock
private FeaturePackTemplateManager featurePackTemplateManager;
@Mock
private LicenseManager licenseManager;

@Before
public void setUp() throws Exception {
Expand Down Expand Up @@ -984,6 +991,53 @@ public void findAndApplyTemplateWithAdditionalPackages() throws Exception {
.contains("additional.package");
}

@Test
public void testAddLicenses() throws Exception {
// install base feature pack
final FeaturePackCreator creator = FeaturePackCreator.getInstance().addArtifactResolver(repo);
creator.newFeaturePack(FeaturePackLocation.fromString("org.test:base-pack:1.0.0:zip").getFPID())
.getCreator()
.newFeaturePack(FeaturePackLocation.fromString("org.test:added-pack:1.0.0:zip").getFPID())
.addDependency(FeaturePackLocation.fromString("org.test:base-pack:1.0.0"))
;
deployFeaturePacks(creator);
// install
installFeaturePack(installDir, "org.test:base-pack:1.0.0:zip");

final Path licenses = installDir.resolve(METADATA_DIR).resolve(LicenseManager.LICENSES_FOLDER);
Files.createDirectories(licenses);

// create licenses - base-license is accepted in the original server and added-license is accepted during
// addition of a feature pack
final License addedLicense = new License("added-license", "org.test:added-pack", "Added License", "Added license text");
final License baseLicense = new License("base-license", "org.test:base-pack", "Base license", "Base license text");
when(licenseManager.getLicenses(any())).thenReturn(List.of(addedLicense));
// use real method to actually write out the content of licenses - this way we can check that both old and new licenses are saved
Mockito.doCallRealMethod().when(licenseManager).recordAgreements(any(), any());
licenseManager.recordAgreements(List.of(baseLicense), installDir);

getFeaturesAddAction().addFeaturePack("org.test:added-pack", NO_DEFAULT_CONFIGS, candidatePath);

verify(prepareCandidateAction).buildCandidate(any(), any(), eq(ApplyCandidateAction.Type.FEATURE_ADD),
any());


// verify candidate has licenses from both base server and newly added ones
final Properties properties = new Properties();
final Path licensesDir = candidatePath.resolve(METADATA_DIR).resolve(LicenseManager.LICENSES_FOLDER);
properties.load(new FileInputStream(licensesDir.resolve("license_accepted.properties").toFile()));
assertThat(properties.stringPropertyNames())
.contains("license.0.name", "license.1.name");
assertThat(properties.getProperty("license.0.name"))
.isEqualTo("base-license");
assertThat(properties.getProperty("license.1.name"))
.isEqualTo("added-license");
assertThat(licensesDir.resolve("base-license.txt"))
.hasContent("Base license text");
assertThat(licensesDir.resolve("added-license.txt"))
.hasContent("Added license text");
}

private static GalleonFeaturePackConfig getFeaturePackConfig(GalleonProvisioningConfig config, String fpl) {
return config.getFeaturePackDeps().stream().filter(f -> f.getLocation().toString().equals(fpl)).findFirst().get();
}
Expand Down Expand Up @@ -1012,7 +1066,7 @@ private FeaturesAddAction getFeaturesAddAction() throws MetadataException, Provi

final FeaturesAddAction featuresAddAction = new FeaturesAddAction(MavenOptions.OFFLINE_NO_CACHE, installDir,
List.of(new Repository("test", repositoryUrl.toExternalForm())), null,
candidateActionsFactory, featurePackTemplateManager);
candidateActionsFactory, featurePackTemplateManager, licenseManager);
return featuresAddAction;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/*
* Copyright 2024 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.licenses;

import static org.assertj.core.api.Assertions.*;

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

import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;

public class SortedPropertiesTest {

@Rule
public TemporaryFolder temp = new TemporaryFolder();

@Test
public void writeSortedProperties() throws Exception {
final SortedProperties properties = new SortedProperties();

properties.setProperty("bbb", "bar");
properties.setProperty("aaa", "foo");
properties.setProperty("ddd", "212");
properties.setProperty("ccc", "123");

final Path propertiesFile = temp.newFile().toPath();
try (FileOutputStream fos = new FileOutputStream(propertiesFile.toFile())) {
properties.store(fos, null);
}

// first line is going to be a comment with timestamp, need to add it to the check
final String firstLine = Files.readAllLines(propertiesFile).get(0);
assertThat(firstLine)
.startsWith("#");
assertThat(propertiesFile)
.hasContent(firstLine + "\naaa=foo\nbbb=bar\nccc=123\nddd=212");

}
}

0 comments on commit db28ae1

Please sign in to comment.