This is an automated email from the ASF dual-hosted git repository.

chesnay pushed a commit to branch release-1.12
in repository https://gitbox.apache.org/repos/asf/flink.git

commit 1f184e6b4fd184280eadaddac366f5ae67d0c8c7
Author: Chesnay Schepler <[email protected]>
AuthorDate: Mon Dec 7 03:03:43 2020 +0100

    [FLINK-20455][build][legal] Add jar license checker
---
 tools/ci/compile.sh                                |  10 +-
 tools/ci/java-ci-tools/pom.xml                     |  10 +
 .../tools/ci/licensecheck/JarFileChecker.java      | 156 ++++++++
 .../tools/ci/licensecheck/LicenseChecker.java      |   7 +-
 .../tools/ci/licensecheck/JarFileCheckerTest.java  | 444 +++++++++++++++++++++
 tools/ci/license_check.sh                          |   3 +-
 6 files changed, 625 insertions(+), 5 deletions(-)

diff --git a/tools/ci/compile.sh b/tools/ci/compile.sh
index d91d24a..14e03fe 100755
--- a/tools/ci/compile.sh
+++ b/tools/ci/compile.sh
@@ -29,6 +29,10 @@ fi
 CI_DIR="$HERE/../ci"
 MVN_CLEAN_COMPILE_OUT="/tmp/clean_compile.out"
 
+# Deploy into this directory, to run license checks on all jars staged for 
deployment.
+# This helps us ensure that ALL artifacts we deploy to maven central adhere to 
our license conditions.
+MVN_VALIDATION_DIR="/tmp/flink-validation-deployment"
+
 # source required ci scripts
 source "${CI_DIR}/stage.sh"
 source "${CI_DIR}/shade.sh"
@@ -43,7 +47,7 @@ echo 
"==========================================================================
 
 EXIT_CODE=0
 
-run_mvn clean install $MAVEN_OPTS -Dflink.convergence.phase=install 
-Pcheck-convergence -Dflink.forkCount=2 \
+run_mvn clean deploy 
-DaltDeploymentRepository=validation_repository::default::file:$MVN_VALIDATION_DIR
 $MAVEN_OPTS -Dflink.convergence.phase=install -Pcheck-convergence 
-Dflink.forkCount=2 \
     -Dflink.forkCountTestPackage=2 -Dmaven.javadoc.skip=true -U -DskipTests | 
tee $MVN_CLEAN_COMPILE_OUT
 
 EXIT_CODE=${PIPESTATUS[0]}
@@ -107,8 +111,10 @@ EXIT_CODE=$(($EXIT_CODE+$?))
 
 echo "============ Run license check ============"
 
+find $MVN_VALIDATION_DIR
+
 if [[ ${PROFILE} != *"scala-2.12"* ]]; then
-  ${CI_DIR}/license_check.sh $MVN_CLEAN_COMPILE_OUT $CI_DIR $(pwd) || exit $?
+  ${CI_DIR}/license_check.sh $MVN_CLEAN_COMPILE_OUT $CI_DIR $(pwd) 
$MVN_VALIDATION_DIR || exit $?
 fi
 
 exit $EXIT_CODE
diff --git a/tools/ci/java-ci-tools/pom.xml b/tools/ci/java-ci-tools/pom.xml
index fdfb268..bd75a46 100644
--- a/tools/ci/java-ci-tools/pom.xml
+++ b/tools/ci/java-ci-tools/pom.xml
@@ -35,6 +35,16 @@ under the License.
 
        <dependencies>
                <dependency>
+                       <groupId>org.apache.flink</groupId>
+                       <artifactId>flink-annotations</artifactId>
+                       <version>${project.version}</version>
+               </dependency>
+               <dependency>
+                       <groupId>org.apache.flink</groupId>
+                       <artifactId>flink-test-utils-junit</artifactId>
+                       <scope>test</scope>
+               </dependency>
+               <dependency>
                        <groupId>com.google.guava</groupId>
                        <artifactId>guava</artifactId>
                        <version>30.0-jre</version>
diff --git 
a/tools/ci/java-ci-tools/src/main/java/org/apache/flink/tools/ci/licensecheck/JarFileChecker.java
 
