Skip to content

Commit

Permalink
Display and accept licenses related to added feature pack
Browse files Browse the repository at this point in the history
  • Loading branch information
spyrkob committed Apr 11, 2024
1 parent e7c5df5 commit 6273375
Show file tree
Hide file tree
Showing 8 changed files with 127 additions and 14 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -608,5 +608,7 @@ default String featurePackDoesNotSupportCustomization(String featurePackName) {
return format(bundle.getString("prospero.features.add.validation.customization_not_supported"), featurePackName,
String.join(",", List.of(CliConstants.LAYERS, CliConstants.TARGET_CONFIG)));
}

default String featurePackRequiresLicense(String featurePackName) {
return format(bundle.getString("prospero.features.add.required_licences"), featurePackName);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,11 @@
import org.wildfly.prospero.cli.CliConsole;
import org.wildfly.prospero.cli.CliMessages;
import org.wildfly.prospero.cli.FileConflictPrinter;
import org.wildfly.prospero.cli.LicensePrinter;
import org.wildfly.prospero.cli.RepositoryDefinition;
import org.wildfly.prospero.cli.ReturnCodes;
import org.wildfly.prospero.api.TemporaryFilesManager;
import org.wildfly.prospero.licenses.License;
import org.wildfly.prospero.model.FeaturePackTemplate;
import picocli.CommandLine;

Expand Down Expand Up @@ -66,6 +68,9 @@ public static class AddCommand extends AbstractMavenCommand {
@CommandLine.Option(names = {CliConstants.Y, CliConstants.YES})
boolean skipConfirmation;

@CommandLine.Option(names = CliConstants.ACCEPT_AGREEMENTS)
boolean acceptAgreements;

public AddCommand(CliConsole console, ActionFactory actionFactory) {
super(console, actionFactory);
}
Expand All @@ -90,6 +95,21 @@ public Integer call() throws Exception {

final FeaturesAddAction featuresAddAction = actionFactory.featuresAddAction(installationDir, mavenOptions, repositories, console);

final List<License> pendingLicenses = featuresAddAction.getRequiredLicenses(fpl);

if (!pendingLicenses.isEmpty()) {
console.println(System.lineSeparator() + CliMessages.MESSAGES.featurePackRequiresLicense(fpl) + System.lineSeparator());
new LicensePrinter().print(pendingLicenses);

if (acceptAgreements) {
console.println(CliMessages.MESSAGES.agreementSkipped(CliConstants.ACCEPT_AGREEMENTS) + System.lineSeparator());
} else {
if (!console.confirm(CliMessages.MESSAGES.acceptAgreements() + " ", "", CliMessages.MESSAGES.installationCancelled())) {
return ReturnCodes.PROCESSING_ERROR;
}
}
}

final FeaturePackTemplate featurePackRecipe = featuresAddAction.getFeaturePackRecipe(fpl);

if (featurePackRecipe != null) {
Expand Down
2 changes: 2 additions & 0 deletions prospero-cli/src/main/resources/UsageMessages.properties
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ ${prospero.dist.name}.feature-pack.add.layers = Feature Pack layers selected for
${prospero.dist.name}.feature-pack.add.target-config = Server configuration file that the Feature Pack changes will be applied to. \
If not specified, defaults to the @|bold standalone.xml|@.


#
# Parameter Groups Headings
#
Expand Down Expand Up @@ -348,6 +349,7 @@ prospero.features.add.validation.model.not_supported=The feature pack `%s` does
prospero.features.add.validation.configuration.not_supported=The feature pack `%s` does not provide requested configuration `%s/%s`.
prospero.features.add.validation.layers_required=The feature pack `%s` requires at least one installation layer to be selected (%s).
prospero.features.add.validation.customization_not_supported=The feature pack `%s` does not support customization. Please try again without [%s] arguments.
prospero.features.add.required_licences=Installing feature pack %s requires accepting following license changes:%n

prospero.changes.diff.manifest=manifest
prospero.changes.diff.repositories=repositories
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@
import org.wildfly.prospero.galleon.ArtifactCache;
import org.wildfly.prospero.galleon.GalleonEnvironment;
import org.wildfly.prospero.installation.git.GitStorage;
import org.wildfly.prospero.licenses.LicenseManager;
import org.wildfly.prospero.metadata.ProsperoMetadataUtils;
import org.wildfly.prospero.updates.MarkerFile;
import org.wildfly.prospero.updates.UpdateSet;
Expand Down Expand Up @@ -346,11 +347,20 @@ private void updateMetadata(Type operation) throws ProvisioningException, Metada
ProsperoMetadataUtils.recordProvisioningDefinition(installationDir);
writeProsperoMetadata(operation);
updateInstallationCache();
updateAcceptedLicences();
} catch (IOException ex) {
throw new ProvisioningException(ex);
}
}

private void updateAcceptedLicences() throws MetadataException {
try {
new LicenseManager().copyIfExists(updateDir, installationDir);
} catch (IOException e) {
throw ProsperoLogger.ROOT_LOGGER.unableToWriteFile(installationDir.resolve(LicenseManager.LICENSES_FOLDER), e);
}
}

private void copyCurrentVersions() throws IOException {
Path sourceVersions = updateDir.resolve(ProsperoMetadataUtils.METADATA_DIR).resolve(CURRENT_VERSION_FILE);
if (Files.exists(sourceVersions)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@
import org.wildfly.prospero.galleon.FeaturePackLocationParser;
import org.wildfly.prospero.galleon.GalleonEnvironment;
import org.wildfly.prospero.galleon.GalleonUtils;
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;
Expand Down Expand Up @@ -84,6 +86,7 @@ public class FeaturesAddAction {
private final Console console;
private final CandidateActionsFactory candidateActionsFactory;
private final FeaturePackTemplateManager featurePackTemplateManager;
private LicenseManager licenseManager;

public FeaturesAddAction(MavenOptions mavenOptions, Path installDir, List<Repository> repositories, Console console) throws MetadataException, ProvisioningException {
this(mavenOptions, installDir, repositories, console,
Expand All @@ -107,6 +110,8 @@ public FeaturesAddAction(MavenOptions mavenOptions, Path installDir, List<Reposi
this.candidateActionsFactory = candidateActionsFactory;

this.featurePackTemplateManager = featurePackTemplateManager;

this.licenseManager = new LicenseManager();
}

@Deprecated
Expand Down Expand Up @@ -172,7 +177,7 @@ public void addFeaturePack(String featurePackCoord, Set<ConfigId> defaultConfigN

final ProvisioningConfig newConfig = buildProvisioningConfig(Collections.emptySet(), fpl, selectedConfigs);

install(newConfig, candidatePath);
install(featurePackCoord, newConfig, candidatePath);
}

@Deprecated
Expand Down Expand Up @@ -239,7 +244,7 @@ public void addFeaturePackWithLayers(String featurePackCoord, Set<String> layers

final ProvisioningConfig newConfig = buildProvisioningConfig(layers, fpl, selectedConfig==null?Collections.emptySet():Set.of(new ConfigId(selectedModel, selectedConfig)));

install(newConfig, candidateFolder);
install(featurePackCoord, newConfig, candidateFolder);
}

/**
Expand Down Expand Up @@ -321,6 +326,10 @@ public boolean isFeaturePackAvailable(String featurePackCoord) throws OperationE
return true;
}

public List<License> getRequiredLicenses(String featurePackCoord) {
return licenseManager.getLicenses(Set.of(featurePackCoord));
}

private static Path createTemporaryFolder() throws ProvisioningException {
final Path candidate;
try {
Expand Down Expand Up @@ -356,7 +365,8 @@ private static void verifyFeaturePackCoord(String featurePackCoord) {
}
}

private void install(ProvisioningConfig newConfig, Path candidate) throws ProvisioningException, OperationException {
private void install(String featurePackCoord, ProvisioningConfig newConfig, Path candidate) throws ProvisioningException, OperationException {
final List<License> pendingLicenses = getRequiredLicenses(featurePackCoord);

verifyConfigurationsAvailable(newConfig);

Expand All @@ -372,6 +382,14 @@ private void install(ProvisioningConfig newConfig, Path candidate) throws Provis
prepareCandidateAction.buildCandidate(candidate, galleonEnv, ApplyCandidateAction.Type.FEATURE_ADD, newConfig);
ProsperoLogger.ROOT_LOGGER.updateCandidateCompleted(installDir);
}

if (!pendingLicenses.isEmpty()) {
try {
licenseManager.recordAgreements(pendingLicenses, candidate);
} catch (IOException e) {
throw ProsperoLogger.ROOT_LOGGER.unableToWriteFile(candidate.resolve(LicenseManager.LICENSES_FOLDER), e);
}
}
}

private static ArtifactCoordinate toMavenCoordinates(String featurePackCoord) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
import org.wildfly.prospero.galleon.GalleonEnvironment;
import org.wildfly.prospero.galleon.GalleonFeaturePackAnalyzer;
import org.wildfly.prospero.galleon.GalleonUtils;
import org.wildfly.prospero.licenses.LicenseManager;
import org.wildfly.prospero.metadata.ManifestVersionRecord;
import org.wildfly.prospero.model.ProsperoConfig;
import org.wildfly.prospero.updates.MarkerFile;
Expand All @@ -55,10 +56,12 @@ class PrepareCandidateAction implements AutoCloseable {
private final InstallationMetadata metadata;
private final ProsperoConfig prosperoConfig;
private final MavenSessionManager mavenSessionManager;
private final Path installDir;

PrepareCandidateAction(Path installDir, MavenSessionManager mavenSessionManager, ProsperoConfig prosperoConfig)
throws OperationException {
this.metadata = InstallationMetadata.loadInstallation(installDir);
this.installDir = installDir;
this.prosperoConfig = prosperoConfig;
this.mavenSessionManager = mavenSessionManager;
}
Expand Down Expand Up @@ -147,6 +150,12 @@ private void doBuildUpdate(Path targetDir, GalleonEnvironment galleonEnv, Provis
} catch (Exception e) {
throw new RuntimeException(e);
}

try {
new LicenseManager().copyIfExists(installDir, targetDir);
} catch (IOException e) {
throw ProsperoLogger.ROOT_LOGGER.unableToWriteFile(installDir.resolve(LicenseManager.LICENSES_FOLDER), e);
}
}

private Optional<ManifestVersionRecord> getManifestVersionRecord(List<Channel> channels) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,18 +20,21 @@
import org.jboss.logging.Logger;
import org.wildfly.prospero.metadata.ProsperoMetadataUtils;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
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;
import java.util.HashMap;
import java.util.List;
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 @@ -115,7 +118,6 @@ public void recordAgreements(List<License> licenses, Path targetServer) throws I
if (logger.isDebugEnabled()) {
logger.debugf("Saving %d license agreements.", licenses.size());
}
final String username = System.getProperty("user.name");
final LocalDateTime timestamp = LocalDateTime.now();

final Path licenseFolder = targetServer.resolve(ProsperoMetadataUtils.METADATA_DIR).resolve(LICENSES_FOLDER);
Expand All @@ -126,16 +128,31 @@ 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();
if (Files.exists(licenseAcceptFile)) {
try (FileInputStream inStream = new FileInputStream(licenseAcceptFile.toFile())) {
licenseApproveProperties.load(inStream);
}
}
final Optional<Integer> first = licenseApproveProperties.keySet().stream()
.map(Object::toString)
.filter(s -> s.startsWith("license.") && s.endsWith(".name"))
.map(s -> s.replace("license.", "").replace(".name", ""))
.map(Integer::parseInt)
.max(Integer::compareTo)
.map(i->i+1); // add one to get the next starting index

try (FileOutputStream fos = new FileOutputStream(licenseAcceptFile.toFile())) {
final Properties licenseApproveProperties = new Properties();
licenseApproveProperties.setProperty("username", username);
licenseApproveProperties.setProperty("timestamp", timestamp.toString());
for (int i = 0; i < licenses.size(); i++) {
final License license = licenses.get(i);

int nextLicenseIndex = first.orElse(0);
for (License license : licenses) {
saveLicenseText(license, licenseFolder);

licenseApproveProperties.setProperty("license." + i + ".name", license.getName());
licenseApproveProperties.setProperty("license." + i + ".file", toFileName(license));
licenseApproveProperties.setProperty("license." + nextLicenseIndex + ".name", license.getName());
licenseApproveProperties.setProperty("license." + nextLicenseIndex + ".file", toFileName(license));
licenseApproveProperties.setProperty("license." + nextLicenseIndex + ".timestamp", timestamp.toString());

nextLicenseIndex++;
}

if (logger.isTraceEnabled()) {
Expand All @@ -145,6 +162,20 @@ 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(LicenseManager.LICENSES_FOLDER).resolve(LicenseManager.LICENSE_AGREEMENT_FILENAME);
final Path targetLicenses = targetServer.resolve(ProsperoMetadataUtils.METADATA_DIR).resolve(LicenseManager.LICENSES_FOLDER).resolve(LicenseManager.LICENSE_AGREEMENT_FILENAME);
if (!Files.exists(sourceLicenses)) {
return;
}

if (!Files.exists(targetLicenses.getParent())) {
Files.createDirectory(targetLicenses.getParent());
}

Files.copy(sourceLicenses, targetLicenses, StandardCopyOption.REPLACE_EXISTING);
}

private static URL getLicensesFile() {
final Locale locale = Locale.getDefault();
final URL licensesUrl = LicenseManager.class.getClassLoader().getResource(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,12 +96,12 @@ public void printAcceptedLicenses() throws Exception {
.exists()
.hasContent(LICENSE_TWO.getText());
assertThat(readProperties(licensesPath.resolve(LICENSE_AGREEMENT_FILENAME)))
.containsEntry("username", System.getProperty("user.name"))
.containsEntry("license.0.name", "name")
.containsEntry("license.1.name", "name2")
.containsEntry("license.0.file", "name.txt")
.containsEntry("license.1.file", "name2.txt")
.containsKey("timestamp");
.containsKey("license.0.timestamp")
.containsKey("license.1.timestamp");
}

@Test
Expand All @@ -122,6 +122,27 @@ public void acceptedLicenseFilenameReplacesWhitespacesAndLowerCases() throws Exc
.exists();
}

@Test
public void addsAcceptedLicenses() throws Exception {
new LicenseManager().recordAgreements(List.of(LICENSE_ONE), serverPath);
new LicenseManager().recordAgreements(List.of(LICENSE_TWO), serverPath);

final Path licensesPath = licensesFolder(serverPath);
assertThat(licensesPath.resolve("name.txt"))
.exists()
.hasContent(LICENSE_ONE.getText());
assertThat(licensesPath.resolve("name2.txt"))
.exists()
.hasContent(LICENSE_TWO.getText());
assertThat(readProperties(licensesPath.resolve(LICENSE_AGREEMENT_FILENAME)))
.containsEntry("license.0.name", "name")
.containsEntry("license.1.name", "name2")
.containsEntry("license.0.file", "name.txt")
.containsEntry("license.1.file", "name2.txt")
.containsKey("license.0.timestamp")
.containsKey("license.1.timestamp");
}

private static Properties readProperties(Path resolve) throws IOException {
final Properties acceptedProperties = new Properties();
try (FileInputStream fis = new FileInputStream(resolve.toFile())) {
Expand Down

0 comments on commit 6273375

Please sign in to comment.