From 1c403855c77f2d785fccf47639cc364de688c66e Mon Sep 17 00:00:00 2001 From: Mathieu Carbou Date: Mon, 28 Mar 2022 18:19:28 +0200 Subject: [PATCH] Rewrote the PropertiesProvider API to support initialization, close and multithreading better --- .../license/git/CopyrightAuthorProvider.java | 52 ++++--- .../license/git/CopyrightRangeProvider.java | 58 +++++--- .../maven/plugin/license/git/GitLookup.java | 133 +++++++++++++---- .../license/git/GitPropertiesProvider.java | 93 ------------ .../git/CopyrightAuthorProviderTest.java | 33 +++-- .../git/CopyrightRangeProviderTest.java | 40 +++-- .../plugin/license/git/GitLookupTest.java | 38 +++-- .../license/svn/SVNPropertiesProvider.java | 104 +++++++------ .../plugin/license/AbstractLicenseMojo.java | 139 +++++++++++------- .../plugin/license/PropertiesProvider.java | 31 +++- .../document/DocumentPropertiesLoader.java | 5 +- .../document/PropertyPlaceholderResolver.java | 8 +- .../src/test/java/MyPropertiesProvider.java | 16 +- .../plugin/license/document/DocumentTest.java | 7 +- 14 files changed, 437 insertions(+), 320 deletions(-) delete mode 100644 license-maven-plugin-git/src/main/java/com/mycila/maven/plugin/license/git/GitPropertiesProvider.java diff --git a/license-maven-plugin-git/src/main/java/com/mycila/maven/plugin/license/git/CopyrightAuthorProvider.java b/license-maven-plugin-git/src/main/java/com/mycila/maven/plugin/license/git/CopyrightAuthorProvider.java index 7e85d97a3..9bddc39b2 100644 --- a/license-maven-plugin-git/src/main/java/com/mycila/maven/plugin/license/git/CopyrightAuthorProvider.java +++ b/license-maven-plugin-git/src/main/java/com/mycila/maven/plugin/license/git/CopyrightAuthorProvider.java @@ -18,26 +18,41 @@ import com.mycila.maven.plugin.license.AbstractLicenseMojo; import com.mycila.maven.plugin.license.PropertiesProvider; import com.mycila.maven.plugin.license.document.Document; +import java.io.IOException; +import java.io.UncheckedIOException; import java.util.Collections; import java.util.HashMap; import java.util.Map; -import java.util.Properties; /** - * An implementation of {@link PropertiesProvider} that adds {@value #COPYRIGHT_CREATION_AUTHOR_NAME_KEY} and - * {@value #COPYRIGHT_CREATION_AUTHOR_EMAIL_KEY} values - see - * {@link #getAdditionalProperties(AbstractLicenseMojo, Properties, Document)}. + * An implementation of {@link PropertiesProvider} that adds {@value + * #COPYRIGHT_CREATION_AUTHOR_NAME_KEY} and {@value #COPYRIGHT_CREATION_AUTHOR_EMAIL_KEY} values - + * see {@link #adjustProperties(AbstractLicenseMojo, Map, Document)}. * * @author masakimu */ -public class CopyrightAuthorProvider extends GitPropertiesProvider implements PropertiesProvider { +public class CopyrightAuthorProvider implements PropertiesProvider { public static final String COPYRIGHT_CREATION_AUTHOR_NAME_KEY = "license.git.CreationAuthorName"; public static final String COPYRIGHT_CREATION_AUTHOR_EMAIL_KEY = "license.git.CreationAuthorEmail"; + private GitLookup gitLookup; - public CopyrightAuthorProvider() { - super(); + @Override + public void init(AbstractLicenseMojo mojo, Map currentProperties) { + gitLookup = GitLookup.create(mojo.defaultBasedir, currentProperties); + + // One-time warning for shallow repo + if (mojo.warnIfShallow && gitLookup.isShallowRepository()) { + mojo.warn("Shallow git repository detected. Author property values may not be accurate."); + } + } + + @Override + public void close() { + if (gitLookup != null) { + gitLookup.close(); + } } /** @@ -49,21 +64,20 @@ public CopyrightAuthorProvider() { *
  • {@value #COPYRIGHT_CREATION_AUTHOR_EMAIL_KEY} key stores the author's email address of the first git commit. * */ - public Map getAdditionalProperties(AbstractLicenseMojo mojo, Properties properties, - Document document) { - + @Override + public Map adjustProperties(AbstractLicenseMojo mojo, + Map properties, Document document) { try { Map result = new HashMap<>(3); - GitLookup gitLookup = getGitLookup(mojo, document.getFile(), properties); - - result.put(COPYRIGHT_CREATION_AUTHOR_NAME_KEY, gitLookup.getAuthorNameOfCreation(document.getFile())); - result.put(COPYRIGHT_CREATION_AUTHOR_EMAIL_KEY, gitLookup.getAuthorEmailOfCreation(document.getFile())); + result.put(COPYRIGHT_CREATION_AUTHOR_NAME_KEY, + gitLookup.getAuthorNameOfCreation(document.getFile())); + result.put(COPYRIGHT_CREATION_AUTHOR_EMAIL_KEY, + gitLookup.getAuthorEmailOfCreation(document.getFile())); return Collections.unmodifiableMap(result); - } catch (Exception e) { - throw new RuntimeException("Could not compute the year of the last git commit for file " - + document.getFile().getAbsolutePath(), e); + } catch (IOException e) { + throw new UncheckedIOException( + "CopyrightAuthorProvider error on file: " + document.getFile().getAbsolutePath() + ": " + + e.getMessage(), e); } } - - } diff --git a/license-maven-plugin-git/src/main/java/com/mycila/maven/plugin/license/git/CopyrightRangeProvider.java b/license-maven-plugin-git/src/main/java/com/mycila/maven/plugin/license/git/CopyrightRangeProvider.java index b87311067..916498717 100644 --- a/license-maven-plugin-git/src/main/java/com/mycila/maven/plugin/license/git/CopyrightRangeProvider.java +++ b/license-maven-plugin-git/src/main/java/com/mycila/maven/plugin/license/git/CopyrightRangeProvider.java @@ -18,19 +18,20 @@ import com.mycila.maven.plugin.license.AbstractLicenseMojo; import com.mycila.maven.plugin.license.PropertiesProvider; import com.mycila.maven.plugin.license.document.Document; +import java.io.IOException; import java.util.Collections; import java.util.HashMap; import java.util.Map; -import java.util.Properties; +import org.eclipse.jgit.api.errors.GitAPIException; /** * An implementation of {@link PropertiesProvider} that adds {@value #COPYRIGHT_LAST_YEAR_KEY} and - * {@value #COPYRIGHT_YEARS_KEY} values - see - * {@link #getAdditionalProperties(AbstractLicenseMojo, Properties, Document)}. + * {@value #COPYRIGHT_YEARS_KEY} values - see {@link #adjustProperties(AbstractLicenseMojo, Map, + * Document)}. * * @author Peter Palaga */ -public class CopyrightRangeProvider extends GitPropertiesProvider implements PropertiesProvider { +public class CopyrightRangeProvider implements PropertiesProvider { public static final String COPYRIGHT_LAST_YEAR_KEY = "license.git.copyrightLastYear"; public static final String COPYRIGHT_CREATION_YEAR_KEY = "license.git.copyrightCreationYear"; @@ -38,9 +39,23 @@ public class CopyrightRangeProvider extends GitPropertiesProvider implements Pro public static final String COPYRIGHT_YEARS_KEY = "license.git.copyrightYears"; public static final String INCEPTION_YEAR_KEY = "project.inceptionYear"; + private GitLookup gitLookup; - public CopyrightRangeProvider() { - super(); + @Override + public void init(AbstractLicenseMojo mojo, Map currentProperties) { + gitLookup = GitLookup.create(mojo.defaultBasedir, currentProperties); + + // One-time warning for shallow repo + if (mojo.warnIfShallow && gitLookup.isShallowRepository()) { + mojo.warn("Shallow git repository detected. Year property values may not be accurate."); + } + } + + @Override + public void close() { + if (gitLookup != null) { + gitLookup.close(); + } } /** @@ -54,16 +69,17 @@ public CopyrightRangeProvider() { * returned; otherwise, the two values are combined using dash, so that the result is e.g. {@code "2000-2010"}.
  • *
  • {@value #COPYRIGHT_CREATION_YEAR_KEY} key stores the year from the committer date of the first git commit for * the supplied {@code document}.
  • - *
  • {@value #COPYRIGHT_EXISTENCE_YEARS_KEY} key stores the range from {@value #COPYRIGHT_CREATION_YEAR_KEY} value to + *
  • {@value #COPYRIGHT_EXISTENCE_YEARS_KEY} key stores the range from {@value #COPYRIGHT_CREATION_YEAR_KEY} value to * {@value #COPYRIGHT_LAST_YEAR_KEY} value. If both values are equal only the {@value #COPYRIGHT_CREATION_YEAR_KEY} is returned; * otherwise, the two values are combined using dash, so that the result is e.g. {@code "2005-2010"}.
  • * * The {@value #INCEPTION_YEAR_KEY} value is read from the supplied properties and it must available. Otherwise a * {@link RuntimeException} is thrown. */ - public Map getAdditionalProperties(AbstractLicenseMojo mojo, Properties properties, - Document document) { - String inceptionYear = properties.getProperty(INCEPTION_YEAR_KEY); + @Override + public Map adjustProperties(AbstractLicenseMojo mojo, + Map properties, Document document) { + String inceptionYear = properties.get(INCEPTION_YEAR_KEY); if (inceptionYear == null) { throw new RuntimeException("'" + INCEPTION_YEAR_KEY + "' must have a value for file " + document.getFile().getAbsolutePath()); @@ -72,12 +88,13 @@ public Map getAdditionalProperties(AbstractLicenseMojo mojo, Pro try { inceptionYearInt = Integer.parseInt(inceptionYear); } catch (NumberFormatException e1) { - throw new RuntimeException("'" + INCEPTION_YEAR_KEY + "' must be an integer ; found = " + inceptionYear + " file: " - + document.getFile().getAbsolutePath()); + throw new RuntimeException( + "'" + INCEPTION_YEAR_KEY + "' must be an integer ; found = " + inceptionYear + " file: " + + document.getFile().getAbsolutePath()); } try { Map result = new HashMap<>(4); - GitLookup gitLookup = getGitLookup(mojo, document.getFile(), properties); + int copyrightEnd = gitLookup.getYearOfLastChange(document.getFile()); result.put(COPYRIGHT_LAST_YEAR_KEY, Integer.toString(copyrightEnd)); final String copyrightYears; @@ -90,19 +107,20 @@ public Map getAdditionalProperties(AbstractLicenseMojo mojo, Pro int copyrightStart = gitLookup.getYearOfCreation(document.getFile()); result.put(COPYRIGHT_CREATION_YEAR_KEY, Integer.toString(copyrightStart)); - + final String copyrightExistenceYears; if (copyrightStart >= copyrightEnd) { - copyrightExistenceYears = Integer.toString(copyrightStart); + copyrightExistenceYears = Integer.toString(copyrightStart); } else { - copyrightExistenceYears = copyrightStart + "-" + copyrightEnd; + copyrightExistenceYears = copyrightStart + "-" + copyrightEnd; } result.put(COPYRIGHT_EXISTENCE_YEARS_KEY, copyrightExistenceYears); - + return Collections.unmodifiableMap(result); - } catch (Exception e) { - throw new RuntimeException("Could not compute the year of the last git commit for file " - + document.getFile().getAbsolutePath(), e); + } catch (IOException | GitAPIException e) { + throw new RuntimeException( + "CopyrightRangeProvider error on file: " + document.getFile().getAbsolutePath() + ": " + + e.getMessage(), e); } } } diff --git a/license-maven-plugin-git/src/main/java/com/mycila/maven/plugin/license/git/GitLookup.java b/license-maven-plugin-git/src/main/java/com/mycila/maven/plugin/license/git/GitLookup.java index 57405b3b3..a4a8783f5 100644 --- a/license-maven-plugin-git/src/main/java/com/mycila/maven/plugin/license/git/GitLookup.java +++ b/license-maven-plugin-git/src/main/java/com/mycila/maven/plugin/license/git/GitLookup.java @@ -15,12 +15,16 @@ */ package com.mycila.maven.plugin.license.git; +import java.io.Closeable; import java.io.File; import java.io.IOException; +import java.io.UncheckedIOException; import java.util.Arrays; import java.util.Calendar; import java.util.Date; import java.util.Iterator; +import java.util.Locale; +import java.util.Map; import java.util.TimeZone; import org.eclipse.jgit.api.Git; import org.eclipse.jgit.api.Status; @@ -44,9 +48,16 @@ * * @author Peter Palaga */ -public class GitLookup { +public class GitLookup implements Closeable { + public static final TimeZone DEFAULT_ZONE = TimeZone.getTimeZone("GMT"); + public static final String MAX_COMMITS_LOOKUP_KEY = "license.git.maxCommitsLookup"; + // keep for compatibility + private static final String COPYRIGHT_LAST_YEAR_MAX_COMMITS_LOOKUP_KEY = "license.git.copyrightLastYearMaxCommitsLookup"; + public static final String COPYRIGHT_LAST_YEAR_SOURCE_KEY = "license.git.copyrightLastYearSource"; + public static final String COPYRIGHT_LAST_YEAR_TIME_ZONE_KEY = "license.git.copyrightLastYearTimeZone"; + public enum DateSource { AUTHOR, COMMITER } @@ -59,41 +70,94 @@ public enum DateSource { private final boolean shallow; /** - * Creates a new {@link GitLookup} for a repository that is detected from the supplied {@code anyFile}. - *

    - * Note on time zones: - * - * @param anyFile - any path from the working tree of the git repository to consider in all subsequent calls to - * {@link #getYearOfLastChange(File)} - * @param dateSource where to read the commit dates from - committer date or author date - * @param timeZone the time zone if {@code dateSource} is {@link DateSource#COMMITER}; otherwise must be {@code null}. - * @param checkCommitsCount - * @throws IOException + * Lazily initializes #gitLookup assuming that all subsequent calls to this method will be related + * to the same git repository. */ - public GitLookup(File anyFile, DateSource dateSource, TimeZone timeZone, int checkCommitsCount) throws IOException { - super(); - this.repository = new FileRepositoryBuilder().findGitDir(anyFile).build(); - /* A workaround for https://bugs.eclipse.org/bugs/show_bug.cgi?id=457961 */ - // Also contains contents of .git/shallow and can detect shallow repo - this.shallow = !this.repository.getObjectDatabase().newReader().getShallowCommits().isEmpty(); - - this.pathResolver = new GitPathResolver(repository.getWorkTree().getAbsolutePath()); - this.dateSource = dateSource; + public static GitLookup create(File file, Map props) { + String dateSourceString = props.get(COPYRIGHT_LAST_YEAR_SOURCE_KEY); + if (dateSourceString == null) { + dateSourceString = GitLookup.DateSource.AUTHOR.name(); + } + GitLookup.DateSource dateSource = GitLookup.DateSource.valueOf( + dateSourceString.toUpperCase(Locale.US)); + String checkCommitsCountString = props.get(MAX_COMMITS_LOOKUP_KEY); + // Backwads compatibility + if (checkCommitsCountString == null) { + checkCommitsCountString = props.get(COPYRIGHT_LAST_YEAR_MAX_COMMITS_LOOKUP_KEY); + } + int checkCommitsCount = Integer.MAX_VALUE; + if (checkCommitsCountString != null) { + checkCommitsCountString = checkCommitsCountString.trim(); + checkCommitsCount = Integer.parseInt(checkCommitsCountString); + } + final TimeZone timeZone; + String tzString = props.get(COPYRIGHT_LAST_YEAR_TIME_ZONE_KEY); switch (dateSource) { case COMMITER: - this.timeZone = timeZone == null ? DEFAULT_ZONE : timeZone; + timeZone = tzString == null ? GitLookup.DEFAULT_ZONE : TimeZone.getTimeZone(tzString); break; case AUTHOR: - if (timeZone != null) { - throw new IllegalArgumentException("Time zone must be null with dateSource " + DateSource.AUTHOR.name() - + " because git author name already contrains time zone information."); + if (tzString != null) { + throw new RuntimeException(COPYRIGHT_LAST_YEAR_TIME_ZONE_KEY + " must not be set with " + + COPYRIGHT_LAST_YEAR_SOURCE_KEY + " = " + GitLookup.DateSource.AUTHOR.name() + + " because git author name already contains time zone information."); } - this.timeZone = null; + timeZone = null; break; default: - throw new IllegalStateException("Unexpected " + DateSource.class.getName() + " " + dateSource); + throw new IllegalStateException( + "Unexpected " + GitLookup.DateSource.class.getName() + " " + dateSource); + } + return new GitLookup(file, dateSource, timeZone, checkCommitsCount); + } + + /** + * Creates a new {@link GitLookup} for a repository that is detected from the supplied {@code + * anyFile}. + *

    + * Note on time zones: + * + * @param anyFile - any path from the working tree of the git repository to consider in + * all subsequent calls to {@link #getYearOfLastChange(File)} + * @param dateSource where to read the commit dates from - committer date or author date + * @param timeZone the time zone if {@code dateSource} is {@link DateSource#COMMITER}; + * otherwise must be {@code null}. + * @param checkCommitsCount + * @throws IOException + */ + private GitLookup(File anyFile, DateSource dateSource, TimeZone timeZone, int checkCommitsCount) { + try { + this.repository = new FileRepositoryBuilder().findGitDir(anyFile).build(); + /* A workaround for https://bugs.eclipse.org/bugs/show_bug.cgi?id=457961 */ + // Also contains contents of .git/shallow and can detect shallow repo + // the line below reads and caches the entries in the FileObjectDatabase of the repository to + // avoid concurrent modifications during RevWalk + // Closing the repository will close the FileObjectDatabase. + // Here the newReader() is a WindowCursor which delegates the getShallowCommits() to the FileObjectDatabase. + this.shallow = !this.repository.getObjectDatabase().newReader().getShallowCommits().isEmpty(); + + this.pathResolver = new GitPathResolver(repository.getWorkTree().getAbsolutePath()); + this.dateSource = dateSource; + switch (dateSource) { + case COMMITER: + this.timeZone = timeZone == null ? DEFAULT_ZONE : timeZone; + break; + case AUTHOR: + if (timeZone != null) { + throw new IllegalArgumentException( + "Time zone must be null with dateSource " + DateSource.AUTHOR.name() + + " because git author name already contains time zone information."); + } + this.timeZone = null; + break; + default: + throw new IllegalStateException( + "Unexpected " + DateSource.class.getName() + " " + dateSource); + } + this.checkCommitsCount = checkCommitsCount; + } catch (IOException e) { + throw new UncheckedIOException(e); } - this.checkCommitsCount = checkCommitsCount; } /** @@ -148,12 +212,12 @@ int getYearOfCreation(File file) throws IOException, GitAPIException { commitYear = getYearFromCommit(commit); } walk.dispose(); - + // If we couldn't find a creation year from Git assume newly created file if (commitYear == 0) { - return getCurrentYear(); - } - + return getCurrentYear(); + } + return commitYear; } @@ -182,7 +246,7 @@ String getAuthorEmailOfCreation(File file) throws IOException { walk.dispose(); return authorEmail; } - + boolean isShallowRepository() { return this.shallow; } @@ -245,4 +309,9 @@ private String getAuthorEmailFromCommit(RevCommit commit) { PersonIdent id = commit.getAuthorIdent(); return id.getEmailAddress(); } + + @Override + public void close() { + repository.close(); + } } diff --git a/license-maven-plugin-git/src/main/java/com/mycila/maven/plugin/license/git/GitPropertiesProvider.java b/license-maven-plugin-git/src/main/java/com/mycila/maven/plugin/license/git/GitPropertiesProvider.java deleted file mode 100644 index d967b0242..000000000 --- a/license-maven-plugin-git/src/main/java/com/mycila/maven/plugin/license/git/GitPropertiesProvider.java +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright (C) 2008-2022 Mycila (mathieu.carbou@gmail.com) - * - * 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 com.mycila.maven.plugin.license.git; - -import com.mycila.maven.plugin.license.AbstractLicenseMojo; -import java.io.File; -import java.io.IOException; -import java.util.Locale; -import java.util.Properties; -import java.util.TimeZone; - -/** - * @author Peter Palaga - */ -public class GitPropertiesProvider { - - private GitLookup gitLookup; - public static final String MAX_COMMITS_LOOKUP_KEY = "license.git.maxCommitsLookup"; - // keep for compatibility - private static final String COPYRIGHT_LAST_YEAR_MAX_COMMITS_LOOKUP_KEY = "license.git.copyrightLastYearMaxCommitsLookup"; - public static final String COPYRIGHT_LAST_YEAR_SOURCE_KEY = "license.git.copyrightLastYearSource"; - public static final String COPYRIGHT_LAST_YEAR_TIME_ZONE_KEY = "license.git.copyrightLastYearTimeZone"; - - public GitPropertiesProvider() {} - - ; - - /** - * Lazily initializes #gitLookup assuming that all subsequent calls to this method will be related to the same - * git repository. - * - * @param file - * @return - * @throws IOException - */ - GitLookup getGitLookup(AbstractLicenseMojo mojo, File file, Properties props) throws IOException { - if (gitLookup == null) { - synchronized (this) { - if (gitLookup == null) { - String dateSourceString = props.getProperty(COPYRIGHT_LAST_YEAR_SOURCE_KEY, - GitLookup.DateSource.AUTHOR.name()); - GitLookup.DateSource dateSource = GitLookup.DateSource.valueOf(dateSourceString.toUpperCase(Locale.US)); - String checkCommitsCountString = props.getProperty(MAX_COMMITS_LOOKUP_KEY); - // Backwads compatibility - if (checkCommitsCountString == null) { - checkCommitsCountString = props.getProperty(COPYRIGHT_LAST_YEAR_MAX_COMMITS_LOOKUP_KEY); - } - int checkCommitsCount = Integer.MAX_VALUE; - if (checkCommitsCountString != null) { - checkCommitsCountString = checkCommitsCountString.trim(); - checkCommitsCount = Integer.parseInt(checkCommitsCountString); - } - final TimeZone timeZone; - String tzString = props.getProperty(COPYRIGHT_LAST_YEAR_TIME_ZONE_KEY); - switch (dateSource) { - case COMMITER: - timeZone = tzString == null ? GitLookup.DEFAULT_ZONE : TimeZone.getTimeZone(tzString); - break; - case AUTHOR: - if (tzString != null) { - throw new RuntimeException(COPYRIGHT_LAST_YEAR_TIME_ZONE_KEY + " must not be set with " - + COPYRIGHT_LAST_YEAR_SOURCE_KEY + " = " + GitLookup.DateSource.AUTHOR.name() - + " because git author name already contrains time zone information."); - } - timeZone = null; - break; - default: - throw new IllegalStateException("Unexpected " + GitLookup.DateSource.class.getName() + " " + dateSource); - } - gitLookup = new GitLookup(file, dateSource, timeZone, checkCommitsCount); - // One-time warning for shallow repo - if (mojo.warnIfShallow && gitLookup.isShallowRepository()) { - mojo.warn("Shallow git repository detected. Year and author property values may not be accurate."); - } - } - } - } - return gitLookup; - } -} diff --git a/license-maven-plugin-git/src/test/java/com/mycila/maven/plugin/license/git/CopyrightAuthorProviderTest.java b/license-maven-plugin-git/src/test/java/com/mycila/maven/plugin/license/git/CopyrightAuthorProviderTest.java index 3bdf35c1e..9af67d253 100644 --- a/license-maven-plugin-git/src/test/java/com/mycila/maven/plugin/license/git/CopyrightAuthorProviderTest.java +++ b/license-maven-plugin-git/src/test/java/com/mycila/maven/plugin/license/git/CopyrightAuthorProviderTest.java @@ -24,7 +24,6 @@ import java.nio.file.Paths; import java.util.HashMap; import java.util.Map; -import java.util.Properties; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; @@ -44,19 +43,31 @@ class CopyrightAuthorProviderTest { void copyrightAuthor() { CopyrightAuthorProvider provider = new CopyrightAuthorProvider(); - assertAuthor(provider, "dir1/file1.txt", "Peter Palaga", "ppalaga@redhat.com"); - } + Map props = new HashMap<>(); + final LicenseCheckMojo mojo = new LicenseCheckMojo(); + mojo.defaultBasedir = gitRepoRoot.toFile(); + + try { + provider.init(mojo, props); + + String path = "dir1/file1.txt"; - private void assertAuthor(CopyrightAuthorProvider provider, String path, String copyrightAuthorName, String copyrightAuthorEmail) { - Properties props = new Properties(); + Document document = newDocument(path); + Map actual = provider.adjustProperties(mojo, props, document); - Document document = newDocument(path); - Map actual = provider.getAdditionalProperties(new LicenseCheckMojo(), props, document); + HashMap expected = new HashMap(); + expected.put(CopyrightAuthorProvider.COPYRIGHT_CREATION_AUTHOR_NAME_KEY, "Peter Palaga"); + expected.put(CopyrightAuthorProvider.COPYRIGHT_CREATION_AUTHOR_EMAIL_KEY, + "ppalaga@redhat.com"); + Assertions.assertEquals(expected, actual, "for file '" + path + "': "); + + } finally { + provider.close(); + } + } - HashMap expected = new HashMap(); - expected.put(CopyrightAuthorProvider.COPYRIGHT_CREATION_AUTHOR_NAME_KEY, copyrightAuthorName); - expected.put(CopyrightAuthorProvider.COPYRIGHT_CREATION_AUTHOR_EMAIL_KEY, copyrightAuthorEmail); - Assertions.assertEquals(expected, actual, "for file '" + path + "': "); + private void assertAuthor(CopyrightAuthorProvider provider, String path, + String copyrightAuthorName, String copyrightAuthorEmail) { } diff --git a/license-maven-plugin-git/src/test/java/com/mycila/maven/plugin/license/git/CopyrightRangeProviderTest.java b/license-maven-plugin-git/src/test/java/com/mycila/maven/plugin/license/git/CopyrightRangeProviderTest.java index 8627f110f..dfade0903 100644 --- a/license-maven-plugin-git/src/test/java/com/mycila/maven/plugin/license/git/CopyrightRangeProviderTest.java +++ b/license-maven-plugin-git/src/test/java/com/mycila/maven/plugin/license/git/CopyrightRangeProviderTest.java @@ -24,7 +24,6 @@ import java.nio.file.Paths; import java.util.HashMap; import java.util.Map; -import java.util.Properties; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; @@ -44,19 +43,28 @@ class CopyrightRangeProviderTest { void copyrightRange() { CopyrightRangeProvider provider = new CopyrightRangeProvider(); - assertRange(provider, "dir1/file1.txt", "2000", "2006", "1999-2006", "2000-2006"); - assertRange(provider, "dir2/file2.txt", "2007", "2007", "1999-2007", "2007"); - assertRange(provider, "dir1/file3.txt", "2009", "2009", "1999-2009", "2009"); - assertRange(provider, "dir2/file4.txt", "1999", "1999", "1999", "1999"); - - /* The last change of file4.txt in git history is in 1999 - * but the inception year is 2000 - * and we do not want the range to go back (2000-1999) - * so in this case we expect just 2000 - * However for existence years always report the actual year regardless - * of the inception year so expect 1999 for that */ - assertRange(provider, "dir2/file4.txt", "2000", "1999", "1999", "2000", "1999"); - + Map props = new HashMap<>(); + final LicenseCheckMojo mojo = new LicenseCheckMojo(); + mojo.defaultBasedir = gitRepoRoot.toFile(); + try { + provider.init(mojo, props); + + assertRange(provider, "dir1/file1.txt", "2000", "2006", "1999-2006", "2000-2006"); + assertRange(provider, "dir2/file2.txt", "2007", "2007", "1999-2007", "2007"); + assertRange(provider, "dir1/file3.txt", "2009", "2009", "1999-2009", "2009"); + assertRange(provider, "dir2/file4.txt", "1999", "1999", "1999", "1999"); + + /* The last change of file4.txt in git history is in 1999 + * but the inception year is 2000 + * and we do not want the range to go back (2000-1999) + * so in this case we expect just 2000 + * However for existence years always report the actual year regardless + * of the inception year so expect 1999 for that */ + assertRange(provider, "dir2/file4.txt", "2000", "1999", "1999", "2000", "1999"); + + } finally { + provider.close(); + } } private void assertRange(CopyrightRangeProvider provider, String path, String copyrightStart, String copyrightEnd, String copyrightRange, String copyrightExistence) { @@ -65,11 +73,11 @@ private void assertRange(CopyrightRangeProvider provider, String path, String co private void assertRange(CopyrightRangeProvider provider, String path, String inceptionYear, String copyrightStart, String copyrightEnd, String copyrightRange, String copyrightExistence) { - Properties props = new Properties(); + Map props = new HashMap<>(); props.put(CopyrightRangeProvider.INCEPTION_YEAR_KEY, inceptionYear); Document document = newDocument(path); - Map actual = provider.getAdditionalProperties(new LicenseCheckMojo(), props, document); + Map actual = provider.adjustProperties(new LicenseCheckMojo(), props, document); HashMap expected = new HashMap(); expected.put(CopyrightRangeProvider.COPYRIGHT_CREATION_YEAR_KEY, copyrightStart); diff --git a/license-maven-plugin-git/src/test/java/com/mycila/maven/plugin/license/git/GitLookupTest.java b/license-maven-plugin-git/src/test/java/com/mycila/maven/plugin/license/git/GitLookupTest.java index b85525f5e..55e5e520b 100644 --- a/license-maven-plugin-git/src/test/java/com/mycila/maven/plugin/license/git/GitLookupTest.java +++ b/license-maven-plugin-git/src/test/java/com/mycila/maven/plugin/license/git/GitLookupTest.java @@ -26,6 +26,8 @@ import java.nio.file.Path; import java.nio.file.Paths; import java.util.Calendar; +import java.util.HashMap; +import java.util.Map; import java.util.TimeZone; import java.util.zip.ZipEntry; import java.util.zip.ZipInputStream; @@ -155,10 +157,11 @@ void reuseProvider() throws GitAPIException, IOException { @Test void timezone() throws GitAPIException, IOException { try { - new GitLookup(gitRepoRoot.toFile(), DateSource.AUTHOR, TimeZone.getTimeZone("GMT"), 10); + GitLookup.create(gitRepoRoot.toFile(), buildProps(DateSource.AUTHOR, "GMT", "10")); Assertions.fail("RuntimeException expected"); } catch (RuntimeException e) { - if (e.getMessage().startsWith("Time zone must be null with dateSource " + DateSource.AUTHOR.name() + "")) { + if (e.getMessage().contains( + "license.git.copyrightLastYearTimeZone must not be set with license.git.copyrightLastYearSource = AUTHOR because git author name already contains time zone information.")) { /* expected */ } else { throw e; @@ -166,28 +169,45 @@ void timezone() throws GitAPIException, IOException { } /* null is GMT */ - GitLookup nullTzLookup = new GitLookup(gitRepoRoot.toFile(), DateSource.COMMITER, null, 10); + GitLookup nullTzLookup = GitLookup.create(gitRepoRoot.toFile(), + buildProps(DateSource.COMMITER, null, "10")); assertLastChange(nullTzLookup, "dir1/file3.txt", 2010); /* explicit GMT */ - GitLookup gmtLookup = new GitLookup(gitRepoRoot.toFile(), DateSource.COMMITER, TimeZone.getTimeZone("GMT"), 10); + GitLookup gmtLookup = GitLookup.create(gitRepoRoot.toFile(), + buildProps(DateSource.COMMITER, "GMT", "10")); assertLastChange(gmtLookup, "dir1/file3.txt", 2010); /* * explicit non-GMT zome. Note that the relevant commit's (GMT) time stamp is 2010-12-31T23:30:00 which yealds * 2011 in the CET (+01:00) time zone */ - GitLookup cetLookup = new GitLookup(gitRepoRoot.toFile(), DateSource.COMMITER, TimeZone.getTimeZone("CET"), 10); + GitLookup cetLookup = GitLookup.create(gitRepoRoot.toFile(), + buildProps(DateSource.COMMITER, "CET", "10")); assertLastChange(cetLookup, "dir1/file3.txt", 2011); } - private GitLookup newAuthorLookup() throws IOException { - return new GitLookup(gitRepoRoot.toFile(), DateSource.AUTHOR, null, 10); + private Map buildProps(DateSource ds, String tz, String history) { + Map props = new HashMap<>(); + if (history != null) { + props.put(GitLookup.MAX_COMMITS_LOOKUP_KEY, history); + } + if (tz != null) { + props.put(GitLookup.COPYRIGHT_LAST_YEAR_TIME_ZONE_KEY, tz); + } + if (ds != null) { + props.put(GitLookup.COPYRIGHT_LAST_YEAR_SOURCE_KEY, ds.name()); + } + return props; + } + + private GitLookup newAuthorLookup() { + return GitLookup.create(gitRepoRoot.toFile(), buildProps(DateSource.AUTHOR, null, "10")); } - private GitLookup newCommitterLookup() throws IOException { - return new GitLookup(gitRepoRoot.toFile(), DateSource.COMMITER, null, 10); + private GitLookup newCommitterLookup() { + return GitLookup.create(gitRepoRoot.toFile(), buildProps(DateSource.COMMITER, null, "10")); } private void assertLastChange(GitLookup provider, String relativePath, int expected) throws diff --git a/license-maven-plugin-svn/src/main/java/com/mycila/maven/plugin/license/svn/SVNPropertiesProvider.java b/license-maven-plugin-svn/src/main/java/com/mycila/maven/plugin/license/svn/SVNPropertiesProvider.java index 39b697a32..4df1a0313 100755 --- a/license-maven-plugin-svn/src/main/java/com/mycila/maven/plugin/license/svn/SVNPropertiesProvider.java +++ b/license-maven-plugin-svn/src/main/java/com/mycila/maven/plugin/license/svn/SVNPropertiesProvider.java @@ -24,7 +24,9 @@ import java.util.GregorianCalendar; import java.util.HashMap; import java.util.Map; -import java.util.Properties; +import java.util.Queue; +import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.concurrent.atomic.AtomicBoolean; import org.tmatesoft.svn.core.ISVNLogEntryHandler; import org.tmatesoft.svn.core.SVNDepth; import org.tmatesoft.svn.core.SVNException; @@ -41,46 +43,60 @@ * @author Matthieu Brouillard */ public class SVNPropertiesProvider implements PropertiesProvider { - ThreadLocal svnClientThreadLocal = new ThreadLocal<>(); - ThreadLocal sdfTimestampThreadLocal = new ThreadLocal() { - @Override - protected SimpleDateFormat initialValue() { - return new SimpleDateFormat("yyyyMMdd-HH:mm:ss"); - } - }; + public static final String SVN_COPYRIGHT_LASTCHANGE_YEAR_KEY = "license.svn.lastchange.year"; public static final String SVN_COPYRIGHT_LASTCHANGE_DATE_KEY = "license.svn.lastchange.date"; public static final String SVN_COPYRIGHT_LASTCHANGE_TIMESTAMP_KEY = "license.svn.lastchange.timestamp"; public static final String SVN_COPYRIGHT_LASTCHANGE_REVISION_KEY = "license.svn.lastchange.revision"; public static final String SVN_COPYRIGHT_YEARS_RANGE_KEY = "license.svn.years.range"; - public static final String INCEPTION_YEAR_KEY = "project.inceptionYear"; - public static final String SVN_SERVER_ID_PLUGIN_KEY = "license.svn.serverId"; - private volatile boolean initialized = false; + private Credentials svnCredentials; + + private final AtomicBoolean warnedIfShallow = new AtomicBoolean(); + private final Queue clients = new ConcurrentLinkedQueue<>(); + private final ThreadLocal sdfTimestampThreadLocal = ThreadLocal.withInitial( + () -> new SimpleDateFormat("yyyyMMdd-HH:mm:ss")); + private final ThreadLocal svnClientThreadLocal = ThreadLocal.withInitial(() -> { + SVNClientManager svnClientManager = svnCredentials == null ? + SVNClientManager.newInstance(new DefaultSVNOptions()) : + SVNClientManager.newInstance(new DefaultSVNOptions(), svnCredentials.getLogin(), + svnCredentials.getPassword()); + clients.offer(svnClientManager); + return svnClientManager; + }); + + @Override + public void init(AbstractLicenseMojo mojo, Map currentProperties) { + svnCredentials = mojo.findCredentials(currentProperties.get(SVN_SERVER_ID_PLUGIN_KEY)); + } + + @Override + public void close() { + while (!clients.isEmpty()) { + clients.poll().dispose(); + } + } /** - * Provides information on the given document. The information is put in the - * returned map using: SVN_COPYRIGHT_LAST_YEAR_KEY the year of the latest - * change detected for the given document file. + * Provides information on the given document. The information is put in the returned map using: + * SVN_COPYRIGHT_LAST_YEAR_KEY the year of the latest change detected for the given document + * file. * * @param mojo the current license maven plugin * @param currentProperties the default properties (without any plugin contributions) - * @param document the document corresponding to the file for which we want to add properties + * @param document the document corresponding to the file for which we want to add + * properties * @return a non null Map containing the added entries */ @Override - public Map getAdditionalProperties(final AbstractLicenseMojo mojo, Properties currentProperties, Document document) { + public Map adjustProperties(final AbstractLicenseMojo mojo, + Map currentProperties, Document document) { final Map newProperties = new HashMap<>(); final File documentFile = document.getFile(); - - initThreadLocalObjects(mojo, currentProperties.getProperty(SVN_SERVER_ID_PLUGIN_KEY)); - - SVNClientManager clientManager = svnClientThreadLocal.get(); - - final String inceptionYear = currentProperties.getProperty(INCEPTION_YEAR_KEY); + final SVNClientManager svnClientManager = svnClientThreadLocal.get(); ISVNLogEntryHandler lastChangeDateLogEntryHandler = new ISVNLogEntryHandler() { @Override @@ -90,6 +106,7 @@ public void handleLogEntry(SVNLogEntry logEntry) throws SVNException { final String timestamp = sdfTimestampThreadLocal.get().format(logEntry.getDate()); final String year = timestamp.substring(0, 4); + final String inceptionYear = currentProperties.get(INCEPTION_YEAR_KEY); newProperties.put(SVN_COPYRIGHT_LASTCHANGE_TIMESTAMP_KEY, timestamp); newProperties.put(SVN_COPYRIGHT_LASTCHANGE_DATE_KEY, timestamp.substring(0, 8)); @@ -97,6 +114,7 @@ public void handleLogEntry(SVNLogEntry logEntry) throws SVNException { newProperties.put(SVN_COPYRIGHT_LASTCHANGE_YEAR_KEY, year); mojo.getLog().debug("found " + logEntry.getDate() + " as last modified date for file: " + documentFile); + if (year.equals(inceptionYear) || inceptionYear == null) { newProperties.put(SVN_COPYRIGHT_YEARS_RANGE_KEY, year); } else { @@ -107,21 +125,20 @@ public void handleLogEntry(SVNLogEntry logEntry) throws SVNException { }; try { - if (!this.initialized) { - synchronized (this) { - if (!this.initialized) { - this.initialized = true; - // One-time warning for shallow repo - if (mojo.warnIfShallow) { - SVNInfo info = clientManager.getWCClient().doInfo(documentFile, SVNRevision.HEAD); - if (info.getDepth() != SVNDepth.INFINITY) { - mojo.warn("Sparse svn repository detected. Year and author property values may not be accurate."); - } - } + // One-time warning for shallow repo + if (mojo.warnIfShallow && !warnedIfShallow.get()) { + SVNInfo info = svnClientManager.getWCClient().doInfo(documentFile, SVNRevision.HEAD); + if (info.getDepth() != SVNDepth.INFINITY) { + if (warnedIfShallow.compareAndSet(false, true)) { + mojo.warn( + "Sparse svn repository detected. Year and author property values may not be accurate."); } } } - clientManager.getLogClient().doLog(new File[]{documentFile}, SVNRevision.HEAD, SVNRevision.create(0), true, true, 1, lastChangeDateLogEntryHandler); + + svnClientManager.getLogClient() + .doLog(new File[]{documentFile}, SVNRevision.HEAD, SVNRevision.create(0), true, true, 1, + lastChangeDateLogEntryHandler); } catch (SVNException ex) { IllegalStateException ise = new IllegalStateException("cannot query SVN latest date information for file: " + documentFile, ex); throw ise; @@ -129,23 +146,4 @@ public void handleLogEntry(SVNLogEntry logEntry) throws SVNException { return newProperties; } - - private void setSVNClientManager(AbstractLicenseMojo mojo, String svnServerID) { - SVNClientManager c = svnClientThreadLocal.get(); - if (c == null) { - Credentials svnCredentials = mojo.findCredentials(svnServerID); - - if (svnCredentials == null) { - c = SVNClientManager.newInstance(new DefaultSVNOptions()); - } else { - c = SVNClientManager.newInstance(new DefaultSVNOptions(), svnCredentials.getLogin(), svnCredentials.getPassword()); - } - - svnClientThreadLocal.set(c); - } - } - - private void initThreadLocalObjects(AbstractLicenseMojo mojo, String serverID) { - setSVNClientManager(mojo, serverID); - } } diff --git a/license-maven-plugin/src/main/java/com/mycila/maven/plugin/license/AbstractLicenseMojo.java b/license-maven-plugin/src/main/java/com/mycila/maven/plugin/license/AbstractLicenseMojo.java index b38553c89..6a340ee9f 100755 --- a/license-maven-plugin/src/main/java/com/mycila/maven/plugin/license/AbstractLicenseMojo.java +++ b/license-maven-plugin/src/main/java/com/mycila/maven/plugin/license/AbstractLicenseMojo.java @@ -41,20 +41,23 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; +import java.util.Collections; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; -import java.util.Properties; +import java.util.Objects; import java.util.ServiceLoader; import java.util.Set; +import java.util.TreeMap; import java.util.concurrent.CompletionService; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorCompletionService; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; +import java.util.stream.Collectors; import org.apache.maven.artifact.DependencyResolutionRequiredException; import org.apache.maven.execution.MavenSession; import org.apache.maven.model.Organization; @@ -303,7 +306,7 @@ public abstract class AbstractLicenseMojo extends AbstractMojo { */ @Parameter(property = "license.warnIfShallow", defaultValue = "true") public boolean warnIfShallow = true; - + /** * If you do not want to see the list of file having a missing header, you * can add the quiet flag that will shorten the output @@ -583,60 +586,92 @@ private void executeForLicenseSet(final LicenseSet licenseSet, final Callback ca } final List

    validHeaders = new ArrayList
    (licenseSet.validHeaders.length); for (final String validHeader : licenseSet.validHeaders) { - final HeaderSource validHeaderSource = HeaderSource.of(null, null, validHeader, this.encoding, finder); + final HeaderSource validHeaderSource = HeaderSource.of(null, null, validHeader, this.encoding, + finder); validHeaders.add(new Header(validHeaderSource, licenseSet.headerSections)); } - final List propertiesProviders = new LinkedList(); - for (final PropertiesProvider provider : ServiceLoader.load(PropertiesProvider.class, Thread.currentThread().getContextClassLoader())) { - propertiesProviders.add(provider); - } - final DocumentPropertiesLoader propertiesLoader = new DocumentPropertiesLoader() { - @Override - public Properties load(final Document document) { - final Properties props = new Properties(); + Map globalProperties = getDefaultProperties(); - for (final Map.Entry entry : mergeProperties(licenseSet, document).entrySet()) { - if (entry.getValue() != null) { - props.setProperty(entry.getKey(), entry.getValue()); - } else { - props.remove(entry.getKey()); - } - } - for (final PropertiesProvider provider : propertiesProviders) { - try { - final Map providerProperties = provider.getAdditionalProperties(AbstractLicenseMojo.this, props, document); - if (getLog().isDebugEnabled()) { - getLog().debug("provider: " + provider.getClass() + " brought new properties\n" + providerProperties); - } - for (Map.Entry entry : providerProperties.entrySet()) { - if (entry.getValue() != null) { - props.setProperty(entry.getKey(), entry.getValue()); - } else { - props.remove(entry.getKey()); - } - } - } catch (Exception e) { - getLog().warn("failure occurred while calling " + provider.getClass(), e); - } + // we override by properties in the licenseSet + if (licenseSet.properties != null) { + for (Map.Entry entry : licenseSet.properties.entrySet()) { + if (!System.getProperties().contains(entry.getKey())) { + globalProperties.put(entry.getKey(), entry.getValue()); } - return props; } - }; + } - final DocumentFactory documentFactory = new DocumentFactory(firstNonNull(licenseSet.basedir, defaultBasedir), buildMapping(), buildHeaderDefinitions(licenseSet, finder), encoding, licenseSet.keywords, propertiesLoader); + if (getLog().isDebugEnabled()) { + getLog().debug( + "global properties:\n - " + globalProperties.entrySet().stream().map(Objects::toString) + .collect(Collectors.joining("\n - "))); + } + final List propertiesProviders = new LinkedList<>(); int nThreads = getNumberOfExecutorThreads(); ExecutorService executorService = Executors.newFixedThreadPool(nThreads); - CompletionService completionService = new ExecutorCompletionService<>(executorService); - int count = 0; - debug("Number of execution threads: %s", nThreads); try { + + for (final PropertiesProvider provider : ServiceLoader.load(PropertiesProvider.class, + Thread.currentThread().getContextClassLoader())) { + provider.init(this, globalProperties); + propertiesProviders.add(provider); + } + + final DocumentPropertiesLoader perDocumentProperties = new DocumentPropertiesLoader() { + @Override + public Map load(final Document document) { + // then add per document properties + Map perDoc = new LinkedHashMap<>(globalProperties); + perDoc.put("file.name", document.getFile().getName()); + + Map readOnly = Collections.unmodifiableMap(perDoc); + + for (final PropertiesProvider provider : propertiesProviders) { + try { + final Map adjustments = provider.adjustProperties( + AbstractLicenseMojo.this, readOnly, document); + if (getLog().isDebugEnabled()) { + getLog().debug("provider: " + provider.getClass() + " adjusted these properties:\n" + + adjustments); + } + for (Map.Entry entry : adjustments.entrySet()) { + if (entry.getValue() != null) { + perDoc.put(entry.getKey(), entry.getValue()); + } else { + perDoc.remove(entry.getKey()); + } + } + } catch (Exception e) { + getLog().warn("failure occurred while calling " + provider.getClass(), e); + } + } + + if (getLog().isDebugEnabled()) { + getLog().debug("properties for " + document + ":\n - " + perDoc.entrySet().stream() + .map(Objects::toString).collect(Collectors.joining("\n - "))); + } + + return perDoc; + } + }; + + final DocumentFactory documentFactory = new DocumentFactory( + firstNonNull(licenseSet.basedir, defaultBasedir), buildMapping(), + buildHeaderDefinitions(licenseSet, finder), encoding, licenseSet.keywords, + perDocumentProperties); + + CompletionService completionService = new ExecutorCompletionService<>(executorService); + int count = 0; + debug("Number of execution threads: %s", nThreads); + for (final String file : listSelectedFiles(licenseSet)) { completionService.submit(() -> { Document document = documentFactory.createDocuments(file); - debug("Selected file: %s [header style: %s]", document.getFilePath(), document.getHeaderDefinition()); + debug("Selected file: %s [header style: %s]", document.getFilePath(), + document.getHeaderDefinition()); if (document.isNotSupported()) { callback.onUnknownFile(document, h); } else if (document.is(h)) { @@ -685,6 +720,7 @@ public Properties load(final Document document) { } finally { executorService.shutdownNow(); + propertiesProviders.forEach(PropertiesProvider::close); } } @@ -702,9 +738,10 @@ private int getNumberOfExecutorThreads() { Math.max(1, (int) (Runtime.getRuntime().availableProcessors() * concurrencyFactor)); } - private Map mergeProperties(final LicenseSet licenseSet, final Document document) { + private Map getDefaultProperties() { // first put system environment - Map props = new LinkedHashMap(System.getenv()); + Map props = new TreeMap<>( + System.getenv()); // treemap just to have nice debug logs // then add ${project.XYZ} properties props.put("project.groupId", project.getGroupId()); props.put("project.artifactId", project.getArtifactId()); @@ -720,23 +757,17 @@ private Map mergeProperties(final LicenseSet licenseSet, final D props.put("project.organization.name", org.getName()); props.put("project.organization.url", org.getUrl()); } - // then add per document properties - props.put("file.name", document.getFile().getName()); // we override by properties in the POM if (this.defaultProperties != null) { props.putAll(this.defaultProperties); } - // we override by properties in the licenseSet - if (licenseSet.properties != null) { - props.putAll(licenseSet.properties); - } - // then we override by java system properties (command-line -D...) for (String key : System.getProperties().stringPropertyNames()) { props.put(key, System.getProperty(key)); } + return props; } @@ -858,11 +889,17 @@ List getDecryptedServers() { * @return */ public Credentials findCredentials(String serverID) { + if (serverID == null) { + return null; + } + List decryptedServers = getDecryptedServers(); for (Server ds : decryptedServers) { if (ds.getId().equals(serverID)) { - getLog().debug("credentials have been found for server: " + serverID + ", login:" + ds.getUsername() + ", password:" + starEncrypt(ds.getPassword())); + getLog().debug( + "credentials have been found for server: " + serverID + ", login:" + ds.getUsername() + + ", password:" + starEncrypt(ds.getPassword())); return new Credentials(ds.getUsername(), ds.getPassword()); } } diff --git a/license-maven-plugin/src/main/java/com/mycila/maven/plugin/license/PropertiesProvider.java b/license-maven-plugin/src/main/java/com/mycila/maven/plugin/license/PropertiesProvider.java index 833784376..67d3737b6 100755 --- a/license-maven-plugin/src/main/java/com/mycila/maven/plugin/license/PropertiesProvider.java +++ b/license-maven-plugin/src/main/java/com/mycila/maven/plugin/license/PropertiesProvider.java @@ -16,13 +16,36 @@ package com.mycila.maven.plugin.license; import com.mycila.maven.plugin.license.document.Document; +import java.io.Closeable; +import java.util.Collections; import java.util.Map; import java.util.Properties; /** - * @author Mathieu Carbou (mathieu.carbou@gmail.com) - * 2013-08-27 + * @author Mathieu Carbou (mathieu.carbou@gmail.com) 2013-08-27 */ -public interface PropertiesProvider { - Map getAdditionalProperties(AbstractLicenseMojo mojo, Properties currentProperties, Document document); +public interface PropertiesProvider extends Closeable { + + default void init(AbstractLicenseMojo mojo, Map currentProperties) { + } + + default Map adjustProperties(AbstractLicenseMojo mojo, + Map currentProperties, Document document) { + Properties properties = new Properties(); + properties.putAll(currentProperties); + return getAdditionalProperties(mojo, properties, document); + } + + /** + * @deprecated Use instead {@link #adjustProperties(AbstractLicenseMojo, Map, Document)} + */ + @Deprecated + default Map getAdditionalProperties(AbstractLicenseMojo mojo, + Properties currentProperties, Document document) { + return Collections.emptyMap(); + } + + @Override + default void close() { + } } diff --git a/license-maven-plugin/src/main/java/com/mycila/maven/plugin/license/document/DocumentPropertiesLoader.java b/license-maven-plugin/src/main/java/com/mycila/maven/plugin/license/document/DocumentPropertiesLoader.java index fe47cfaa2..97bfcebc2 100755 --- a/license-maven-plugin/src/main/java/com/mycila/maven/plugin/license/document/DocumentPropertiesLoader.java +++ b/license-maven-plugin/src/main/java/com/mycila/maven/plugin/license/document/DocumentPropertiesLoader.java @@ -15,12 +15,13 @@ */ package com.mycila.maven.plugin.license.document; -import java.util.Properties; +import java.util.Map; /** * @author Mathieu Carbou (mathieu.carbou@gmail.com) * 2013-08-27 */ public interface DocumentPropertiesLoader { - Properties load(Document d); + + Map load(Document d); } diff --git a/license-maven-plugin/src/main/java/com/mycila/maven/plugin/license/document/PropertyPlaceholderResolver.java b/license-maven-plugin/src/main/java/com/mycila/maven/plugin/license/document/PropertyPlaceholderResolver.java index d06c55bed..c802ea145 100644 --- a/license-maven-plugin/src/main/java/com/mycila/maven/plugin/license/document/PropertyPlaceholderResolver.java +++ b/license-maven-plugin/src/main/java/com/mycila/maven/plugin/license/document/PropertyPlaceholderResolver.java @@ -16,6 +16,7 @@ package com.mycila.maven.plugin.license.document; import java.util.HashSet; +import java.util.Map; import java.util.Properties; import java.util.Set; import java.util.function.Function; @@ -38,15 +39,16 @@ class PropertyPlaceholderResolver { private final String placeholderPrefix = "${"; private final String placeholderSuffix = "}"; - public String replacePlaceholders(String value, final Properties properties) { - return replacePlaceholders(value, properties::getProperty); + public String replacePlaceholders(String value, final Map properties) { + return replacePlaceholders(value, properties::get); } private String replacePlaceholders(String value, Function placeholderResolver) { return parseStringValue(value, placeholderResolver, new HashSet<>()); } - private String parseStringValue(String value, Function placeholderResolver, Set visitedPlaceholders) { + private String parseStringValue(String value, Function placeholderResolver, + Set visitedPlaceholders) { StringBuilder result = new StringBuilder(value); int startIndex = value.indexOf(this.placeholderPrefix); while (startIndex != -1) { diff --git a/license-maven-plugin/src/test/java/MyPropertiesProvider.java b/license-maven-plugin/src/test/java/MyPropertiesProvider.java index 0cd8ca2ef..469d728fa 100755 --- a/license-maven-plugin/src/test/java/MyPropertiesProvider.java +++ b/license-maven-plugin/src/test/java/MyPropertiesProvider.java @@ -3,15 +3,23 @@ import com.mycila.maven.plugin.license.document.Document; import java.util.HashMap; import java.util.Map; -import java.util.Properties; /** - * @author Mathieu Carbou (mathieu.carbou@gmail.com) - * 2013-08-27 + * @author Mathieu Carbou (mathieu.carbou@gmail.com) 2013-08-27 */ public final class MyPropertiesProvider implements PropertiesProvider { + + @Override + public void init(AbstractLicenseMojo mojo, Map currentProperties) { + } + + @Override + public void close() { + } + @Override - public Map getAdditionalProperties(AbstractLicenseMojo mojo, Properties currentProperties, Document document) { + public Map adjustProperties(AbstractLicenseMojo mojo, + Map currentProperties, Document document) { Map map = new HashMap(); map.put("my-custom-property", "my-custom-value"); return map; diff --git a/license-maven-plugin/src/test/java/com/mycila/maven/plugin/license/document/DocumentTest.java b/license-maven-plugin/src/test/java/com/mycila/maven/plugin/license/document/DocumentTest.java index 44e9d2a97..292548813 100755 --- a/license-maven-plugin/src/test/java/com/mycila/maven/plugin/license/document/DocumentTest.java +++ b/license-maven-plugin/src/test/java/com/mycila/maven/plugin/license/document/DocumentTest.java @@ -20,7 +20,8 @@ import com.mycila.maven.plugin.license.util.FileUtils; import java.io.File; import java.io.IOException; -import java.util.Properties; +import java.util.HashMap; +import java.util.Map; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; @@ -33,8 +34,8 @@ class DocumentTest { static Header header; static DocumentPropertiesLoader loader = new DocumentPropertiesLoader() { @Override - public Properties load(Document d) { - Properties props = new Properties(); + public Map load(Document d) { + Map props = new HashMap<>(); props.put("year", "2008"); return props; }