diff --git a/cobigen-eclipse/cobigen-eclipse-test/src/main/resources/OpenAPITest/templates/context.xml b/cobigen-eclipse/cobigen-eclipse-test/src/main/resources/OpenAPITest/templates/context.xml index bb2207f3a7..d47c2dc5ea 100644 --- a/cobigen-eclipse/cobigen-eclipse-test/src/main/resources/OpenAPITest/templates/context.xml +++ b/cobigen-eclipse/cobigen-eclipse-test/src/main/resources/OpenAPITest/templates/context.xml @@ -32,4 +32,5 @@ + diff --git a/cobigen/cobigen-core-api/src/main/java/com/devonfw/cobigen/api/constants/ConfigurationConstants.java b/cobigen/cobigen-core-api/src/main/java/com/devonfw/cobigen/api/constants/ConfigurationConstants.java index e9bd727444..e0ea2d8c6b 100644 --- a/cobigen/cobigen-core-api/src/main/java/com/devonfw/cobigen/api/constants/ConfigurationConstants.java +++ b/cobigen/cobigen-core-api/src/main/java/com/devonfw/cobigen/api/constants/ConfigurationConstants.java @@ -98,6 +98,11 @@ public class ConfigurationConstants { */ public static final String CONFIG_PROPERTY_TEMPLATE_SETS_HIDE = "template-sets.hide"; + /** + * Name of configuration key to preinstall specific template sets + */ + public static final String CONFIG_PROPERTY_TEMPLATE_SETS_INSTALLED = "template-sets.installed"; + /** * Default (public) cobigen GroupId */ diff --git a/cobigen/cobigen-core-api/src/main/java/com/devonfw/cobigen/api/constants/TemplatesJarConstants.java b/cobigen/cobigen-core-api/src/main/java/com/devonfw/cobigen/api/constants/TemplatesJarConstants.java index 4028c22da2..8fe754573f 100644 --- a/cobigen/cobigen-core-api/src/main/java/com/devonfw/cobigen/api/constants/TemplatesJarConstants.java +++ b/cobigen/cobigen-core-api/src/main/java/com/devonfw/cobigen/api/constants/TemplatesJarConstants.java @@ -9,6 +9,12 @@ public class TemplatesJarConstants { */ public static final String DOWNLOADED_JAR_FOLDER = "/.metadata/cobigen_jars"; + /** + * Regular expression to check the correct definition of maven coordinates to download a template-set with the + * configuration key template-sets.installed in the properties. + */ + public static final String MAVEN_COORDINATES_CHECK = "([a-zA-Z0-9_\\-\\.]+):([a-zA-Z0-9_-]+)(:([0-9]+(\\.[0-9]+)*(-SNAPSHOT)?|LATEST))?"; + /** * Jar regular expression name to be used in a file name filter, so that we can check whether the templates are * already downloaded. Checks "templates-anystring-anydigitbetweendots.jar" diff --git a/cobigen/cobigen-core-api/src/main/java/com/devonfw/cobigen/api/util/MavenCoordinate.java b/cobigen/cobigen-core-api/src/main/java/com/devonfw/cobigen/api/util/MavenCoordinate.java new file mode 100644 index 0000000000..96f51f2c43 --- /dev/null +++ b/cobigen/cobigen-core-api/src/main/java/com/devonfw/cobigen/api/util/MavenCoordinate.java @@ -0,0 +1,89 @@ +package com.devonfw.cobigen.api.util; + +import java.util.Objects; + +/** + * This MavenCoordinate class is just a dataholder with maven coordinates. + */ +public class MavenCoordinate { + + /** + * the groupId of the maven artifact + */ + private String groupId; + + /** + * the artifactId of the maven artifact + */ + private String artifactId; + + /** + * the version of the maven artifact + */ + private String version; + + /** + * Creates a new {@link MavenCoordinate} object with the given properties + * + * @param groupId a {@link String} with the groupId of the maven artifact + * @param artifactId {@link String} with the artifactId of the maven artifact + * @param version {@link String} with the version of the maven artifact + */ + public MavenCoordinate(String groupId, String artifactId, String version) { + + this.groupId = groupId; + this.artifactId = artifactId; + this.version = version; + } + + /** + * Returns the value of the artifactID + * + * @return {@link String} artifactID + */ + public String getArtifactId() { + + return this.artifactId; + } + + /** + * Returns the value of the groupID + * + * @return {@link String} groupID + */ + public String getGroupId() { + + return this.groupId; + } + + /** + * Returns the value of the version + * + * @return {@link String} version + */ + public String getVersion() { + + return this.version; + } + + @Override + public int hashCode() { + + return Objects.hash(this.artifactId, this.groupId, this.version); + } + + @Override + public boolean equals(Object obj) { + + if (this == obj) { + return true; + } + if (!(obj instanceof MavenCoordinate)) { + return false; + } + MavenCoordinate other = (MavenCoordinate) obj; + return Objects.equals(this.artifactId, other.artifactId) && Objects.equals(this.groupId, other.groupId) + && Objects.equals(this.version, other.version); + } + +} diff --git a/cobigen/cobigen-core-api/src/main/java/com/devonfw/cobigen/api/util/TemplatesJarUtil.java b/cobigen/cobigen-core-api/src/main/java/com/devonfw/cobigen/api/util/TemplatesJarUtil.java index 2bda97287d..5b7d7ebb9e 100644 --- a/cobigen/cobigen-core-api/src/main/java/com/devonfw/cobigen/api/util/TemplatesJarUtil.java +++ b/cobigen/cobigen-core-api/src/main/java/com/devonfw/cobigen/api/util/TemplatesJarUtil.java @@ -12,15 +12,19 @@ import java.nio.file.StandardCopyOption; import java.util.ArrayList; import java.util.Arrays; +import java.util.HashSet; import java.util.List; +import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.stream.Collectors; import java.util.stream.Stream; +import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import com.devonfw.cobigen.api.constants.ConfigurationConstants; import com.devonfw.cobigen.api.constants.TemplatesJarConstants; import com.devonfw.cobigen.api.exception.CobiGenRuntimeException; @@ -41,11 +45,12 @@ public class TemplatesJarUtil { * @param templatesDirectory directory where the templates jar are located * @return fileName Name of the file downloaded */ - private static String downloadJar(String groupId, String artifactId, String version, boolean isDownloadSource, + public static String downloadJar(String groupId, String artifactId, String version, boolean isDownloadSource, File templatesDirectory) { // By default the version should be latest - if (version.isEmpty() || version == null) { + if (StringUtils.isEmpty(version)) { + version = "LATEST"; } @@ -85,6 +90,8 @@ private static String downloadJar(String groupId, String artifactId, String vers } /** + * Downloads the latest devon4j templates + * * @param isDownloadSource true if downloading source jar file * @param templatesDirectory directory where the templates jar are located * @return fileName Name of the file downloaded @@ -95,6 +102,79 @@ public static String downloadLatestDevon4jTemplates(boolean isDownloadSource, Fi TemplatesJarConstants.DEVON4J_TEMPLATES_ARTIFACTID, "LATEST", isDownloadSource, templatesDirectory); } + /** + * Downloads multiple jar files defined by the maven coordinates. Only downloads if files are not present or adapted + * folder does not exist. + * + * @param templatesDirectory directory where the templates jar are located + * @param mavenCoordinates list with {@link MavenCoordinate} that will be loaded + */ + public static void downloadTemplatesByMavenCoordinates(Path templatesDirectory, + List mavenCoordinates) { + + if (mavenCoordinates == null || mavenCoordinates.isEmpty()) { + return; + // no templates specified + } + + Set existingTemplates = new HashSet<>(); + Path adapted = templatesDirectory.resolve(ConfigurationConstants.ADAPTED_FOLDER); + Path downloaded = templatesDirectory.resolve(ConfigurationConstants.DOWNLOADED_FOLDER); + // search for already available template-sets + if (Files.exists(adapted)) { + existingTemplates.addAll(getMatchingTemplates(mavenCoordinates, adapted)); + } + if (Files.exists(downloaded)) { + existingTemplates.addAll(getMatchingTemplates(mavenCoordinates, downloaded)); + } else { + LOG.info("downloaded folder could not be found and will be created "); + try { + Files.createDirectory(templatesDirectory.resolve(ConfigurationConstants.DOWNLOADED_FOLDER)); + } catch (IOException e) { + throw new CobiGenRuntimeException("Could not create Download Folder", e); + } + } + + if (!existingTemplates.isEmpty()) { + mavenCoordinates.removeAll(existingTemplates); + } + + for (MavenCoordinate mavenCoordinate : mavenCoordinates) { + downloadJar(mavenCoordinate.getGroupId(), mavenCoordinate.getArtifactId(), mavenCoordinate.getVersion(), false, + downloaded.toFile()); + downloadJar(mavenCoordinate.getGroupId(), mavenCoordinate.getArtifactId(), mavenCoordinate.getVersion(), true, + downloaded.toFile()); + } + + } + + /** + * Checks if the given Path contains Folders or files with a artifact name from a list of maven artifact. This + * function is used to check if templates already exists and just uses the artifactId and not the version of the + * artifacts + * + * @param mavenCoordinates a List of maven coordinates that are check for matching templates + * @param path Path to the directory that contains the Templates. + * @return Set with MavenCoordinate that are already present in the directory + */ + private static Set getMatchingTemplates(List mavenCoordinates, Path path) { + + HashSet existingTemplates = new HashSet<>(); + + for (MavenCoordinate mavenCoordinate : mavenCoordinates) { + try { + if (Files.list(path).anyMatch(f -> (f.getFileName().toString().contains(mavenCoordinate.getArtifactId())))) { + existingTemplates.add(mavenCoordinate); + } + } catch (IOException e) { + LOG.warn("Failed to get all files and directories from the folder " + path, e); + + } + } + return existingTemplates; + + } + /** * Checks whether there is a newer version of the templates on Maven * diff --git a/cobigen/cobigen-core-systemtest/src/test/java/com/devonfw/cobigen/systemtest/TemplatesInstallationTest.java b/cobigen/cobigen-core-systemtest/src/test/java/com/devonfw/cobigen/systemtest/TemplatesInstallationTest.java new file mode 100644 index 0000000000..7140e884f0 --- /dev/null +++ b/cobigen/cobigen-core-systemtest/src/test/java/com/devonfw/cobigen/systemtest/TemplatesInstallationTest.java @@ -0,0 +1,147 @@ +package com.devonfw.cobigen.systemtest; + +import static com.github.stefanbirkner.systemlambda.SystemLambda.withEnvironmentVariable; +import static org.assertj.core.api.Assertions.assertThat; + +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileWriter; +import java.nio.file.Files; + +import org.junit.Test; + +import com.devonfw.cobigen.api.CobiGen; +import com.devonfw.cobigen.api.constants.ConfigurationConstants; +import com.devonfw.cobigen.impl.CobiGenFactory; +import com.devonfw.cobigen.systemtest.common.AbstractApiTest; + +/** + * Test suite for template installation with the cobigen startup + * + */ +public class TemplatesInstallationTest extends AbstractApiTest { + + /** + * Tests if the templates specified in the .cobigen file won´t be loaded with the monolithic structure. + * + * @throws Exception test fails. + */ + @Test + public void testInstallTemplatesAtStartupMonolithicStructure() throws Exception { + + File folder = this.tmpFolder.newFolder("TemplateSetsInstalledTest"); + withEnvironmentVariable(ConfigurationConstants.CONFIG_ENV_HOME, folder.getAbsolutePath()).execute(() -> { + File templates = this.tmpFolder.newFolder("TemplateSetsInstalledTest", ConfigurationConstants.TEMPLATES_FOLDER); + File cobigenDir = templates.toPath().resolve(ConfigurationConstants.COBIGEN_TEMPLATES).toFile(); + Files.createDirectories(cobigenDir.toPath()); + File target = new File(folder, ConfigurationConstants.COBIGEN_CONFIG_FILE); + try (BufferedWriter writer = new BufferedWriter(new FileWriter(target))) { + writer.write("template-sets.installed=com.devonfw.cobigen:templates-devon4j:2021.12.006"); + } + CobiGenFactory.create(templates.toURI(), true); + assertThat(cobigenDir.listFiles()).hasSize(0); + }); + } + + /** + * Tests if the templates specified in the .cobigen file will be loaded at startup with the template-set structure and + * an existing downloaded folder. + * + * @throws Exception test fails. + */ + @Test + public void testInstallTemplatesAtStartup() throws Exception { + + File folder = this.tmpFolder.newFolder("TemplateSetsInstalledTest"); + withEnvironmentVariable(ConfigurationConstants.CONFIG_ENV_HOME, folder.getAbsolutePath()).execute(() -> { + File templateSets = this.tmpFolder.newFolder("TemplateSetsInstalledTest", + ConfigurationConstants.TEMPLATE_SETS_FOLDER); + File downloaded = this.tmpFolder.newFolder("TemplateSetsInstalledTest", + ConfigurationConstants.TEMPLATE_SETS_FOLDER, "downloaded"); + File target = new File(folder, ConfigurationConstants.COBIGEN_CONFIG_FILE); + try (BufferedWriter writer = new BufferedWriter(new FileWriter(target))) { + writer.write("template-sets.installed=com.devonfw.cobigen:templates-devon4j:2021.12.006"); + } + CobiGen cobigen = CobiGenFactory.create(templateSets.toURI()); + assertThat(downloaded.listFiles()).hasSize(2); + assertThat(downloaded.listFiles()) + .allMatch(f -> f.getName().matches("templates-devon4j-2021.12.006(-sources)?.jar")); + }); + + } + + /** + * Tests if the templates specified in the .cobigen file won´t be loaded when a adapted folder already exists. + * + * @throws Exception test fails. + */ + @Test + public void testInstallTemplatesAtStartupAdapted() throws Exception { + + File folder = this.tmpFolder.newFolder("TemplateSetsInstalledTest"); + withEnvironmentVariable(ConfigurationConstants.CONFIG_ENV_HOME, folder.getAbsolutePath()).execute(() -> { + File templateSets = this.tmpFolder.newFolder("TemplateSetsInstalledTest", + ConfigurationConstants.TEMPLATE_SETS_FOLDER); + File adapted = this.tmpFolder.newFolder("TemplateSetsInstalledTest", ConfigurationConstants.TEMPLATE_SETS_FOLDER, + ConfigurationConstants.ADAPTED_FOLDER); + File downloaded = this.tmpFolder.newFolder("TemplateSetsInstalledTest", + ConfigurationConstants.TEMPLATE_SETS_FOLDER, ConfigurationConstants.DOWNLOADED_FOLDER); + File target = new File(folder, ConfigurationConstants.COBIGEN_CONFIG_FILE); + try (BufferedWriter writer = new BufferedWriter(new FileWriter(target))) { + writer.write("template-sets.installed=com.devonfw.cobigen:templates-devon4j:2021.12.005"); + } + CobiGen cobigen = CobiGenFactory.create(templateSets.toURI()); + assertThat(downloaded.listFiles()).hasSize(2); + }); + + } + + /** + * Tests if the templates specified in the .cobigen file will be loaded at startup with the template-set structure + * without an existing downloaded folder. + * + * @throws Exception test fails. + */ + @Test + public void testInstallTemplatesAtStartupWithoutDownloaded() throws Exception { + + File folder = this.tmpFolder.newFolder("TemplateSetsInstalledTest"); + withEnvironmentVariable(ConfigurationConstants.CONFIG_ENV_HOME, folder.getAbsolutePath()).execute(() -> { + File templateSets = this.tmpFolder.newFolder("TemplateSetsInstalledTest", + ConfigurationConstants.TEMPLATE_SETS_FOLDER); + File downloaded = templateSets.toPath().resolve(ConfigurationConstants.DOWNLOADED_FOLDER).toFile(); + File target = new File(folder, ConfigurationConstants.COBIGEN_CONFIG_FILE); + try (BufferedWriter writer = new BufferedWriter(new FileWriter(target))) { + writer.write("template-sets.installed=com.devonfw.cobigen:templates-devon4j:2021.12.006"); + } + CobiGen cobigen = CobiGenFactory.create(templateSets.toURI()); + assertThat(downloaded.listFiles()).hasSize(2); + assertThat(downloaded.listFiles()) + .allMatch(f -> f.getName().matches("templates-devon4j-2021.12.006(-sources)?.jar")); + }); + } + + /** + * Tests if the templates specified in the .cobigen file will checked for the correct format defined in the + * documentation. + * + * @throws Exception test fails. + */ + @Test + public void testInstallTemplatesAtStartupWithWrongCoordinates() throws Exception { + + File folder = this.tmpFolder.newFolder("TemplateSetsInstalledTest"); + withEnvironmentVariable(ConfigurationConstants.CONFIG_ENV_HOME, folder.getAbsolutePath()).execute(() -> { + File templateSets = this.tmpFolder.newFolder("TemplateSetsInstalledTest", + ConfigurationConstants.TEMPLATE_SETS_FOLDER); + File downloaded = this.tmpFolder.newFolder("TemplateSetsInstalledTest", + ConfigurationConstants.TEMPLATE_SETS_FOLDER, "downloaded"); + File target = new File(folder, ConfigurationConstants.COBIGEN_CONFIG_FILE); + try (BufferedWriter writer = new BufferedWriter(new FileWriter(target))) { + writer.write("template-sets.installed=com.com.com:com-com:com.com"); + } + CobiGen cobigen = CobiGenFactory.create(templateSets.toURI()); + assertThat(downloaded.listFiles()).hasSize(0); + }); + } +} diff --git a/cobigen/cobigen-core/src/main/java/com/devonfw/cobigen/impl/CobiGenFactory.java b/cobigen/cobigen-core/src/main/java/com/devonfw/cobigen/impl/CobiGenFactory.java index f761496ebf..71cf7cb0a2 100644 --- a/cobigen/cobigen-core/src/main/java/com/devonfw/cobigen/impl/CobiGenFactory.java +++ b/cobigen/cobigen-core/src/main/java/com/devonfw/cobigen/impl/CobiGenFactory.java @@ -1,5 +1,6 @@ package com.devonfw.cobigen.impl; +import java.io.File; import java.net.URI; import java.net.URL; import java.util.Objects; @@ -9,11 +10,15 @@ import com.devonfw.cobigen.api.CobiGen; import com.devonfw.cobigen.api.HealthCheck; +import com.devonfw.cobigen.api.constants.ConfigurationConstants; import com.devonfw.cobigen.api.exception.DeprecatedMonolithicConfigurationException; import com.devonfw.cobigen.api.exception.InvalidConfigurationException; +import com.devonfw.cobigen.api.util.CobiGenPaths; +import com.devonfw.cobigen.api.util.TemplatesJarUtil; import com.devonfw.cobigen.impl.aop.BeanFactory; import com.devonfw.cobigen.impl.aop.ProxyFactory; import com.devonfw.cobigen.impl.config.ConfigurationHolder; +import com.devonfw.cobigen.impl.config.TemplateSetConfiguration; import com.devonfw.cobigen.impl.extension.PluginRegistry; import com.devonfw.cobigen.impl.healthcheck.HealthCheckImpl; import com.devonfw.cobigen.impl.util.ConfigurationClassLoaderUtil; @@ -69,7 +74,8 @@ public static CobiGen create() throws InvalidConfigurationException { } /** - * Creates a new {@link CobiGen} while searching a valid configuration at the given path + * Creates a new {@link CobiGen} while searching a valid configuration at the given path and also start downloading + * templates defined in the properties * * @param configFileOrFolder the root folder containing the context.xml and all templates, configurations etc. * @param allowMonolithicConfiguration ignores deprecated monolithic template folder structure and if found does not @@ -89,8 +95,17 @@ public static CobiGen create(URI configFileOrFolder, boolean allowMonolithicConf // Notifies all plugins of new template root path PluginRegistry.notifyPlugins(configurationHolder.getConfigurationPath()); - if (!allowMonolithicConfiguration && !configurationHolder.isTemplateSetConfiguration()) + if (!allowMonolithicConfiguration && !configurationHolder.isTemplateSetConfiguration()) { throw new DeprecatedMonolithicConfigurationException(); + } + // install Template Sets defined in .properties file + if (configurationHolder.isTemplateSetConfiguration()) { + TemplateSetConfiguration config = ConfigurationFinder.loadTemplateSetConfigurations( + CobiGenPaths.getCobiGenHomePath().resolve(ConfigurationConstants.COBIGEN_CONFIG_FILE)); + URI templatesLocation = ConfigurationFinder.findTemplatesLocation(); + File downloadPath = new File(templatesLocation); + TemplatesJarUtil.downloadTemplatesByMavenCoordinates(downloadPath.toPath(), config.getMavenCoordinates()); + } return createBean; } @@ -109,6 +124,7 @@ public static CobiGen create(boolean allowMonolithicConfiguration) throws Invali throw new InvalidConfigurationException( "No valid templates can be found. Please configure your cobigen configuration file properly or place the templates in cobigen home directory. Creating CobiGen instance aborted."); } + return create(configFileOrFolder, allowMonolithicConfiguration); } diff --git a/cobigen/cobigen-core/src/main/java/com/devonfw/cobigen/impl/config/TemplateSetConfiguration.java b/cobigen/cobigen-core/src/main/java/com/devonfw/cobigen/impl/config/TemplateSetConfiguration.java index e21c4e6533..639b78028e 100644 --- a/cobigen/cobigen-core/src/main/java/com/devonfw/cobigen/impl/config/TemplateSetConfiguration.java +++ b/cobigen/cobigen-core/src/main/java/com/devonfw/cobigen/impl/config/TemplateSetConfiguration.java @@ -1,13 +1,23 @@ package com.devonfw.cobigen.impl.config; +import java.util.ArrayList; import java.util.List; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.devonfw.cobigen.api.constants.TemplatesJarConstants; +import com.devonfw.cobigen.api.util.MavenCoordinate; + /** - * mdukhan This Class is used to set specific properties if not found, or save them if correctly found. These properties - * are groupIds, allowSnapshots and hideTemplates. + * This Class is used to set specific properties if not found, or save them if correctly found. These properties are + * groupIds, allowSnapshots and hideTemplates. */ public class TemplateSetConfiguration { + /** Logger instance */ + private static final Logger LOG = LoggerFactory.getLogger(TemplateSetConfiguration.class); + /** variable for template-set artifacts */ private List groupIds; @@ -15,25 +25,57 @@ public class TemplateSetConfiguration { private boolean allowSnapshots; /** variable to hide very specific template sets or versions of template sets */ - private List hideTemplates; + private List hideTemplates; + + /** List of mavenCoordinates for the template sets that should be installed at cobigen startup */ + private List mavenCoordinates; /** * The constructor. load properties from a given source * - * @param groupIds - * @param allowSnapshots - * @param hideTemplates + * @param groupIds groupID from key template-sets.groupIds + * @param allowSnapshots from key template-sets.allow-snapshot + * @param hideTemplates from key template-set.hide + * @param mavenCoordinates list of mavenCoordinate that define the templates that should be installed */ - public TemplateSetConfiguration(List groupIds, boolean allowSnapshots, List hideTemplates) { + public TemplateSetConfiguration(List groupIds, boolean allowSnapshots, List hideTemplates, + List mavenCoordinates) { super(); this.groupIds = groupIds; this.allowSnapshots = allowSnapshots; - this.hideTemplates = hideTemplates; + this.hideTemplates = convertToMavenCoordinates(hideTemplates); + this.mavenCoordinates = convertToMavenCoordinates(mavenCoordinates); + } + + /** + * Takes a string with multiple maven coordinates separates them and checks if they meet the maven naming conventions + * and are therefore valid. + * + * @param mavenCoordinatesString a String that contains maven coordinates + * @return List with {@link MavenCoordinate} + */ + private List convertToMavenCoordinates(List mavenCoordinatesString) { + + List result = new ArrayList<>(); + for (String mavenCoordinate : mavenCoordinatesString) { + mavenCoordinate = mavenCoordinate.trim(); + if (!mavenCoordinate.matches(TemplatesJarConstants.MAVEN_COORDINATES_CHECK)) { + LOG.warn("configuration key:" + mavenCoordinate + " in .cobigen for " + + "template-sets.installed or template-sets.hide doesnt match the specification and could not be used"); + } else { + String[] split = mavenCoordinate.split(":"); + String groupID = split[0]; + String artifactID = split[1]; + String version = split.length > 2 ? split[2] : null; + result.add(new MavenCoordinate(groupID, artifactID, version)); + } + } + return result; } /** - * return a list of the saved groupIds + * Returns a list of the saved groupIds * * @return groupIds */ @@ -43,7 +85,7 @@ public List getGroupIds() { } /** - * set a list of the groupIds from a source + * Sets a list of the groupIds from a source * * @param groupIds new value of {@link #getgroupIds}. */ @@ -53,7 +95,7 @@ public void setGroupIds(List groupIds) { } /** - * return a boolean which states if specific Snapshots should be allowed. + * Returns a boolean which states if specific Snapshots should be allowed. * * @return allowSnapshots */ @@ -63,7 +105,7 @@ public boolean isAllowSnapshots() { } /** - * set a value on the snapshot + * Sets a value on the snapshot * * @param allowSnapshots new value of {@link #getallowSnapshots}. */ @@ -73,23 +115,33 @@ public void setAllowSnapshots(boolean allowSnapshots) { } /** - * return a list of the saved templates to be hidden + * Returns a list of the saved templates to be hidden * * @return hideTemplates */ - public List getHideTemplates() { + public List getHideTemplates() { return this.hideTemplates; } /** - * set a list of the HideTemplate from a source + * Sets a list of the HideTemplate from a source * * @param hideTemplates new value of {@link #gethideTemplates}. */ - public void setHideTemplates(List hideTemplates) { + public void setHideTemplates(List hideTemplates) { this.hideTemplates = hideTemplates; } + /** + * Returns a list of maven coordinates for the download of template sets + * + * @return maven coordinates + */ + public List getMavenCoordinates() { + + return this.mavenCoordinates; + } + } \ No newline at end of file diff --git a/cobigen/cobigen-core/src/main/java/com/devonfw/cobigen/impl/util/ConfigurationFinder.java b/cobigen/cobigen-core/src/main/java/com/devonfw/cobigen/impl/util/ConfigurationFinder.java index 56bae9e30e..739590d399 100644 --- a/cobigen/cobigen-core/src/main/java/com/devonfw/cobigen/impl/util/ConfigurationFinder.java +++ b/cobigen/cobigen-core/src/main/java/com/devonfw/cobigen/impl/util/ConfigurationFinder.java @@ -54,22 +54,33 @@ public static TemplateSetConfiguration loadTemplateSetConfigurations(Path path) String hide = ConfigurationConstants.CONFIG_PROPERTY_TEMPLATE_SETS_HIDE; String disableLookup = ConfigurationConstants.CONFIG_PROPERTY_TEMPLATE_SETS_DISABLE_LOOKUP; String defaultGroupId = ConfigurationConstants.CONFIG_PROPERTY_TEMPLATE_SETS_DEFAULT_GROUPID; + String templateSetsInstalled = ConfigurationConstants.CONFIG_PROPERTY_TEMPLATE_SETS_INSTALLED; - List groupIdsList = (props.getProperty(groupId) != null) - ? Arrays.asList(props.getProperty(groupId).split(",")) - : new ArrayList<>(); + List groupIdsList = new ArrayList<>(); + if (props.getProperty(groupId) != null) { + groupIdsList = Arrays.asList(props.getProperty(groupId).split(",")); + } // Creating a new ArrayList object which can be modified and prevents UnsupportedOperationException. List groupIds = new ArrayList<>(groupIdsList); if (props.getProperty(disableLookup) == null || props.getProperty(disableLookup).equals("false")) if (!groupIds.contains(defaultGroupId)) groupIds.add(defaultGroupId); - boolean useSnapshots = props.getProperty(snapshot) == null || props.getProperty(snapshot).equals("false") ? false - : true; - List hiddenIds = (props.getProperty(hide) != null) ? Arrays.asList(props.getProperty(hide).split(",")) - : new ArrayList<>(); + boolean useSnapshots = false; + if (props.getProperty(snapshot) != null && props.getProperty(snapshot).equals("true")) { + useSnapshots = true; + } + + List hiddenIds = new ArrayList<>(); + if (props.getProperty(hide) != null) { + hiddenIds = Arrays.asList(props.getProperty(hide).split(",")); + } - return new TemplateSetConfiguration(groupIds, useSnapshots, hiddenIds); + List mavenCoordinates = new ArrayList<>(); + if (props.getProperty(templateSetsInstalled) != null) { + mavenCoordinates = Arrays.asList(props.getProperty(templateSetsInstalled).split(",")); + } + return new TemplateSetConfiguration(groupIds, useSnapshots, hiddenIds, mavenCoordinates); } /** @@ -82,7 +93,7 @@ public static URI findTemplatesLocation() { Path cobigenHome = CobiGenPaths.getCobiGenHomePath(); Path configFile = cobigenHome.resolve(ConfigurationConstants.COBIGEN_CONFIG_FILE); - if (configFile != null && Files.exists(configFile)) { + if (configFile != null && Files.exists(configFile) && !Files.isDirectory(configFile)) { LOG.debug("Custom cobigen configuration found at {}", configFile); Properties props = readConfigurationFile(configFile); String templatesLocation = props.getProperty(ConfigurationConstants.CONFIG_PROPERTY_TEMPLATES_PATH); @@ -193,14 +204,8 @@ private static URI findTemplates(Path home) { return templateSetsFolderPath.toUri(); } - // 5. download template set jars - - LOG.info("Could not find any templates in cobigen home directory {}. Downloading...", - CobiGenPaths.getCobiGenHomePath()); - - TemplatesJarUtil.downloadLatestDevon4jTemplates(true, templatesPath.toFile()); - TemplatesJarUtil.downloadLatestDevon4jTemplates(false, templatesPath.toFile()); return templateSetsFolderPath.toUri(); + } } diff --git a/cobigen/cobigen-core/src/test/java/com/devonfw/cobigen/unittest/config/ConfigurationFinderTest.java b/cobigen/cobigen-core/src/test/java/com/devonfw/cobigen/unittest/config/ConfigurationFinderTest.java index f2989222f2..c8d253aa00 100644 --- a/cobigen/cobigen-core/src/test/java/com/devonfw/cobigen/unittest/config/ConfigurationFinderTest.java +++ b/cobigen/cobigen-core/src/test/java/com/devonfw/cobigen/unittest/config/ConfigurationFinderTest.java @@ -1,6 +1,7 @@ package com.devonfw.cobigen.unittest.config; import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.Assert.assertTrue; import java.nio.file.Path; import java.nio.file.Paths; @@ -47,7 +48,24 @@ public void validConfigurationTest() { assertThat(conf.getGroupIds()).containsSequence("devonfw-cobigen-bla", "abcd", "blablob", ConfigurationConstants.CONFIG_PROPERTY_TEMPLATE_SETS_DEFAULT_GROUPID); assertThat(conf.isAllowSnapshots()).isTrue(); - assertThat(conf.getHideTemplates()).contains("com.devonfw:test-artifact:3.2.1-SNAPSHOT"); + assertThat(conf.getHideTemplates().get(0).getArtifactId().equals("com.devonfw")); + assertThat(conf.getHideTemplates().get(0).getGroupId().equals("test-artifact")); + assertThat(conf.getHideTemplates().get(0).getVersion().equals("3.2.1-SNAPSHOT")); + } + + /** + * Test loadTemplateSetConfigurations Method in ConfigurationFinder if valid properties found, to load these valid + * properties correctly. + */ + @Test + public void invalidInputConfigurationTest() { + + Path validConfiguration = Paths + .get("src/test/resources/testdata/unittest/config/properties/invalidConfigProperties/config.properties"); + TemplateSetConfiguration conf = ConfigurationFinder.loadTemplateSetConfigurations(validConfiguration); + + assertTrue(conf.getHideTemplates().isEmpty()); + assertTrue(conf.getMavenCoordinates().isEmpty()); } /** diff --git a/cobigen/cobigen-core/src/test/java/com/devonfw/cobigen/unittest/templates/TemplateJarDownloaderTest.java b/cobigen/cobigen-core/src/test/java/com/devonfw/cobigen/unittest/templates/TemplateJarDownloaderTest.java index b4fb487b9d..87ed5329af 100644 --- a/cobigen/cobigen-core/src/test/java/com/devonfw/cobigen/unittest/templates/TemplateJarDownloaderTest.java +++ b/cobigen/cobigen-core/src/test/java/com/devonfw/cobigen/unittest/templates/TemplateJarDownloaderTest.java @@ -3,11 +3,19 @@ import static org.assertj.core.api.Assertions.assertThat; import java.io.File; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.List; +import org.junit.After; +import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.rules.TemporaryFolder; +import com.devonfw.cobigen.api.constants.ConfigurationConstants; +import com.devonfw.cobigen.api.constants.TemplatesJarConstants; +import com.devonfw.cobigen.api.util.MavenCoordinate; import com.devonfw.cobigen.api.util.TemplatesJarUtil; import com.devonfw.cobigen.unittest.config.common.AbstractUnitTest; @@ -16,13 +24,186 @@ */ public class TemplateJarDownloaderTest extends AbstractUnitTest { - /** Root path to all resources used in this test case */ - private static String testFileRootPath = "src/test/resources/testdata/unittest/config/templatesJar/"; - /** JUnit Rule to create and automatically cleanup temporarily files/folders */ @Rule public TemporaryFolder tempFolder = new TemporaryFolder(); + /** List with MavenCoordinates for template downloader */ + public List mavenCoordinatesList; + + /** + * Location of the templates sets. + */ + public File templateLocation; + + /** + * Downloaded folder for template jars. + */ + public File downloadedFolder; + + /** + * Creation of folder structure for the tests + * + * @throws Exception + */ + @Before + public void init() throws Exception { + + this.templateLocation = this.tempFolder.newFolder("templateLocation"); + this.downloadedFolder = this.tempFolder.newFolder("templateLocation", ConfigurationConstants.DOWNLOADED_FOLDER); + this.mavenCoordinatesList = new ArrayList<>(); + } + + /** + * Cleanup after test + */ + @After + public void cleanup() { + + this.mavenCoordinatesList.clear(); + this.tempFolder.delete(); + } + + /** + * Helper function in this test suite to create maven coordinates for cobigen devon4j templates. If the version is + * null LATEST is used + * + * @param version version of the cobigen templates jar. If null LATEST will be used. + * @return returns a {@link MavenCoordinate} object for cobigen devon4j templates. + */ + private MavenCoordinate createMavenCoordinateForDevon4jTemplates(String version) { + + String versionNotNull = version == null ? "LATEST" : version; + return new MavenCoordinate(TemplatesJarConstants.DEVON4J_TEMPLATES_GROUPID, + TemplatesJarConstants.DEVON4J_TEMPLATES_ARTIFACTID, versionNotNull); + } + + /** + * Tests if already existing jar will prevent the download of templates + * + * @throws Exception + */ + @Test + public void testDownloadTemplatesAlreadyExisting() throws Exception { + + // preparation + this.mavenCoordinatesList.add(new MavenCoordinate("com.group", "artifact-id", "1.0")); + this.mavenCoordinatesList.add(new MavenCoordinate("some.group", "some-artifact", "2.01")); + createFileOrFolder(this.mavenCoordinatesList.get(0), this.downloadedFolder, false); + createFileOrFolder(this.mavenCoordinatesList.get(1), this.downloadedFolder, false); + // Perform download + TemplatesJarUtil.downloadTemplatesByMavenCoordinates(this.templateLocation.toPath(), this.mavenCoordinatesList); + assertThat(this.downloadedFolder.listFiles()).hasSize(2); + // Perform download + TemplatesJarUtil.downloadTemplatesByMavenCoordinates(this.templateLocation.toPath(), this.mavenCoordinatesList); + assertThat(this.downloadedFolder.listFiles()).hasSize(2); + } + + /** + * Tests if templates can be loaded without providing a version + */ + @Test + public void testDownloadTemplatesWithoutVersion() { + + // preparation + this.mavenCoordinatesList.add(createMavenCoordinateForDevon4jTemplates("")); + // Perform download + TemplatesJarUtil.downloadTemplatesByMavenCoordinates(this.templateLocation.toPath(), this.mavenCoordinatesList); + // Assert + assertThat(this.downloadedFolder.listFiles()).hasSize(2); + assertThat(this.downloadedFolder.listFiles()) + .allMatch(f -> f.getName().matches("templates-devon4j-2021.12.006(-sources)?.jar")); + // preparation + this.mavenCoordinatesList.add(createMavenCoordinateForDevon4jTemplates("LATEST")); + this.mavenCoordinatesList.remove(0); + // Perform download + TemplatesJarUtil.downloadTemplatesByMavenCoordinates(this.templateLocation.toPath(), this.mavenCoordinatesList); + // Assert + assertThat(this.downloadedFolder.listFiles()).hasSize(2); + + } + + /** + * Test if LATEST templates can be loaded + */ + @Test + public void testDownloadTemplatesWithLATEST() { + + // preparation + this.mavenCoordinatesList.add(createMavenCoordinateForDevon4jTemplates("LATEST")); + // Perform download + TemplatesJarUtil.downloadTemplatesByMavenCoordinates(this.templateLocation.toPath(), this.mavenCoordinatesList); + // Assert + assertThat(this.downloadedFolder.listFiles()).hasSize(2); + assertThat(this.downloadedFolder.listFiles()) + .allMatch(f -> f.getName().matches("templates-devon4j-2021.12.006(-sources)?.jar")); + + } + + /** + * Test if no download occurs if one template is adapted the second one is downloaded and the third is missing + * + * @throws Exception + */ + @Test + public void testDownloadTemplates() throws Exception { + + // preparation + File adapted = this.tempFolder.newFolder("templateLocation/adapted"); + this.mavenCoordinatesList.add(new MavenCoordinate("com.group", "artifact-id", "1.0")); + this.mavenCoordinatesList.add(new MavenCoordinate("some.group", "some-artifact", "2.01")); + this.mavenCoordinatesList.add(createMavenCoordinateForDevon4jTemplates(null)); + this.mavenCoordinatesList.add(createMavenCoordinateForDevon4jTemplates(null)); + createFileOrFolder(this.mavenCoordinatesList.get(0), adapted, true); + createFileOrFolder(this.mavenCoordinatesList.get(1), this.downloadedFolder, false); + // Perform download + TemplatesJarUtil.downloadTemplatesByMavenCoordinates(this.templateLocation.toPath(), this.mavenCoordinatesList); + // Assert + assertThat(this.downloadedFolder.listFiles()).hasSize(3); + assertThat(adapted.listFiles()).hasSize(1); + } + + /** + * Test if new templates will be loaded into downloaded if already adapted templates exits + * + * @throws Exception + */ + + @Test + public void testDownloadTemplatesAlreadyAdapted() throws Exception { + + // preparation + File adapted = this.tempFolder.newFolder("templateLocation/adapted"); + this.mavenCoordinatesList.add(new MavenCoordinate("com.group", "artifact-id", "1.0")); + this.mavenCoordinatesList.add(new MavenCoordinate("some.group", "some-artifact", "2.01")); + this.mavenCoordinatesList.add(new MavenCoordinate("com.com", "app-app", "87")); + this.mavenCoordinatesList.add(createMavenCoordinateForDevon4jTemplates(null)); + createFileOrFolder(this.mavenCoordinatesList.get(0), adapted, true); + createFileOrFolder(this.mavenCoordinatesList.get(1), adapted, true); + createFileOrFolder(this.mavenCoordinatesList.get(2), adapted, true); + // Perform download + TemplatesJarUtil.downloadTemplatesByMavenCoordinates(this.templateLocation.toPath(), this.mavenCoordinatesList); + // Assert + assertThat(this.downloadedFolder.listFiles()).hasSize(2); + assertThat(adapted.listFiles()).hasSize(3); + + } + + private void createFileOrFolder(MavenCoordinate m, File f, boolean folder) throws Exception { + + String templateName = m.getArtifactId() + "-" + m.getGroupId() + "-" + m.getVersion(); + if (folder) { + Path temp = this.tempFolder.getRoot().toPath().relativize(f.toPath()); + this.tempFolder.newFolder(temp.resolve(templateName).toString()); + } else { + try { + File.createTempFile(templateName, ".jar", f); + } catch (Exception e) { + throw e; + } + } + } + /** * Tests the valid upgrade of a templates jar * @@ -32,6 +213,8 @@ public class TemplateJarDownloaderTest extends AbstractUnitTest { public void testCorrectTemplatesUpgrade() throws Exception { // preparation + this.downloadedFolder.delete(); + this.templateLocation.delete(); this.tempFolder.newFile("templates-devon4j-3.0.0.jar"); File tmpJarFolder = this.tempFolder.getRoot(); diff --git a/cobigen/cobigen-core/src/test/java/com/devonfw/cobigen/unittest/util/ConfigurationUtilTest.java b/cobigen/cobigen-core/src/test/java/com/devonfw/cobigen/unittest/util/ConfigurationUtilTest.java index b5ec19e20c..9e33e6bebc 100644 --- a/cobigen/cobigen-core/src/test/java/com/devonfw/cobigen/unittest/util/ConfigurationUtilTest.java +++ b/cobigen/cobigen-core/src/test/java/com/devonfw/cobigen/unittest/util/ConfigurationUtilTest.java @@ -1,6 +1,5 @@ package com.devonfw.cobigen.unittest.util; -import static com.github.stefanbirkner.systemlambda.SystemLambda.restoreSystemProperties; import static com.github.stefanbirkner.systemlambda.SystemLambda.withEnvironmentVariable; import static org.assertj.core.api.Assertions.assertThat; @@ -34,11 +33,10 @@ public class ConfigurationUtilTest { @Test public void testFindTemplatesLocation() throws Exception { - restoreSystemProperties(() -> { - File userHome = this.tmpFolder.newFolder("user-home"); + File userHome = this.tmpFolder.newFolder("user-home"); + withEnvironmentVariable(ConfigurationConstants.CONFIG_ENV_HOME, userHome.getAbsolutePath()).execute(() -> { System.setProperty("user.home", userHome.getAbsolutePath()); - Path defaultCobigenHome = userHome.toPath().resolve(ConfigurationConstants.DEFAULT_HOME_DIR_NAME); - Path templatesFolder = defaultCobigenHome.resolve(ConfigurationConstants.TEMPLATE_SETS_FOLDER); + Path templatesFolder = userHome.toPath().resolve(ConfigurationConstants.TEMPLATE_SETS_FOLDER); Files.createDirectories(templatesFolder); String templatesArtifact = "templates-devon4j-1.0.jar"; @@ -68,7 +66,7 @@ public void testFindTemplatesLocation() throws Exception { assertThat(ConfigurationFinder.findTemplatesLocation()).isEqualTo(templates.toURI()); }); - Path configFileInCobigenHome = defaultCobigenHome.resolve(ConfigurationConstants.COBIGEN_CONFIG_FILE); + Path configFileInCobigenHome = userHome.toPath().resolve(ConfigurationConstants.COBIGEN_CONFIG_FILE); FileUtils.copyFile(configFile, configFileInCobigenHome.toFile()); // configuration file found in cobigen home directory assertThat(ConfigurationFinder.findTemplatesLocation()).isEqualTo(templates.toURI()); diff --git a/cobigen/cobigen-core/src/test/resources/testdata/unittest/config/properties/invalidConfigProperties/config.properties b/cobigen/cobigen-core/src/test/resources/testdata/unittest/config/properties/invalidConfigProperties/config.properties new file mode 100644 index 0000000000..068df3c9be --- /dev/null +++ b/cobigen/cobigen-core/src/test/resources/testdata/unittest/config/properties/invalidConfigProperties/config.properties @@ -0,0 +1,2 @@ +template-sets.installed=com.com.com:com.com:com.com:com;blabla:blabla: +template-sets.hide=com.com.com:com.com:com.com:com;blabla:blabla: \ No newline at end of file diff --git a/documentation/cobigen-core_configuration.asciidoc b/documentation/cobigen-core_configuration.asciidoc index a8a0be1dbf..befb20bca3 100644 --- a/documentation/cobigen-core_configuration.asciidoc +++ b/documentation/cobigen-core_configuration.asciidoc @@ -98,6 +98,10 @@ configure multiple (comma separated) `groupIds`. By default, (public) CobiGen `g * `template-sets.hide:` Hide very specific template sets or versions of template sets. +* `template-sets.installed:` Template sets will be available at cobigen startup if template sets arent already adapted. + +The key `template-sets.hide` and `template-sets.installed` accept maven coordinate with the following format: **groupID:artifactID:version** the version is optional and if omitted the **LATEST** version will be used. You can specify multiple maven coordinates seperated with *,*. + * An example of how such a configuration should look like: ``` @@ -105,6 +109,7 @@ template-sets.groupIds=com.devonfw.cobigen.templates,jaxen,jakarta.xml.bind template-sets.allow-snapshots=true template-sets.disable-default-lookup=false template-sets.hide=com.devonfw.cobigen.templates:crud-angular-client-app:2021.12.007-SNAPSHOT +template-sets.installed=com.devonfw.cobigen.templates:crud-angular-client-app:2021.12.007-SNAPSHOT, com.devonfw.cobigen.templates:crud-java-server-app: ``` == Context Configuration