| // Copyright (C) 2019 The Android Open Source Project |
| // |
| // 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.googlesource.gerrit.plugins.copyright.lib; |
| |
| import com.google.common.annotations.VisibleForTesting; |
| import com.google.common.base.Joiner; |
| import com.google.common.collect.ImmutableList; |
| import com.google.common.collect.ImmutableMap; |
| import java.util.NoSuchElementException; |
| |
| /** Constants declaring match patterns for common copyright licenses and owners. */ |
| public abstract class CopyrightPatterns { |
| |
| // No instances |
| private CopyrightPatterns() {} |
| |
| // All of the MAX parameters below have been chosen empirically similar to MATCH_SEARCH_LENGTH to |
| // minimize computing cost while still catching virtually all of the important matches. |
| |
| /** Maximum length of consecutive text characters to match. */ |
| public static final int MAX_NAME_LENGTH = 30; |
| /** Maximum number of potential names to match. */ |
| public static final int MAX_NAME_REPETITION = 35; |
| /** Maximum length of consecutive space/comment characters to match. */ |
| public static final int MAX_SPACE_LENGTH = 47; |
| /** Maximum repetition of potential dates to match. Might have to revisit this in future. */ |
| public static final int MAX_DATE_REPETITION = 30; |
| |
| /** Regular expression matching whitespace or a comment character. */ |
| public static final String WS = "[\\s*/#]"; |
| /** Regular expression matching whitespace, a comment character, or punctuation. */ |
| public static final String WSPCT = "[-,;.\\s*/#]"; |
| /** Regular expression matching a text character. */ |
| public static final String NAME_CHAR = "[-\\p{L}\\p{N}]"; // \p{L}->letter, \p{N}->numeral |
| /** Regular expression matching an UPPER CASE text character. */ |
| public static final String UPPER_CHAR = "\\p{Lu}"; |
| /** Regular expression matching a lower case text character. */ |
| public static final String LOWER_CHAR = "\\p{Ll}"; |
| /** Regular expression matching an email character. */ |
| public static final String EMAIL_CHAR = "[-.\\p{L}\\p{N}_]"; |
| /** Regular expression matching a URL character. */ |
| public static final String URL_CHAR = "[-.\\p{L}\\p{N}_=%+]"; |
| /** Regular experssion matching a web address. */ |
| public static final String URL = |
| "https?[:]/(?:[/?&]" // http://example.com/path/?var=val&var=val |
| + URL_CHAR |
| + "{1," |
| + MAX_NAME_LENGTH |
| + "}){1,25}" |
| + "|www[.]" // www.domain or www.domain/path |
| + URL_CHAR |
| + "{1," |
| + MAX_NAME_LENGTH |
| + "}(?:[.]com|[.]net|[.]org|[.]\\p{L}\\p{L})(?:[/?&#]" |
| + URL_CHAR |
| + "{0," |
| + MAX_NAME_LENGTH |
| + "}){0,25}"; |
| /** Regular expression matching a text or email address. */ |
| public static final String NAME = |
| "(?:(?:" |
| + URL // web address |
| + "|[\\p{L}\\p{N}]" // regular text |
| + NAME_CHAR |
| + "{0,mnl}\\b" |
| + "|[<]?[\\p{L}\\p{N}]" // email@domain or <email@domain> |
| + EMAIL_CHAR |
| + "{1,mnl}[@][\\p{L}\\p{N}]" |
| + EMAIL_CHAR |
| + "{1,mnl}\\b[>]?" |
| + "|\\b\\p{N}{1,2}(?:[.]\\p{N}{1,2}){1,5}\\b" // version number |
| + "|\\p{Pi}[^\\p{Pf}]{0,65}\\p{Pf}" // quoted string |
| + "|(?-i:\\p{Lu}[-.]){1,5}" // Initials A.G. or S.A. etc. \\p{Lu} -> uppercase letter |
| + "|" // domain text |
| + EMAIL_CHAR |
| + "{1,mnl}(?:[.]com|[.]org|[.]net|[.]\\p{L}\\p{L})" |
| + ")[,;:]?)"; // punctuation following text |
| /** Regular expression matching an UPPERCASE text. */ |
| public static final String UPPER_NAME = "(?-i:\\b" + UPPER_CHAR + "{1," + MAX_NAME_LENGTH + "})"; |
| /** Regular expression matching a Proper Case text. */ |
| public static final String PROPER_NAME = |
| "(?-i:\\b" + UPPER_CHAR + LOWER_CHAR + "{0," + MAX_NAME_LENGTH + "})"; |
| /** Regular expression matching any text, email address, or quote character. */ |
| public static final String ANY_CHAR = "[-.,\\p{L}\\p{N}]"; |
| /** Regular expression matching any text, email address, or quoted string. */ |
| public static final String ANY_WORD = "(?:" + ANY_CHAR + "{1," + MAX_NAME_LENGTH + "})"; |
| |
| /** Affero General Public License */ |
| public static final Rule AGPL = license(ImmutableList.of("Affero")); |
| |
| /** Android owned or licensed */ |
| public static final Rule ANDROID = |
| new Rule( |
| ImmutableList.of("Android(?:-x86)? Open(?: |-)Source Project", "LK Trusty Authors"), |
| ImmutableList.of("Android Software Development Kit Licen[cs]e Agreement")); |
| |
| /** Apache 2 owned or licensed */ |
| public static final Rule APACHE2 = |
| new Rule( |
| ImmutableList.of( |
| ".*SPDX-License-Identifier: Apache-2.0", |
| "(?:by )?(?:The )?Apache Software Foundation.?", |
| "Apache Software Foundation.?" |
| + " This product includes software developed" |
| + " (?:by|at) The Apache Software Foundation"), |
| ImmutableList.of( |
| "http://www[.]apache[.]org/licenses/LICENSE-2[.]0", |
| "Apache 2[.]0 Licen[cs]e", |
| ".*Licen[cs]ed under (?:both )?(?:the )?Apache Licen[cs]e,?(?: version 2[.]?0?)?", |
| ".+Licen[cs]ed under (?:both )?(?:the )?Apache Licen[cs]e v2[.]?(?:[\\p{L}\\p{N}]+)?", |
| ".+licen[cs]ed under (?:the )?Apache 2.?", |
| ".+licen[cs]es this file to you under (?:the )?Apache Licen[cs]e,?", |
| "Apache Licen[cs]e Version 2[.]0", |
| "^apache2(?:-android)?", |
| "^the apache licen[cs]e", |
| "^terms of the Apache 2 licen[cs]e", |
| ".+under the terms of (?:either )the Apache Licen[cs]e[,.;]?"), |
| ImmutableList.of("owner as \\p{Pi}?Not a Contribution[.,;:]{0,3}\\p{Pf}?")); |
| |
| /** The BEER-WARE License */ |
| public static final Rule BEER_WARE = license(ImmutableList.of("\\bTHE BEER-WARE LICEN[CS]E")); |
| |
| /** BSD licensed */ |
| public static final Rule BSD = |
| license( |
| ImmutableList.of( |
| ".*SPDX-License-Identifier: BSD-2-Clause", |
| ".*SPDX-License-Identifier: BSD-2-Clause-FreeBSD", |
| ".*SPDX-License-Identifier: BSD-3-Clause", |
| ".*SPDX-License-Identifier: BSD-4-Clause", |
| "^BSD(?:[.]|, see LICEN[CS]E for (?:more )details[.])?", |
| ".*under the terms and conditions of the BSD Licen[cs]e.*", |
| ".*(?:\\p{N}-clause |a )?BSD (?:\\p{N}-clause )?licen[cs]e.*", |
| ".*Redistribution and use in source and binary forms,? with or without modification,?" |
| + " are permitted provided that the following conditions are met[:]?", |
| ".*This header is BSD licen[cs]ed so anyone can use the definitions to implement" |
| + " compatible drivers servers[.:]?.*", |
| ".*Redistribution and use is allowed according to the terms of the" |
| + " (?:\\p{N}-clause )?BSD licen[cs]e[.:]?.*", |
| ".*(?:[-\\p{L}\\p{N}] )?redistributions (?:of|in) source code must retain the" |
| + " (?:(?:above|accompanying) )?copyright notice(?: unmodified)?[,.:;]? this list" |
| + " of conditions[,.;:]? and the following disclaimers?[,.;:]?" |
| + " (?:[-\\p{L}\\p{N}] )?redistributions (?:in|of) binary form must reproduce the" |
| + " (?:above|accompanying) copyright notice[,.;:]? this list of conditions[,.:;]?" |
| + " and the following disclaimer in the documentation[,.;:]? and(?: |[/])or other" |
| + " materials(?: provided with the distribution)?[,.:;]{0,3}")); |
| |
| /** Creative Commons Attribution -- allows commercial */ |
| public static final Rule CC_BY_C = |
| license( |
| ImmutableList.of( |
| "\\bhttps?://[\\p{L}\\p{N}.]*creativecommons[.]org/licen[cs]es/by[-\\p{L}\\p{N}.]*", |
| "(?-i:\\bAttribution(?:-(?:Share ?Alike|NoDerivs)){0,2} )")); |
| |
| /** Creative Commons Non-Commercial License */ |
| public static final Rule CC_BY_NC = |
| license( |
| ImmutableList.of( |
| "\\bhttps?://[\\p{L}\\p{N}.]*creativecommons[.]org/licenses/by" |
| + "(?:-nd)?(?:-sa)?-nc[-/\\p{L}\\p{N}.]*", |
| "\\bAttribution(?:-NoDerivs)?(?:-Share ?Alike)?" |
| + "-NonCommercial(?:-NoDerivs)?(?:-Share ?Alike)?")); |
| |
| /** Commons Cause License */ |
| public static final Rule COMMONS_CAUSE = license(ImmutableList.of("\\bCommons Clause")); |
| |
| /** Common Public Attribution License */ |
| public static final Rule CPAL = |
| license(ImmutableList.of("\\bCommon Public Attribution Licen[cs]e")); |
| |
| /** Eclipse Public License */ |
| public static final Rule EPL = |
| license( |
| ImmutableList.of( |
| "^Eclipse Public Licen[cs]e[.]?", |
| ".*under (?:(?:the|this) )?(?:terms of )?(?:the )?eclipse" |
| + " (?:public )?licen[cs]e[,.;:]?.*", |
| ".*terms of (?:(?:the|this) )?eclipse public licen[cs]e[,.;:]?.*")); |
| |
| /** European Union Public License */ |
| public static final Rule EUPL = license(ImmutableList.of(" [(]?EUPL[)]? ")); |
| |
| /** Appears in tests similar to using example.com as a test domain */ |
| public static final Rule EXAMPLES = owner(ImmutableList.of("Your Company.")); |
| |
| /** Google owned */ |
| public static final Rule GOOGLE = owner(ImmutableList.of("Google,? Inc.")); |
| |
| /** Generic GNU General Public License */ |
| public static final Rule GPL = |
| license( |
| ImmutableList.of( |
| "\\bIn addition to the permissions in the GNU General Public License[,.;:]?", |
| "See the [\\[]?GNU[\\]]? General Public Licen[cs]e for more details[,.;:]?", |
| "\\bGNU General Public Licen[cs]e", |
| ".*gnu (?:library|lesser) general public licen[cs]e.*"), |
| ImmutableList.of( |
| "See the [\\[]?GNU[\\]]? General Public Licen[cs]e for more details[,.;:]?", |
| "In addition to the permissions in the GNU General Public License[,.;:]?")); |
| |
| /** GNU General Public License v2 */ |
| public static final Rule GPL2 = |
| license( |
| ImmutableList.of( |
| ".*SPDX-License-Identifier: GPL-2.0[+]?", |
| ".*SPDX-License-Identifier: GPL-2.0-only", |
| ".*SPDX-License-Identifier: GPL-2.0-or-later", |
| ".*[\\[]?GNU[\\]]? GPL[,;]? version 2[,.;:]?.*", |
| ".*[\\[]?GNU[\\]]? General Public Licen[cs]e[,;]? version 2[,.;:]?.*", |
| "See the [\\[]?GNU[\\]]? General Public Licen[cs]e for more details[,.;:]?", |
| "You should have received a copy of the [\\[]?GNU[\\]]? General Public Licen[cs]e", |
| ".*[\\[]?GNU[\\]]? General Public Licen[cs]e as published by the Free Software" |
| + " Foundation?(?:[']s)?[,.;:]? (?:either )?version 2.*"), |
| ImmutableList.of( |
| "See the [\\[]?GNU[\\]]? General Public Licen[cs]e for more details[,.;:]?", |
| "In addition to the permissions in the GNU General Public License[,.;:]?")); |
| |
| /** GNU General Public License v3 */ |
| public static final Rule GPL3 = |
| license( |
| ImmutableList.of( |
| ".*SPDX-License-Identifier: GPL-3.0[+]?", |
| ".*[\\[]?GNU[\\]]? GPL[,;]? version 3[,.;:]?.*", |
| ".*[\\[]?GNU[\\]]? General Public Licen[cs]e[,;]? version 3[,.;:]?.*", |
| "See the [\\[]?GNU[\\]]? General Public Licen[cs]e for more details[,.;:]?", |
| "You should have received a copy of the [\\[]?GNU[\\]]? General Public Licen[cs]e", |
| ".*[\\[]?GNU[\\]]? General Public Licen[cs]e as published by the Free Software" |
| + " Foundation?(?:[']s)?[,.;:]? (?:either )?version 3.*"), |
| ImmutableList.of( |
| "See the [\\[]?GNU[\\]]? General Public Licen[cs]e for more details[,.;:]?", |
| "In addition to the permissions in the GNU General Public License[,.;:]?")); |
| |
| /** GNU Lessor or Library General Public License */ |
| public static final Rule LGPL = |
| license( |
| ImmutableList.of( |
| ".*SPDX-License-Identifier: LGPL.*", |
| ".*LGPL.*", |
| ".*gnu (?:library|lesser) general public licen[cs]e.*")); |
| |
| /** MIT licensed */ |
| public static final Rule MIT = |
| license( |
| ImmutableList.of( |
| ".*SPDX-License-Identifier: MIT", |
| "http://www.opensource.org/licenses/mit-license.php", |
| "^the mit licen[cs]e(?:[:] http://www.opensource.org/licenses/mit-license.php)?", |
| "^MIT licen[cs]e[,.;:]? http://www.ibiblio.org/pub/Linux/LICENSE", |
| ".*under (?:(?:the|this) )?(?:terms of )?(?:the )?mit" |
| + " (?:open source )?licen[cs]e[,.;:]?.*", |
| ".*MIT licen[cs]ed", |
| ".*terms of (?:(?:the|this) )?mit licen[cs]e[,.;:]?.*", |
| ".*this code is licen[cs]ed under the mit licen[cs]e[,;.:]?.*", |
| ".*the mit or psf open source licen[cs]es[,.]?.*", |
| ".*Dual licen[cs]ed under the MIT or.*", |
| ".*Use of this software is governed by the MIT licen[cs]e[,.;:]?.*", |
| ".*This library is free software[,.;:]? you can redistribute it and or modify it" |
| + " under the terms of the MIT licen[cs]e[,.;:]?.*", |
| ".*may be distributed under the MIT or PSF open source licen[cs]es[,.;:]?.*", |
| ".*permission is (?:hereby )?granted[,;]? free of charge[,;]? to any person.*", |
| "(?:the mit licen[cs]e )?permission is (?:hereby )?granted[,;]? free of charge[,;]?" |
| + " to any person obtaining a copy of this software and associated documentation" |
| + " files [(]?the \\p{Pi}?software\\p{Pf}[)]?[,;]? to deal (?:in|with) the" |
| + " software without restriction[,;.:]? including without limitation the rights" |
| + " to use[,;]? copy[,;]? modify[,;]? merge[,;]? publish[,;]? distribute[,;]?" |
| + " sublicense[,;]? and(?: |[/])or sell copies of the software[,;]? and to permit" |
| + " persons to whom the software is furnished to do so[,;.:]? subject to the" |
| + " following conditions[,;.:]? the above copyright notice[,;]? and this" |
| + " permission notice shall be included in all copies[,;]? or substantial" |
| + " portions of the software[,;.:]?", |
| ".*permission to use[,;]? copy[,;]? modify[,;]? (?:and )?distribute" |
| + " (?:and sell )?this software (?:and its documentation )?(?:for any purpose )?" |
| + "(?:(?:and|with or) without fee)?is (?:hereby )?granted[,;]?" |
| + " (?:without fee )?provided that the above copyright notice.*", |
| ".*I hereby give permission[,;]? free of charge[,;]? to copy[,;]? modify[,;]? and" |
| + " redistribute this software[,;]? in source or binary form[,;]? provided that" |
| + " the above copyright notice and the following disclaimer are included.*")); |
| |
| /** Generic non-commercial disclaimer. */ |
| public static final Rule NON_COMMERCIAL = |
| license(ImmutableList.of("\\bNON-?COMMERCIAL LICEN[CS]E")); |
| |
| /** Rejects distribution under APACHE */ |
| public static final Rule NOT_A_CONTRIBUTION = |
| license( |
| ImmutableList.of( |
| ".*(?:" |
| + ANY_WORD |
| + " ){2}\\p{Pi}?" // 2 words to exclude false +ves |
| + "Not a Contribution[.,;:]{0,3}\\p{Pf}?.*"), // explicitly disclaims license |
| ImmutableList.of("owner as \\p{Pi}?Not a Contribution[.,;:]{0,3}\\p{Pf}?")); |
| |
| /** Python Software Foundation */ |
| public static final Rule PSF = owner(ImmutableList.of("Python Software Foundation")); |
| |
| /** Python Software Foundation License */ |
| public static final Rule PSFL = |
| license( |
| ImmutableList.of( |
| ".*Python Software Foundation license(?: version \\p{N})?[,.;:]?.*", |
| ".*Permission to use[,;]? copy[,;]? modify[,;]? and distribute this Python software" |
| + " and its associated documentation for any purpose.*")); |
| |
| /** Sun Insdustry Standards Source License */ |
| public static final Rule SISSL = |
| license(ImmutableList.of("\\bSun Industry Standards Source Licen[cs]e")); |
| |
| /** Watcom-1.0 license */ |
| public static final Rule WATCOM = |
| license( |
| ImmutableList.of( |
| ".*Sybase Open Watcom Public License.*", |
| ".*automatically without notice if You[,;]? at any time during the term of this" |
| + " Licen[cs]e[,;]? commence an action for patent infringement [(]?including as a" |
| + " cross claim or counterclaim[)]?.*")); |
| |
| /** Do What The Fuck You Want To Public License */ |
| public static final Rule WTFPL = |
| license(ImmutableList.of("\\bDo What The Fuck You Want To Public Licen[cs]e")); |
| |
| @VisibleForTesting |
| static ImmutableMap<String, Rule> lookup = |
| ImmutableMap.<String, Rule>builder() |
| .put("AGPL", AGPL) |
| .put("ANDROID", ANDROID) |
| .put("APACHE2", APACHE2) |
| .put("BEER_WARE", BEER_WARE) |
| .put("BSD", BSD) |
| .put("CC_BY_C", CC_BY_C) |
| .put("CC_BY_NC", CC_BY_NC) |
| .put("COMMONS_CLAUSE", COMMONS_CAUSE) |
| .put("CPAL", CPAL) |
| .put("EPL", EPL) |
| .put("EUPL", EUPL) |
| .put("EXAMPLES", EXAMPLES) |
| .put("GOOGLE", GOOGLE) |
| .put("GPL", GPL) |
| .put("GPL2", GPL2) |
| .put("GPL3", GPL3) |
| .put("LGPL", LGPL) |
| .put("MIT", MIT) |
| .put("NON_COMMERCIAL", NON_COMMERCIAL) |
| .put("NOT_A_CONTRIBUTION", NOT_A_CONTRIBUTION) |
| .put("PSF", PSF) |
| .put("PSFL", PSFL) |
| .put("SISSL", SISSL) |
| .put("WATCOM", WATCOM) |
| .put("WTFPL", WTFPL) |
| .build(); |
| |
| /** Immutable set of copyright rules described as lists of regular expression strings. */ |
| public static class RuleSet { |
| public final ImmutableList<String> firstPartyLicenses; |
| public final ImmutableList<String> thirdPartyLicenses; |
| public final ImmutableList<String> forbiddenLicenses; |
| public final ImmutableList<String> firstPartyOwners; |
| public final ImmutableList<String> thirdPartyOwners; |
| public final ImmutableList<String> forbiddenOwners; |
| public final ImmutableList<String> excludePatterns; |
| |
| /** Returns a Builder object for the RuleSet class. */ |
| public static Builder builder() { |
| return new Builder(); |
| } |
| |
| /** Implements the Builder pattern for CopyrightPatterns.RuleSet. */ |
| public static class Builder { |
| private final ImmutableList.Builder<String> firstPartyLicenses = |
| ImmutableList.<String>builder(); |
| private final ImmutableList.Builder<String> thirdPartyLicenses = |
| ImmutableList.<String>builder(); |
| private final ImmutableList.Builder<String> forbiddenLicenses = |
| ImmutableList.<String>builder(); |
| private final ImmutableList.Builder<String> firstPartyOwners = |
| ImmutableList.<String>builder(); |
| private final ImmutableList.Builder<String> thirdPartyOwners = |
| ImmutableList.<String>builder(); |
| private final ImmutableList.Builder<String> forbiddenOwners = ImmutableList.<String>builder(); |
| private final ImmutableList.Builder<String> excludePatterns = ImmutableList.<String>builder(); |
| |
| private Builder() {} |
| |
| /** Create a RuleSet reflecting the current state of this Builder. */ |
| public RuleSet build() { |
| return new RuleSet( |
| firstPartyLicenses.build(), |
| thirdPartyLicenses.build(), |
| forbiddenLicenses.build(), |
| firstPartyOwners.build(), |
| thirdPartyOwners.build(), |
| forbiddenOwners.build(), |
| excludePatterns.build()); |
| } |
| |
| /** Look up `ruleName` and add it as a 1p rule type. */ |
| public Builder addFirstParty(String ruleName) { |
| Rule pattern = lookup.get(ruleName); |
| if (pattern == null) { |
| throw new UnknownPatternName(ruleName); |
| } |
| if (pattern.licenses != null) { |
| firstPartyLicenses.addAll(pattern.licenses); |
| } |
| if (pattern.owners != null) { |
| firstPartyOwners.addAll(pattern.owners); |
| } |
| if (pattern.exclusions != null) { |
| excludePatterns.addAll(pattern.exclusions); |
| } |
| return this; |
| } |
| |
| /** Add the regular expression `pattern` as a 1p owner. */ |
| public Builder addFirstPartyOwner(String pattern) { |
| firstPartyOwners.add(pattern); |
| return this; |
| } |
| |
| /** Add the regular expression `pattern` as a 1p license */ |
| public Builder addFirstPartyLicense(String pattern) { |
| firstPartyLicenses.add(pattern); |
| return this; |
| } |
| |
| /** Look up `ruleName` and add it as a 3p rule type. */ |
| public Builder addThirdParty(String ruleName) { |
| Rule pattern = lookup.get(ruleName); |
| if (pattern == null) { |
| throw new UnknownPatternName(ruleName); |
| } |
| if (pattern.licenses != null) { |
| thirdPartyLicenses.addAll(pattern.licenses); |
| } |
| if (pattern.owners != null) { |
| thirdPartyOwners.addAll(pattern.owners); |
| } |
| if (pattern.exclusions != null) { |
| excludePatterns.addAll(pattern.exclusions); |
| } |
| return this; |
| } |
| |
| /** Add the regular expression `pattern` as a 3p owner. */ |
| public Builder addThirdPartyOwner(String pattern) { |
| thirdPartyOwners.add(pattern); |
| return this; |
| } |
| |
| /** Add the regular expression `pattern` as a 3p license. */ |
| public Builder addThirdPartyLicense(String pattern) { |
| thirdPartyLicenses.add(pattern); |
| return this; |
| } |
| |
| /** Look up `ruleName` and add it as a forbidden rule type. */ |
| public Builder addForbidden(String ruleName) { |
| Rule pattern = lookup.get(ruleName); |
| if (pattern == null) { |
| throw new UnknownPatternName(ruleName); |
| } |
| if (pattern.licenses != null) { |
| forbiddenLicenses.addAll(pattern.licenses); |
| } |
| if (pattern.owners != null) { |
| forbiddenOwners.addAll(pattern.owners); |
| } |
| if (pattern.exclusions != null) { |
| excludePatterns.addAll(pattern.exclusions); |
| } |
| return this; |
| } |
| |
| /** Add the regular expression `pattern` as a forbidden owner. */ |
| public Builder addForbiddenOwner(String pattern) { |
| forbiddenOwners.add(pattern); |
| return this; |
| } |
| |
| /** Add the regular expression `pattern` as a forbidden license. */ |
| public Builder addForbiddenLicense(String pattern) { |
| forbiddenLicenses.add(pattern); |
| return this; |
| } |
| |
| /** Look up `ruleName` and add it as a rule type to ignore completely. */ |
| public Builder exclude(String ruleName) { |
| Rule pattern = lookup.get(ruleName); |
| if (pattern == null) { |
| throw new UnknownPatternName(ruleName); |
| } |
| if (pattern.licenses != null) { |
| excludePatterns.addAll(pattern.licenses); |
| } |
| if (pattern.owners != null) { |
| excludePatterns.addAll(pattern.owners); |
| } |
| if (pattern.exclusions != null) { |
| excludePatterns.addAll(pattern.exclusions); |
| } |
| return this; |
| } |
| |
| /** Add the regular expression `pattern` to the list of patterns to ignore when found. */ |
| public Builder excludePattern(String pattern) { |
| excludePatterns.add(pattern); |
| return this; |
| } |
| } |
| |
| private RuleSet( |
| ImmutableList<String> firstPartyLicenses, |
| ImmutableList<String> thirdPartyLicenses, |
| ImmutableList<String> forbiddenLicenses, |
| ImmutableList<String> firstPartyOwners, |
| ImmutableList<String> thirdPartyOwners, |
| ImmutableList<String> forbiddenOwners, |
| ImmutableList<String> excludePatterns) { |
| this.firstPartyLicenses = firstPartyLicenses; |
| this.thirdPartyLicenses = thirdPartyLicenses; |
| this.forbiddenLicenses = forbiddenLicenses; |
| this.firstPartyOwners = firstPartyOwners; |
| this.thirdPartyOwners = thirdPartyOwners; |
| this.forbiddenOwners = forbiddenOwners; |
| this.excludePatterns = excludePatterns; |
| } |
| } |
| |
| /** Initialize a pattern consisting of only a list of owner patterns. */ |
| private static Rule owner(ImmutableList<String> owners) { |
| return new Rule(owners, null, null); |
| } |
| |
| /** Initialize a pattern consisting of only a list of license patterns. */ |
| private static Rule license(ImmutableList<String> licenses) { |
| return new Rule(null, licenses, null); |
| } |
| |
| /** Initialize a pattern consisting of lists of license and exclusion patterns. */ |
| private static Rule license(ImmutableList<String> licenses, ImmutableList<String> exclusions) { |
| return new Rule(null, licenses, exclusions); |
| } |
| |
| /** |
| * A matching rule described by lists of regular expressions matching relevant licenses and |
| * owners, and a list of regular expressions matching hits to ignore when found. |
| * |
| * <p>e.g. The text "not a contribution" is important for Apache2 licensed code because it |
| * disclaims the terms of the otherwise described Apache2 license. However, this very text exists |
| * inside the Apache2 license to allow such disclaimers. An effective rule for /not a |
| * contribution/ will have to match /not a contribution/ but ignore /owner as "not a |
| * contribution"/ like it appears in the license itself. |
| */ |
| @VisibleForTesting |
| static class Rule { |
| public final ImmutableList<String> exclusions; |
| public final ImmutableList<String> owners; |
| public final ImmutableList<String> licenses; |
| |
| private Rule(ImmutableList<String> owners, ImmutableList<String> licenses) { |
| this(owners, licenses, null); |
| } |
| |
| private Rule( |
| ImmutableList<String> owners, |
| ImmutableList<String> licenses, |
| ImmutableList<String> exclusions) { |
| this.owners = owners; |
| this.licenses = licenses; |
| this.exclusions = exclusions; |
| } |
| } |
| |
| /** Thrown when requesting a pattern by a name that does not appear among the known patterns. */ |
| public static class UnknownPatternName extends NoSuchElementException { |
| UnknownPatternName(String ruleName) { |
| super( |
| "Unknown pattern name: " |
| + ruleName |
| + "\nKnown pattern names include: " |
| + Joiner.on(", ").join(lookup.keySet())); |
| } |
| } |
| } |