b/tools/ci/java-ci-tools/src/main/java/org/apache/flink/tools/ci/licensecheck/JarFileChecker.java
new file mode 100644
index 0000000..dbd1945
--- /dev/null
+++ 
b/tools/ci/java-ci-tools/src/main/java/org/apache/flink/tools/ci/licensecheck/JarFileChecker.java
@@ -0,0 +1,156 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.flink.tools.ci.licensecheck;
+
+import org.apache.flink.annotation.VisibleForTesting;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+import java.net.URI;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.FileSystem;
+import java.nio.file.FileSystems;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.Collections;
+import java.util.List;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+/**
+ * Checks the Jar files created by the build process.
+ */
+public class JarFileChecker {
+       private static final Logger LOG = 
LoggerFactory.getLogger(JarFileChecker.class);
+
+       public static int checkPath(Path path) throws Exception {
+               List<Path> files = getBuildJars(path);
+               LOG.info("Checking directory {} with a total of {} jar files.", 
path, files.size());
+
+               int severeIssues = 0;
+               for (Path file : files) {
+                       severeIssues += checkJar(file);
+               }
+
+               return severeIssues;
+       }
+
+       private static List<Path> getBuildJars(Path path) throws IOException {
+               return Files.walk(path)
+                       .filter(file -> file.toString().endsWith(".jar"))
+                       .collect(Collectors.toList());
+       }
+
+       @VisibleForTesting
+       static int checkJar(Path file) throws Exception {
+               final URI uri = file.toUri();
+
+               int numSevereIssues = 0;
+               try (final FileSystem fileSystem = 
FileSystems.newFileSystem(new URI("jar:file", uri.getHost(), uri.getPath(), 
uri.getFragment()), Collections.emptyMap())) {
+                       if (isTestJarAndEmpty(file, fileSystem.getPath("/"))) {
+                               return 0;
+                       }
+                       if 
(!noticeFileExistsAndIsValid(fileSystem.getPath("META-INF", "NOTICE"), file)) {
+                               numSevereIssues++;
+                       }
+                       if 
(!licenseFileExistsAndIsValid(fileSystem.getPath("META-INF", "LICENSE"), file)) 
{
+                               numSevereIssues++;
+                       }
+
+                       numSevereIssues += 
getNumLicenseFilesOutsideMetaInfDirectory(file, fileSystem.getPath("/"));
+               }
+               return numSevereIssues;
+       }
+
+       private static boolean isTestJarAndEmpty(Path jar, Path jarRoot) throws 
IOException {
+               if (jar.getFileName().toString().endsWith("-tests.jar")) {
+                       try (Stream<Path> files = Files.walk(jarRoot)) {
+                               long numClassFiles = files
+                                       .filter(path -> !path.equals(jarRoot))
+                                       .filter(path -> 
path.getFileName().toString().endsWith(".class"))
+                                       .count();
+                               if (numClassFiles == 0) {
+                                       return true;
+                               }
+                       }
+               }
+
+               return false;
+       }
+
+       private static boolean noticeFileExistsAndIsValid(Path noticeFile, Path 
jar) throws IOException {
+               if (!Files.exists(noticeFile)) {
+                       LOG.error("Missing META-INF/NOTICE in {}", jar);
+                       return false;
+               }
+
+               final String noticeFileContents = new 
String(Files.readAllBytes(noticeFile), StandardCharsets.UTF_8);
+               if (!noticeFileContents.toLowerCase().contains("flink") || 
!noticeFileContents.contains("The Apache Software Foundation")) {
+                       LOG.error("The notice file in {} does not contain the 
expected entries.", jar);
+                       return false;
+               }
+
+               return true;
+       }
+
+       private static boolean licenseFileExistsAndIsValid(Path licenseFile, 
Path jar) throws IOException {
+               if (!Files.exists(licenseFile)) {
+                       LOG.error("Missing META-INF/LICENSE in {}", jar);
+                       return false;
+               }
+
+               final String licenseFileContents = new 
String(Files.readAllBytes(licenseFile), StandardCharsets.UTF_8);
+               if (!licenseFileContents.contains("Apache License") || 
!licenseFileContents.contains("Version 2.0, January 2004")) {
+                       LOG.error("The license file in {} does not contain the 
expected entries.", jar);
+                       return false;
+               }
+
+               return true;
+       }
+
+       private static int getNumLicenseFilesOutsideMetaInfDirectory(Path jar, 
Path jarRoot) throws IOException {
+               try (Stream<Path> files = Files.walk(jarRoot)) {
+                       /*
+                        * LICENSE or NOTICE files found outside of the 
META-INF directory are most likely shading mistakes (we are including the files 
from other dependencies, thus providing an invalid LICENSE file)
+                        *
+                        * <p>In such a case, we recommend updating the shading 
exclusions, and adding the license file to META-INF/licenses.
+                        */
+                       final List<String> filesWithIssues = files
+                               .filter(path -> !path.equals(jarRoot))
+                               .filter(path -> 
getFileName(path).contains("license") || getFileName(path).contains("notice"))
+                               .filter(path -> !Files.isDirectory(path)) // 
ignore directories, e.g. "license/"
+                               .filter(path -> 
!getFileName(path).endsWith(".class")) // some class files contain LICENSE in 
their name
+                               .filter(path -> 
!getFileName(path).endsWith(".ftl")) // a false positive in flink-python
+                               .map(Path::toString)
+                               .filter(path -> !path.contains("META-INF")) // 
license files in META-INF are expected
+                               .filter(path -> 
!path.endsWith("web/3rdpartylicenses.txt")) // a false positive in 
flink-runtime-web
+                               .collect(Collectors.toList());
+                       for (String fileWithIssue : filesWithIssues) {
+                               LOG.error("Jar file {} contains a LICENSE file 
in an unexpected location: {}", jar, fileWithIssue);
+                       }
+                       return filesWithIssues.size();
+               }
+       }
+
+       private static String getFileName(Path path) {
+               return path.getFileName().toString().toLowerCase();
+       }
+}
diff --git 
a/tools/ci/java-ci-tools/src/main/java/org/apache/flink/tools/ci/licensecheck/LicenseChecker.java
 
b/tools/ci/java-ci-tools/src/main/java/org/apache/flink/tools/ci/licensecheck/LicenseChecker.java
index 240e062..1f066e5 100644
--- 
a/tools/ci/java-ci-tools/src/main/java/org/apache/flink/tools/ci/licensecheck/LicenseChecker.java
+++ 
b/tools/ci/java-ci-tools/src/main/java/org/apache/flink/tools/ci/licensecheck/LicenseChecker.java
@@ -32,9 +32,9 @@ public class LicenseChecker {
 
        private static final Logger LOG = 
LoggerFactory.getLogger(LicenseChecker.class);
 
-       public static void main(String[] args) throws IOException {
+       public static void main(String[] args) throws Exception {
                if (args.length < 2) {
-                       System.out.println("Usage: LicenseChecker 
<pathMavenBuildOutput> <pathFlinkRoot>");
+                       System.out.println("Usage: LicenseChecker 
<pathMavenBuildOutput> <pathFlinkRoot> <pathFlinkDeployed>");
                        System.exit(1);
                }
                LOG.warn("THIS UTILITY IS ONLY CHECKING FOR COMMON LICENSING 
MISTAKES. A MANUAL CHECK OF THE NOTICE FILES, DEPLOYED ARTIFACTS, ETC. IS STILL 
NEEDED!");
@@ -42,6 +42,9 @@ public class LicenseChecker {
                NoticeFileChecker noticeChecker = new NoticeFileChecker();
                int severeIssueCount = noticeChecker.run(new File(args[0]), 
Paths.get(args[1]));
 
+               JarFileChecker jarChecker = new JarFileChecker();
+               severeIssueCount += jarChecker.checkPath(Paths.get(args[2]));
+
                if (severeIssueCount > 0) {
                        LOG.warn("Found a total of {} severe license issues", 
severeIssueCount);
 
diff --git 
a/tools/ci/java-ci-tools/src/test/java/org/apache/flink/tools/ci/licensecheck/JarFileCheckerTest.java
 
b/tools/ci/java-ci-tools/src/test/java/org/apache/flink/tools/ci/licensecheck/JarFileCheckerTest.java
new file mode 100644
index 0000000..f9fb664
--- /dev/null
+++ 
b/tools/ci/java-ci-tools/src/test/java/org/apache/flink/tools/ci/licensecheck/JarFileCheckerTest.java
@@ -0,0 +1,444 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.flink.tools.ci.licensecheck;
+
+import org.apache.flink.util.TestLogger;
+
+import org.junit.ClassRule;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+
+import java.net.URI;
+import java.nio.file.FileSystem;
+import java.nio.file.FileSystems;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertThat;
+
+/**
+ * Tests for the {@link JarFileChecker}.
+ *
+ * <p>For dev purposes, generate a deploy-directory with:
+ * mvn clean deploy 
-DaltDeploymentRepository=snapshot-repo::default::file:/tmp/flink-deployment 
-DskipTests -Drat.skip
+ * and add a test checking that directory.
+ */
+public class JarFileCheckerTest extends TestLogger {
+
+       @ClassRule
+       public static final TemporaryFolder TMP = new TemporaryFolder();
+
+       private static final List<String> VALID_NOTICE_PATH = 
Arrays.asList("META-INF", "NOTICE");
+       private static final List<String> VALID_LICENSE_PATH = 
Arrays.asList("META-INF", "LICENSE");
+
+       @Test
+       public void testValidJarAccepted() throws Exception {
+               assertThat(JarFileChecker.checkJar(
+                       createJar(
+                               Entry.fileEntry(VALID_NOTICE_CONTENTS, 
VALID_NOTICE_PATH),
+                               Entry.fileEntry(VALID_LICENSE_CONTENTS, 
VALID_LICENSE_PATH))),
+                       is(0));
+       }
+
+       @Test
+       public void testRejectedOnMissingNoticeFile() throws Exception {
+               assertThat(JarFileChecker.checkJar(
+                       createJar(
+                               Entry.fileEntry(VALID_LICENSE_CONTENTS, 
VALID_LICENSE_PATH))),
+                       is(1));
+       }
+
+       @Test
+       public void testRejectedOnInvalidNoticeFile() throws Exception {
+               assertThat(JarFileChecker.checkJar(
+                       createJar(
+                               Entry.fileEntry(INVALID_NOTICE_CONTENTS, 
VALID_NOTICE_PATH),
+                               Entry.fileEntry(VALID_LICENSE_CONTENTS, 
VALID_LICENSE_PATH))),
+                       is(1));
+       }
+
+       @Test
+       public void testRejectedOnNoticeFileInRoot() throws Exception {
+               assertThat(JarFileChecker.checkJar(
+                       createJar(
+                               Entry.fileEntry(VALID_NOTICE_CONTENTS, 
VALID_NOTICE_PATH),
+                               Entry.fileEntry(VALID_LICENSE_CONTENTS, 
VALID_LICENSE_PATH),
+                               Entry.fileEntry(VALID_NOTICE_CONTENTS, 
Arrays.asList("some_custom_notice")))),
+                       is(1));
+       }
+
+       @Test
+       public void testRejectedOnMissingLicenseFile() throws Exception {
+               assertThat(JarFileChecker.checkJar(
+                       createJar(
+                               Entry.fileEntry(VALID_NOTICE_CONTENTS, 
VALID_NOTICE_PATH))),
+                       is(1));
+       }
+
+       @Test
+       public void testRejectedOnInvalidLicenseFile() throws Exception {
+               assertThat(JarFileChecker.checkJar(
+                       createJar(
+                               Entry.fileEntry(VALID_NOTICE_CONTENTS, 
VALID_NOTICE_PATH),
+                               Entry.fileEntry(INVALID_LICENSE_CONTENTS, 
VALID_LICENSE_PATH))),
+                       is(1));
+       }
+
+       @Test
+       public void testRejectedOnLicenseFileInRoot() throws Exception {
+               assertThat(JarFileChecker.checkJar(
+                       createJar(
+                               Entry.fileEntry(VALID_NOTICE_CONTENTS, 
VALID_NOTICE_PATH),
+                               Entry.fileEntry(VALID_LICENSE_CONTENTS, 
VALID_LICENSE_PATH),
+                               Entry.fileEntry(VALID_LICENSE_CONTENTS, 
Arrays.asList("some_custom_license")))),
+                       is(1));
+       }
+
+       @Test
+       public void testRejectedOnLicenseFileInSomeDirectory() throws Exception 
{
+               assertThat(JarFileChecker.checkJar(
+                       createJar(
+                               Entry.fileEntry(VALID_NOTICE_CONTENTS, 
VALID_NOTICE_PATH),
+                               Entry.fileEntry(VALID_LICENSE_CONTENTS, 
VALID_LICENSE_PATH),
+                               Entry.fileEntry(VALID_LICENSE_CONTENTS, 
Arrays.asList("some", "directory", "some_custom_license")))),
+                       is(1));
+       }
+
+       @Ignore("Currently not checked, but we may want to enforce this in the 
future to reduce ambiguity.")
+       public void testRejectedOnAdditionalLicenseFileInMetaInf() throws 
Exception {
+               assertThat(JarFileChecker.checkJar(
+                       createJar(
+                               Entry.fileEntry(VALID_NOTICE_CONTENTS, 
VALID_NOTICE_PATH),
+                               Entry.fileEntry(VALID_LICENSE_CONTENTS, 
VALID_LICENSE_PATH),
+                               Entry.fileEntry(VALID_LICENSE_CONTENTS, 
Arrays.asList("META-INF", "LICENSE.txt")))),
+                       is(1));
+       }
+
+       @Test
+       public void testIgnoreLicenseDirectories() throws Exception {
+               assertThat(JarFileChecker.checkJar(
+                       createJar(
+                               Entry.fileEntry(VALID_NOTICE_CONTENTS, 
VALID_NOTICE_PATH),
+                               Entry.fileEntry(VALID_LICENSE_CONTENTS, 
VALID_LICENSE_PATH),
+                               Entry.directoryEntry(Arrays.asList("some", 
"license", "directory")))),
+                       is(0));
+       }
+
+       @Test
+       public void testIgnoreClassFiles() throws Exception {
+               assertThat(JarFileChecker.checkJar(
+                       createJar(
+                               Entry.fileEntry(VALID_NOTICE_CONTENTS, 
VALID_NOTICE_PATH),
+                               Entry.fileEntry(VALID_LICENSE_CONTENTS, 
VALID_LICENSE_PATH),
+                               Entry.fileEntry("content", 
Arrays.asList("SomeLicenseClass.class")))),
+                       is(0));
+       }
+
+       @Test
+       public void testIgnoreFtlFiles() throws Exception {
+               assertThat(JarFileChecker.checkJar(
+                       createJar(
+                               Entry.fileEntry(VALID_NOTICE_CONTENTS, 
VALID_NOTICE_PATH),
+                               Entry.fileEntry(VALID_LICENSE_CONTENTS, 
VALID_LICENSE_PATH),
+                               Entry.fileEntry("content", 
Arrays.asList("SomeLicenseFile.ftl")))),
+                       is(0));
+       }
+
+       @Test
+       public void testIgnoreWebThirdPartyLicenses() throws Exception {
+               assertThat(JarFileChecker.checkJar(
+                       createJar(
+                               Entry.fileEntry(VALID_NOTICE_CONTENTS, 
VALID_NOTICE_PATH),
+                               Entry.fileEntry(VALID_LICENSE_CONTENTS, 
VALID_LICENSE_PATH),
+                               Entry.fileEntry("class contents", 
Arrays.asList("web", "3rdpartylicenses.txt")))),
+                       is(0));
+       }
+
+       private static class Entry {
+               final String contents;
+               final List<String> path;
+               final boolean isDirectory;
+
+               public static Entry directoryEntry(List<String> path) {
+                       return new Entry("", path, true);
+               }
+
+               public static Entry fileEntry(String contents, List<String> 
path) {
+                       return new Entry(contents, path, false);
+               }
+
+               private Entry(String contents, List<String> path, boolean 
isDirectory) {
+                       this.contents = contents;
+                       this.path = path;
+                       this.isDirectory = isDirectory;
+               }
+       }
+
+       private static Path createJar(Entry... entries) throws Exception {
+               final Path path = 
TMP.getRoot().toPath().resolve(UUID.randomUUID().toString() + ".jar");
+
+               final URI uriWithoutScheme = path.toUri();
+
+               final URI uri = new URI("jar:file", uriWithoutScheme.getHost(), 
uriWithoutScheme.getPath(), uriWithoutScheme.getFragment());
+
+               // causes FileSystems#newFileSystem to automatically create a 
valid zip file
+               // this is easier than manually creating a valid empty zip file 
manually
+               final Map<String, String> env = new HashMap<>();
+               env.put("create", "true");
+
+               try (FileSystem zip = FileSystems.newFileSystem(uri, env)) {
+                       // shortcut to getting the single root
+                       final Path root = zip.getPath("").toAbsolutePath();
+                       for (Entry entry : entries) {
+                               final Path zipPath = 
root.resolve(zip.getPath(entry.path.get(0), entry.path.subList(1, 
entry.path.size()).toArray(new String[]{})));
+                               if (entry.isDirectory) {
+                                       Files.createDirectories(zipPath);
+                               } else {
+                                       
Files.createDirectories(zipPath.getParent());
+                                       Files.write(zipPath, 
entry.contents.getBytes());
+                               }
+                       }
+               }
+               return path;
+       }
+
+       private static final String INVALID_NOTICE_CONTENTS = "" +
+               "invalid";
+
+       private static final String VALID_NOTICE_CONTENTS = "" +
+               "Flink : SomeModule\n" +
+               "Copyright 2014-2020 The Apache Software Foundation\n" +
+               "\n" +
+               "This product includes software developed at\n" +
+               "The Apache Software Foundation (http://www.apache.org/).";
+
+       private static final String INVALID_LICENSE_CONTENTS = "" +
+               "invalid";
+
+       private static final String VALID_LICENSE_CONTENTS = "" +
+               "\n" +
+               "                                 Apache License\n" +
+               "                           Version 2.0, January 2004\n" +
+               "                        http://www.apache.org/licenses/\n"; +
+               "\n" +
+               "   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND 
DISTRIBUTION\n" +
+               "\n" +
+               "   1. Definitions.\n" +
+               "\n" +
+               "      \"License\" shall mean the terms and conditions for use, 
reproduction,\n" +
+               "      and distribution as defined by Sections 1 through 9 of 
this document.\n" +
+               "\n" +
+               "      \"Licensor\" shall mean the copyright owner or entity 
authorized by\n" +
+               "      the copyright owner that is granting the License.\n" +
+               "\n" +
+               "      \"Legal Entity\" shall mean the union of the acting 
entity and all\n" +
+               "      other entities that control, are controlled by, or are 
under common\n" +
+               "      control with that entity. For the purposes of this 
definition,\n" +
+               "      \"control\" means (i) the power, direct or indirect, to 
cause the\n" +
+               "      direction or management of such entity, whether by 
contract or\n" +
+               "      otherwise, or (ii) ownership of fifty percent (50%) or 
more of the\n" +
+               "      outstanding shares, or (iii) beneficial ownership of 
such entity.\n" +
+               "\n" +
+               "      \"You\" (or \"Your\") shall mean an individual or Legal 
Entity\n" +
+               "      exercising permissions granted by this License.\n" +
+               "\n" +
+               "      \"Source\" form shall mean the preferred form for making 
modifications,\n" +
+               "      including but not limited to software source code, 
documentation\n" +
+               "      source, and configuration files.\n" +
+               "\n" +
+               "      \"Object\" form shall mean any form resulting from 
mechanical\n" +
+               "      transformation or translation of a Source form, 
including but\n" +
+               "      not limited to compiled object code, generated 
documentation,\n" +
+               "      and conversions to other media types.\n" +
+               "\n" +
+               "      \"Work\" shall mean the work of authorship, whether in 
Source or\n" +
+               "      Object form, made available under the License, as 
indicated by a\n" +
+               "      copyright notice that is included in or attached to the 
work\n" +
+               "      (an example is provided in the Appendix below).\n" +
+               "\n" +
+               "      \"Derivative Works\" shall mean any work, whether in 
Source or Object\n" +
+               "      form, that is based on (or derived from) the Work and 
for which the\n" +
+               "      editorial revisions, annotations, elaborations, or other 
modifications\n" +
+               "      represent, as a whole, an original work of authorship. 
For the purposes\n" +
+               "      of this License, Derivative Works shall not include 
works that remain\n" +
+               "      separable from, or merely link (or bind by name) to the 
interfaces of,\n" +
+               "      the Work and Derivative Works thereof.\n" +
+               "\n" +
+               "      \"Contribution\" shall mean any work of authorship, 
including\n" +
+               "      the original version of the Work and any modifications 
or additions\n" +
+               "      to that Work or Derivative Works thereof, that is 
intentionally\n" +
+               "      submitted to Licensor for inclusion in the Work by the 
copyright owner\n" +
+               "      or by an individual or Legal Entity authorized to submit 
on behalf of\n" +
+               "      the copyright owner. For the purposes of this 
definition, \"submitted\"\n" +
+               "      means any form of electronic, verbal, or written 
communication sent\n" +
+               "      to the Licensor or its representatives, including but 
not limited to\n" +
+               "      communication on electronic mailing lists, source code 
control systems,\n" +
+               "      and issue tracking systems that are managed by, or on 
behalf of, the\n" +
+               "      Licensor for the purpose of discussing and improving the 
Work, but\n" +
+               "      excluding communication that is conspicuously marked or 
otherwise\n" +
+               "      designated in writing by the copyright owner as \"Not a 
Contribution.\"\n" +
+               "\n" +
+               "      \"Contributor\" shall mean Licensor and any individual 
or Legal Entity\n" +
+               "      on behalf of whom a Contribution has been received by 
Licensor and\n" +
+               "      subsequently incorporated within the Work.\n" +
+               "\n" +
+               "   2. Grant of Copyright License. Subject to the terms and 
conditions of\n" +
+               "      this License, each Contributor hereby grants to You a 
perpetual,\n" +
+               "      worldwide, non-exclusive, no-charge, royalty-free, 
irrevocable\n" +
+               "      copyright license to reproduce, prepare Derivative Works 
of,\n" +
+               "      publicly display, publicly perform, sublicense, and 
distribute the\n" +
+               "      Work and such Derivative Works in Source or Object 
form.\n" +
+               "\n" +
+               "   3. Grant of Patent License. Subject to the terms and 
conditions of\n" +
+               "      this License, each Contributor hereby grants to You a 
perpetual,\n" +
+               "      worldwide, non-exclusive, no-charge, royalty-free, 
irrevocable\n" +
+               "      (except as stated in this section) patent license to 
make, have made,\n" +
+               "      use, offer to sell, sell, import, and otherwise transfer 
the Work,\n" +
+               "      where such license applies only to those patent claims 
licensable\n" +
+               "      by such Contributor that are necessarily infringed by 
their\n" +
+               "      Contribution(s) alone or by combination of their 
Contribution(s)\n" +
+               "      with the Work to which such Contribution(s) was 
submitted. If You\n" +
+               "      institute patent litigation against any entity 
(including a\n" +
+               "      cross-claim or counterclaim in a lawsuit) alleging that 
the Work\n" +
+               "      or a Contribution incorporated within the Work 
constitutes direct\n" +
+               "      or contributory patent infringement, then any patent 
licenses\n" +
+               "      granted to You under this License for that Work shall 
terminate\n" +
+               "      as of the date such litigation is filed.\n" +
+               "\n" +
+               "   4. Redistribution. You may reproduce and distribute copies 
of the\n" +
+               "      Work or Derivative Works thereof in any medium, with or 
without\n" +
+               "      modifications, and in Source or Object form, provided 
that You\n" +
+               "      meet the following conditions:\n" +
+               "\n" +
+               "      (a) You must give any other recipients of the Work or\n" 
+
+               "          Derivative Works a copy of this License; and\n" +
+               "\n" +
+               "      (b) You must cause any modified files to carry prominent 
notices\n" +
+               "          stating that You changed the files; and\n" +
+               "\n" +
+               "      (c) You must retain, in the Source form of any 
Derivative Works\n" +
+               "          that You distribute, all copyright, patent, 
trademark, and\n" +
+               "          attribution notices from the Source form of the 
Work,\n" +
+               "          excluding those notices that do not pertain to any 
part of\n" +
+               "          the Derivative Works; and\n" +
+               "\n" +
+               "      (d) If the Work includes a \"NOTICE\" text file as part 
of its\n" +
+               "          distribution, then any Derivative Works that You 
distribute must\n" +
+               "          include a readable copy of the attribution notices 
contained\n" +
+               "          within such NOTICE file, excluding those notices 
that do not\n" +
+               "          pertain to any part of the Derivative Works, in at 
least one\n" +
+               "          of the following places: within a NOTICE text file 
distributed\n" +
+               "          as part of the Derivative Works; within the Source 
form or\n" +
+               "          documentation, if provided along with the Derivative 
Works; or,\n" +
+               "          within a display generated by the Derivative Works, 
if and\n" +
+               "          wherever such third-party notices normally appear. 
The contents\n" +
+               "          of the NOTICE file are for informational purposes 
only and\n" +
+               "          do not modify the License. You may add Your own 
attribution\n" +
+               "          notices within Derivative Works that You distribute, 
alongside\n" +
+               "          or as an addendum to the NOTICE text from the Work, 
provided\n" +
+               "          that such additional attribution notices cannot be 
construed\n" +
+               "          as modifying the License.\n" +
+               "\n" +
+               "      You may add Your own copyright statement to Your 
modifications and\n" +
+               "      may provide additional or different license terms and 
conditions\n" +
+               "      for use, reproduction, or distribution of Your 
modifications, or\n" +
+               "      for any such Derivative Works as a whole, provided Your 
use,\n" +
+               "      reproduction, and distribution of the Work otherwise 
complies with\n" +
+               "      the conditions stated in this License.\n" +
+               "\n" +
+               "   5. Submission of Contributions. Unless You explicitly state 
otherwise,\n" +
+               "      any Contribution intentionally submitted for inclusion 
in the Work\n" +
+               "      by You to the Licensor shall be under the terms and 
conditions of\n" +
+               "      this License, without any additional terms or 
conditions.\n" +
+               "      Notwithstanding the above, nothing herein shall 
supersede or modify\n" +
+               "      the terms of any separate license agreement you may have 
executed\n" +
+               "      with Licensor regarding such Contributions.\n" +
+               "\n" +
+               "   6. Trademarks. This License does not grant permission to 
use the trade\n" +
+               "      names, trademarks, service marks, or product names of 
the Licensor,\n" +
+               "      except as required for reasonable and customary use in 
describing the\n" +
+               "      origin of the Work and reproducing the content of the 
NOTICE file.\n" +
+               "\n" +
+               "   7. Disclaimer of Warranty. Unless required by applicable 
law or\n" +
+               "      agreed to in writing, Licensor provides the Work (and 
each\n" +
+               "      Contributor provides its Contributions) on an \"AS IS\" 
BASIS,\n" +
+               "      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 
express or\n" +
+               "      implied, including, without limitation, any warranties 
or conditions\n" +
+               "      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS 
FOR A\n" +
+               "      PARTICULAR PURPOSE. You are solely responsible for 
determining the\n" +
+               "      appropriateness of using or redistributing the Work and 
assume any\n" +
+               "      risks associated with Your exercise of permissions under 
this License.\n" +
+               "\n" +
+               "   8. Limitation of Liability. In no event and under no legal 
theory,\n" +
+               "      whether in tort (including negligence), contract, or 
otherwise,\n" +
+               "      unless required by applicable law (such as deliberate 
and grossly\n" +
+               "      negligent acts) or agreed to in writing, shall any 
Contributor be\n" +
+               "      liable to You for damages, including any direct, 
indirect, special,\n" +
+               "      incidental, or consequential damages of any character 
arising as a\n" +
+               "      result of this License or out of the use or inability to 
use the\n" +
+               "      Work (including but not limited to damages for loss of 
goodwill,\n" +
+               "      work stoppage, computer failure or malfunction, or any 
and all\n" +
+               "      other commercial damages or losses), even if such 
Contributor\n" +
+               "      has been advised of the possibility of such damages.\n" +
+               "\n" +
+               "   9. Accepting Warranty or Additional Liability. While 
redistributing\n" +
+               "      the Work or Derivative Works thereof, You may choose to 
offer,\n" +
+               "      and charge a fee for, acceptance of support, warranty, 
indemnity,\n" +
+               "      or other liability obligations and/or rights consistent 
with this\n" +
+               "      License. However, in accepting such obligations, You may 
act only\n" +
+               "      on Your own behalf and on Your sole responsibility, not 
on behalf\n" +
+               "      of any other Contributor, and only if You agree to 
indemnify,\n" +
+               "      defend, and hold each Contributor harmless for any 
liability\n" +
+               "      incurred by, or claims asserted against, such 
Contributor by reason\n" +
+               "      of your accepting any such warranty or additional 
liability.\n" +
+               "\n" +
+               "   END OF TERMS AND CONDITIONS\n" +
+               "\n" +
+               "   APPENDIX: How to apply the Apache License to your work.\n" +
+               "\n" +
+               "      To apply the Apache License to your work, attach the 
following\n" +
+               "      boilerplate notice, with the fields enclosed by brackets 
\"[]\"\n" +
+               "      replaced with your own identifying information. (Don't 
include\n" +
+               "      the brackets!)  The text should be enclosed in the 
appropriate\n" +
+               "      comment syntax for the file format. We also recommend 
that a\n" +
+               "      file or class name and description of purpose be 
included on the\n" +
+               "      same \"printed page\" as the copyright notice for 
easier\n" +
+               "      identification within third-party archives.\n" +
+               "\n" +
+               "   Copyright [yyyy] [name of copyright owner]\n" +
+               "\n" +
+               "   Licensed under the Apache License, Version 2.0 (the 
\"License\");\n" +
+               "   you may not use this file except in compliance with the 
License.\n" +
+               "   You may obtain a copy of the License at\n" +
+               "\n" +
+               "       http://www.apache.org/licenses/LICENSE-2.0\n"; +
+               "\n" +
+               "   Unless required by applicable law or agreed to in writing, 
software\n" +
+               "   distributed under the License is distributed on an \"AS 
IS\" BASIS,\n" +
+               "   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 
express or implied.\n" +
+               "   See the License for the specific language governing 
permissions and\n" +
+               "   limitations under the License.\n";
+
+}
diff --git a/tools/ci/license_check.sh b/tools/ci/license_check.sh
index 5a8b87f..34f0916 100755
--- a/tools/ci/license_check.sh
+++ b/tools/ci/license_check.sh
@@ -20,12 +20,13 @@
 MVN_CLEAN_COMPILE_OUT=$1
 CI_DIR=$2
 FLINK_ROOT=$3
+FLINK_DEPLOYED_ROOT=$4
 
 source "${CI_DIR}/maven-utils.sh"
 
 cd $CI_DIR/java-ci-tools/
 
-run_mvn exec:java 
-Dexec.mainClass=org.apache.flink.tools.ci.licensecheck.LicenseChecker 
-Dexec.args=\"$MVN_CLEAN_COMPILE_OUT $FLINK_ROOT\"
+run_mvn exec:java 
-Dexec.mainClass=org.apache.flink.tools.ci.licensecheck.LicenseChecker 
-Dexec.args=\"$MVN_CLEAN_COMPILE_OUT $FLINK_ROOT $FLINK_DEPLOYED_ROOT\"
 EXIT_CODE=$?
 
 if [ $EXIT_CODE != 0 ]; then

Reply via email to