This is an automated email from the ASF dual-hosted git repository.
XiaoHongbo-Hope pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/paimon-mosaic.git
The following commit(s) were added to refs/heads/main by this push:
new f38fb7f fix(release): include third-party licenses in binary LICENSE
files (#101)
f38fb7f is described below
commit f38fb7f9e1c94865f4318fa6f620a538773c9bad
Author: jianguotian <[email protected]>
AuthorDate: Wed Oct 21 10:16:14 2026 +0800
fix(release): include third-party licenses in binary LICENSE files (#101)
* fix(release): include third-party licenses in binary LICENSE files
* fix(release): narrow RC verification changes
* docs(release): keep RC instructions focused
---------
Co-authored-by: mingfeng <[email protected]>
---
docs/verifying-a-release-candidate.html | 6 +-
java/pom.xml | 1 +
java/src/main/binary-resources/META-INF/LICENSE | 438 +++++++++++++++++++++++-
python/setup.py | 12 +-
python/tests/test_packaging.py | 7 +-
tools/generate_license_reports.py | 12 +-
tools/tests/test_generate_license_reports.py | 18 +
tools/tests/test_verify_binary_artifact.py | 129 +++++++
tools/verify_binary_artifact.py | 24 +-
9 files changed, 620 insertions(+), 27 deletions(-)
diff --git a/docs/verifying-a-release-candidate.html
b/docs/verifying-a-release-candidate.html
index fb1d44f..f003408 100644
--- a/docs/verifying-a-release-candidate.html
+++ b/docs/verifying-a-release-candidate.html
@@ -209,8 +209,10 @@ paimon-mosaic-core = { git =
"https://github.com/apache/paimon-mosaic", tag = "v
</ol>
<h3>Python (TestPyPI)</h3>
- <p>The RC tag publishes wheels to TestPyPI after the Rust and Java
release jobs succeed. Install and verify:</p>
-<pre><code>pip install -i https://test.pypi.org/simple/
paimon-mosaic==${RELEASE_VERSION}rc${RC_NUM}
+ <p>The RC tag publishes wheels to TestPyPI after the Rust and Java
release jobs succeed. In a fresh virtual environment, install dependencies from
PyPI first, then install the exact RC wheel from TestPyPI without resolving
dependencies there:</p>
+<pre><code>python -m pip install --index-url https://pypi.org/simple/ pyarrow
+python -m pip install --no-deps --index-url https://test.pypi.org/simple/
paimon-mosaic==${RELEASE_VERSION}rc${RC_NUM}
+python -m pip check
python -c "import mosaic; print('OK')"</code></pre>
<p>Verify wheels are available for: Linux x86_64, Linux aarch64,
macOS aarch64, Windows x86_64.</p>
diff --git a/java/pom.xml b/java/pom.xml
index 438ac23..cff0f76 100644
--- a/java/pom.xml
+++ b/java/pom.xml
@@ -141,6 +141,7 @@
<directory>src/main/binary-resources</directory>
<filtering>false</filtering>
<includes>
+
<include>META-INF/LICENSE</include>
<include>META-INF/NOTICE</include>
</includes>
</resource>
diff --git a/java/src/main/binary-resources/META-INF/LICENSE
b/java/src/main/binary-resources/META-INF/LICENSE
index ffcce7d..215ba9d 100644
--- a/java/src/main/binary-resources/META-INF/LICENSE
+++ b/java/src/main/binary-resources/META-INF/LICENSE
@@ -200,15 +200,429 @@
See the License for the specific language governing permissions and
limitations under the License.
-===============================================================================
-BUNDLED THIRD-PARTY COMPONENTS
-===============================================================================
-
-This binary JAR bundles Rust native libraries for four release targets.
-The component inventory, copyright notices, and complete license texts
-are provided in:
-
- META-INF/licenses/x86_64-unknown-linux-gnu/THIRD-PARTY-LICENSES.html
- META-INF/licenses/aarch64-unknown-linux-gnu/THIRD-PARTY-LICENSES.html
- META-INF/licenses/aarch64-apple-darwin/THIRD-PARTY-LICENSES.html
- META-INF/licenses/x86_64-pc-windows-msvc/THIRD-PARTY-LICENSES.html
+Apache Paimon Mosaic Java binary distributions
+===============================================
+
+The Java JAR includes the compiled paimon-mosaic-jni Rust dependency closure
+and the Rust standard library.
+
+Except for the components listed below, Apache Paimon Mosaic selects the
+Apache License, Version 2.0 option for dependencies that offer it. The full
+Apache License, Version 2.0 text is in LICENSE.
+
+arrow-array 58.4.0
+------------------
+
+This component is distributed under both the Apache License, Version 2.0 and
+the following MIT license.
+
+MIT License
+
+Copyright (c) 2020-2022 Oliver Margetts
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in 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.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+bytes 1.12.1
+------------
+
+Copyright (c) 2018 Carl Lerche
+
+Permission is hereby granted, free of charge, to any
+person obtaining a copy of this software and associated
+documentation files (the "Software"), to deal in 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.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
+ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
+TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
+PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
+SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
+IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+combine 4.6.7
+-------------
+
+The MIT License (MIT)
+
+Copyright (c) 2015 Markus Westerlind
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in 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.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+crunchy 0.2.4
+-------------
+
+The MIT License (MIT)
+
+Copyright 2017-2023 Eira Fransham.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in 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.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+libm 0.2.16
+-----------
+
+This component is distributed under the following MIT license option.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in 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.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+This Rust library contains the following copyrights:
+
+ Copyright (c) 2018 Jorge Aparicio
+
+Portions of this software are derived from third-party works licensed under
+terms compatible with the above MIT license:
+
+* musl libc https://www.musl-libc.org/. This library contains the following
+ copyright:
+
+ Copyright © 2005-2020 Rich Felker, et al.
+
+* The CORE-MATH project https://core-math.gitlabpages.inria.fr/. CORE-MATH
+ routines are available under the MIT license on a per-file basis.
+
+The musl libc COPYRIGHT file also includes the following notice relevant to
+math portions of the library:
+
+Much of the math library code (src/math/* and src/complex/*) is
+Copyright © 1993,2004 Sun Microsystems or
+Copyright © 2003-2011 David Schultz or
+Copyright © 2003-2009 Steven G. Kargl or
+Copyright © 2003-2009 Bruce D. Evans or
+Copyright © 2008 Stephen L. Moshier or
+Copyright © 2017-2018 Arm Limited
+and labelled as such in comments in the individual source files. All
+have been licensed under extremely permissive terms.
+
+Copyright notices are retained in src/* files where relevant.
+
+memchr 2.8.3
+------------
+
+This component is distributed under the following MIT license option.
+
+The MIT License (MIT)
+
+Copyright (c) 2015 Andrew Gallant
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in 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.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+tiny-keccak 2.0.2
+-----------------
+
+Creative Commons Legal Code
+
+CC0 1.0 Universal
+
+ CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE
+ LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN
+ ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS
+ INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES
+ REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS
+ PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM
+ THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED
+ HEREUNDER.
+
+Statement of Purpose
+
+The laws of most jurisdictions throughout the world automatically confer
+exclusive Copyright and Related Rights (defined below) upon the creator
+and subsequent owner(s) (each and all, an "owner") of an original work of
+authorship and/or a database (each, a "Work").
+
+Certain owners wish to permanently relinquish those rights to a Work for
+the purpose of contributing to a commons of creative, cultural and
+scientific works ("Commons") that the public can reliably and without fear
+of later claims of infringement build upon, modify, incorporate in other
+works, reuse and redistribute as freely as possible in any form whatsoever
+and for any purposes, including without limitation commercial purposes.
+These owners may contribute to the Commons to promote the ideal of a free
+culture and the further production of creative, cultural and scientific
+works, or to gain reputation or greater distribution for their Work in
+part through the use and efforts of others.
+
+For these and/or other purposes and motivations, and without any
+expectation of additional consideration or compensation, the person
+associating CC0 with a Work (the "Affirmer"), to the extent that he or she
+is an owner of Copyright and Related Rights in the Work, voluntarily
+elects to apply CC0 to the Work and publicly distribute the Work under its
+terms, with knowledge of his or her Copyright and Related Rights in the
+Work and the meaning and intended legal effect of CC0 on those rights.
+
+1. Copyright and Related Rights. A Work made available under CC0 may be
+protected by copyright and related or neighboring rights ("Copyright and
+Related Rights"). Copyright and Related Rights include, but are not
+limited to, the following:
+
+ i. the right to reproduce, adapt, distribute, perform, display,
+ communicate, and translate a Work;
+ ii. moral rights retained by the original author(s) and/or performer(s);
+iii. publicity and privacy rights pertaining to a person's image or
+ likeness depicted in a Work;
+ iv. rights protecting against unfair competition in regards to a Work,
+ subject to the limitations in paragraph 4(a), below;
+ v. rights protecting the extraction, dissemination, use and reuse of data
+ in a Work;
+ vi. database rights (such as those arising under Directive 96/9/EC of the
+ European Parliament and of the Council of 11 March 1996 on the legal
+ protection of databases, and under any national implementation
+ thereof, including any amended or successor version of such
+ directive); and
+vii. other similar, equivalent or corresponding rights throughout the
+ world based on applicable law or treaty, and any national
+ implementations thereof.
+
+2. Waiver. To the greatest extent permitted by, but not in contravention
+of, applicable law, Affirmer hereby overtly, fully, permanently,
+irrevocably and unconditionally waives, abandons, and surrenders all of
+Affirmer's Copyright and Related Rights and associated claims and causes
+of action, whether now known or unknown (including existing as well as
+future claims and causes of action), in the Work (i) in all territories
+worldwide, (ii) for the maximum duration provided by applicable law or
+treaty (including future time extensions), (iii) in any current or future
+medium and for any number of copies, and (iv) for any purpose whatsoever,
+including without limitation commercial, advertising or promotional
+purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each
+member of the public at large and to the detriment of Affirmer's heirs and
+successors, fully intending that such Waiver shall not be subject to
+revocation, rescission, cancellation, termination, or any other legal or
+equitable action to disrupt the quiet enjoyment of the Work by the public
+as contemplated by Affirmer's express Statement of Purpose.
+
+3. Public License Fallback. Should any part of the Waiver for any reason
+be judged legally invalid or ineffective under applicable law, then the
+Waiver shall be preserved to the maximum extent permitted taking into
+account Affirmer's express Statement of Purpose. In addition, to the
+extent the Waiver is so judged Affirmer hereby grants to each affected
+person a royalty-free, non transferable, non sublicensable, non exclusive,
+irrevocable and unconditional license to exercise Affirmer's Copyright and
+Related Rights in the Work (i) in all territories worldwide, (ii) for the
+maximum duration provided by applicable law or treaty (including future
+time extensions), (iii) in any current or future medium and for any number
+of copies, and (iv) for any purpose whatsoever, including without
+limitation commercial, advertising or promotional purposes (the
+"License"). The License shall be deemed effective as of the date CC0 was
+applied by Affirmer to the Work. Should any part of the License for any
+reason be judged legally invalid or ineffective under applicable law, such
+partial invalidity or ineffectiveness shall not invalidate the remainder
+of the License, and in such case Affirmer hereby affirms that he or she
+will not (i) exercise any of his or her remaining Copyright and Related
+Rights in the Work or (ii) assert any associated claims and causes of
+action with respect to the Work, in either case contrary to Affirmer's
+express Statement of Purpose.
+
+4. Limitations and Disclaimers.
+
+ a. No trademark or patent rights held by Affirmer are waived, abandoned,
+ surrendered, licensed or otherwise affected by this document.
+ b. Affirmer offers the Work as-is and makes no representations or
+ warranties of any kind concerning the Work, express, implied,
+ statutory or otherwise, including without limitation warranties of
+ title, merchantability, fitness for a particular purpose, non
+ infringement, or the absence of latent or other defects, accuracy, or
+ the present or absence of errors, whether or not discoverable, all to
+ the greatest extent permissible under applicable law.
+ c. Affirmer disclaims responsibility for clearing rights of other persons
+ that may apply to the Work or any use thereof, including without
+ limitation any person's Copyright and Related Rights in the Work.
+ Further, Affirmer disclaims responsibility for obtaining any necessary
+ consents, permissions or other rights required for any use of the
+ Work.
+ d. Affirmer understands and acknowledges that Creative Commons is not a
+ party to this document and has no duty or obligation with respect to
+ this CC0 or use of the Work.
+
+unicode-ident 1.0.24 and Rust standard library 1.97.1
+---------------------------------------------------
+
+The Rust code is distributed under the Apache License, Version 2.0 option.
+Unicode data from unicode-ident has Copyright © 1991-2023 Unicode, Inc.
+Unicode data from the Rust standard library has
+Copyright © 1991-2024 Unicode, Inc. Both are additionally covered by the
+following Unicode License V3.
+
+UNICODE LICENSE V3
+
+COPYRIGHT AND PERMISSION NOTICE
+
+NOTICE TO USER: Carefully read the following legal agreement. BY
+DOWNLOADING, INSTALLING, COPYING OR OTHERWISE USING DATA FILES, AND/OR
+SOFTWARE, YOU UNEQUIVOCALLY ACCEPT, AND AGREE TO BE BOUND BY, ALL OF THE
+TERMS AND CONDITIONS OF THIS AGREEMENT. IF YOU DO NOT AGREE, DO NOT
+DOWNLOAD, INSTALL, COPY, DISTRIBUTE OR USE THE DATA FILES OR SOFTWARE.
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of data files and any associated documentation (the "Data Files") or
+software and any associated documentation (the "Software") to deal in the
+Data Files or Software without restriction, including without limitation
+the rights to use, copy, modify, merge, publish, distribute, and/or sell
+copies of the Data Files or Software, and to permit persons to whom the
+Data Files or Software are furnished to do so, provided that either (a)
+this copyright and permission notice appear with all copies of the Data
+Files or Software, or (b) this copyright and permission notice appear in
+associated Documentation.
+
+THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
+THIRD PARTY RIGHTS.
+
+IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS NOTICE
+BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES,
+OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THE DATA
+FILES OR SOFTWARE.
+
+Except as contained in this notice, the name of a copyright holder shall
+not be used in advertising or otherwise to promote the sale, use or other
+dealings in these Data Files or Software without prior written
+authorization of the copyright holder.
+
+zstd 0.13.3
+-----------
+
+The MIT License (MIT)
+Copyright (c) 2016 Alexandre Bury
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in 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.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+zstd-sys 2.0.16+zstd.1.5.7 (vendored Zstandard 1.5.7)
+-----------------------------------------------------
+
+BSD License
+
+For Zstandard software
+
+Copyright (c) Meta Platforms, Inc. and affiliates. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
modification,
+are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ * Neither the name Facebook, nor Meta, nor the names of its contributors may
+ be used to endorse or promote products derived from this software without
+ specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/python/setup.py b/python/setup.py
index 8180fdf..7438653 100644
--- a/python/setup.py
+++ b/python/setup.py
@@ -73,9 +73,14 @@ def _stage_legal_files(destination_dir):
source = os.path.join(here, name)
if not os.path.isfile(source):
raise RuntimeError(f"required binary legal file is missing:
{source}")
+ with open(source, "rb") as source_file:
+ source_bytes = source_file.read()
+ if name == "LICENSE" and source == os.path.join(here, "../LICENSE"):
+ # Build the primary binary LICENSE from the maintained inventory.
+ # An sdist already carries this combined file; do not append twice.
+ with open(os.path.join(here, "../LICENSE-binary-ffi"), "rb") as
licenses:
+ source_bytes = source_bytes.rstrip() + b"\n\n" +
licenses.read()
if os.path.exists(destination):
- with open(source, "rb") as source_file:
- source_bytes = source_file.read()
with open(destination, "rb") as destination_file:
destination_bytes = destination_file.read()
if source_bytes != destination_bytes:
@@ -83,7 +88,8 @@ def _stage_legal_files(destination_dir):
f"staged binary legal file does not match source:
{destination}"
)
continue
- shutil.copy2(source, destination)
+ with open(destination, "wb") as destination_file:
+ destination_file.write(source_bytes)
staged.append(destination)
return staged
diff --git a/python/tests/test_packaging.py b/python/tests/test_packaging.py
index bd2904f..e7f5980 100644
--- a/python/tests/test_packaging.py
+++ b/python/tests/test_packaging.py
@@ -63,8 +63,13 @@ def
test_sdist_to_wheel_preserves_canonical_legal_files(tmp_path):
with tarfile.open(sdist) as archive:
prefix = sdist.name.removesuffix(".tar.gz")
for name, source in legal_sources.items():
+ expected = (ROOT / source).read_bytes()
+ if name == "LICENSE":
+ expected = expected.rstrip() + b"\n\n" + (
+ ROOT / "LICENSE-binary-ffi"
+ ).read_bytes()
with archive.extractfile(f"{prefix}/{name}") as legal_file:
- assert legal_file.read() == (ROOT / source).read_bytes()
+ assert legal_file.read() == expected
wheel, = (package / "dist").glob("*.whl")
result = subprocess.run(
diff --git a/tools/generate_license_reports.py
b/tools/generate_license_reports.py
index d7c5d6a..6e02908 100755
--- a/tools/generate_license_reports.py
+++ b/tools/generate_license_reports.py
@@ -440,14 +440,10 @@ def generated_files(root: Path) -> dict[Path, str]:
apache_license = (root / "LICENSE").read_text(encoding="utf-8")
project_notice = (root / "NOTICE").read_text(encoding="utf-8")
- java_report_paths = [
- f"META-INF/licenses/{target}/THIRD-PARTY-LICENSES.html"
- for target in TARGETS
- ]
- java_license = binary_license(
- apache_license,
- "This binary JAR bundles Rust native libraries for four release
targets.",
- java_report_paths,
+ java_license = (
+ apache_license.rstrip()
+ + "\n\n"
+ + (root / "LICENSE-binary").read_text(encoding="utf-8")
)
result[
root / "java/src/main/binary-resources/META-INF/LICENSE"
diff --git a/tools/tests/test_generate_license_reports.py
b/tools/tests/test_generate_license_reports.py
index cf789f9..febb1fd 100644
--- a/tools/tests/test_generate_license_reports.py
+++ b/tools/tests/test_generate_license_reports.py
@@ -67,3 +67,21 @@ def test_generate_removes_obsolete_target_report(tmp_path:
Path) -> None:
assert expected.read_text(encoding="utf-8") == "current\n"
assert not obsolete.exists()
+
+
+def test_java_license_contains_the_packaged_inventory(tmp_path, monkeypatch):
+ (tmp_path / "LICENSE").write_text("Apache license\n", encoding="utf-8")
+ (tmp_path / "LICENSE-binary").write_text(
+ "Bundled JNI component license\n", encoding="utf-8"
+ )
+ (tmp_path / "NOTICE").write_text("Project notice\n", encoding="utf-8")
+ monkeypatch.setattr(generator, "verify_cargo_about", lambda root: None)
+ monkeypatch.setattr(generator, "generate_base_report", lambda *args:
"report")
+ monkeypatch.setattr(generator, "cargo_metadata", lambda *args: {})
+ monkeypatch.setattr(generator, "third_party_notices", lambda *args: ())
+ monkeypatch.setattr(generator, "complete_report", lambda *args: "report")
+
+ files = generator.generated_files(tmp_path)
+ assert files[tmp_path / "java/src/main/binary-resources/META-INF/LICENSE"]
== (
+ "Apache license\n\nBundled JNI component license\n"
+ )
diff --git a/tools/tests/test_verify_binary_artifact.py
b/tools/tests/test_verify_binary_artifact.py
new file mode 100644
index 0000000..deb54bc
--- /dev/null
+++ b/tools/tests/test_verify_binary_artifact.py
@@ -0,0 +1,129 @@
+# 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.
+
+from pathlib import Path
+import sys
+import zipfile
+
+import pytest
+
+
+sys.path.insert(0, str(Path(__file__).resolve().parents[1]))
+import verify_binary_artifact as verifier # noqa: E402
+
+
[email protected]
+def repository(tmp_path, monkeypatch):
+ root = tmp_path / "repository"
+ root.mkdir()
+ for name, content in {
+ "LICENSE": b"Apache license\n",
+ "LICENSE-binary": b"JNI third-party licenses\n",
+ "LICENSE-binary-ffi": b"FFI third-party licenses\n",
+ "java/src/main/binary-resources/META-INF/NOTICE": b"Binary notices\n",
+ }.items():
+ path = root / name
+ path.parent.mkdir(parents=True, exist_ok=True)
+ path.write_bytes(content)
+ monkeypatch.setattr(verifier, "ROOT", root)
+ return root
+
+
+def jar_entries():
+ return {
+ "META-INF/LICENSE": b"Apache license\n\nJNI third-party licenses\n",
+ "META-INF/LICENSE-binary": b"JNI third-party licenses\n",
+ "META-INF/NOTICE": b"Binary notices\n",
+ "META-INF/DEPENDENCIES": b"Dependencies\n",
+ "org/apache/paimon/mosaic/NativeLib.class": b"class",
+ **{name: b"native" for name in verifier.JAR_NATIVE_FILES},
+ }
+
+
+def wheel_entries():
+ return {
+ "mosaic-0.3.0.dist-info/METADATA": b"Name: paimon-mosaic\nVersion:
0.3.0\n",
+ "mosaic/libpaimon_mosaic_ffi.so": b"native",
+ **{
+ f"{prefix}/{name}": content
+ for prefix in ("mosaic", "mosaic-0.3.0.dist-info/licenses")
+ for name, content in {
+ "LICENSE": b"Apache license\n\nFFI third-party licenses\n",
+ "LICENSE-binary": b"FFI third-party licenses\n",
+ "NOTICE": b"Binary notices\n",
+ }.items()
+ },
+ }
+
+
+def verify_archive(tmp_path, kind, entries):
+ artifact = tmp_path / f"artifact.{kind}"
+ with zipfile.ZipFile(artifact, "w") as archive:
+ for name, content in entries.items():
+ archive.writestr(name, content)
+ if kind == "jar":
+ verifier.verify_jar(artifact, verifier.JAR_NATIVE_FILES)
+ else:
+ verifier.verify_wheel(artifact)
+
+
[email protected]("kind,entries", [("jar", jar_entries()), ("whl",
wheel_entries())])
+def test_accepts_complete_binary_license(repository, tmp_path, kind, entries):
+ verify_archive(tmp_path, kind, entries)
+
+
[email protected](
+ "kind,entry",
+ [
+ ("jar", "META-INF/LICENSE"),
+ ("whl", "mosaic/LICENSE"),
+ ("whl", "mosaic-0.3.0.dist-info/licenses/LICENSE"),
+ ],
+)
[email protected](
+ "license_content",
+ [
+ b"Apache license\n",
+ b"Apache license\n\nSee missing/THIRD-PARTY-LICENSES.html\n",
+ b"Apache license\n\nOutdated third-party inventory\n",
+ ],
+)
+def test_rejects_incomplete_primary_license(
+ repository, tmp_path, kind, entry, license_content
+):
+ entries = jar_entries() if kind == "jar" else wheel_entries()
+ entries[entry] = license_content
+ with pytest.raises(ValueError, match="complete third-party license
inventory"):
+ verify_archive(tmp_path, kind, entries)
+
+
[email protected](
+ "kind,entry",
+ [("jar", "META-INF/LICENSE-binary"), ("whl", "mosaic/LICENSE-binary")],
+)
+def test_still_rejects_missing_inventory(repository, tmp_path, kind, entry):
+ entries = jar_entries() if kind == "jar" else wheel_entries()
+ del entries[entry]
+ with pytest.raises(ValueError, match="missing entries"):
+ verify_archive(tmp_path, kind, entries)
+
+
+def test_rejects_stale_java_license_before_resolving_dependencies(repository):
+ path = repository / "java/src/main/binary-resources/META-INF/LICENSE"
+ path.write_bytes(b"Apache license\n")
+ with pytest.raises(ValueError, match="Java binary LICENSE is stale"):
+ verifier.verify_source_legal_inventory()
diff --git a/tools/verify_binary_artifact.py b/tools/verify_binary_artifact.py
index e3685a9..bde4096 100644
--- a/tools/verify_binary_artifact.py
+++ b/tools/verify_binary_artifact.py
@@ -31,7 +31,6 @@ from pathlib import Path
ROOT = Path(__file__).resolve().parent.parent
LEGAL_FILES = ("LICENSE", "NOTICE", "LICENSE-binary")
WHEEL_LEGAL_SOURCES = {
- "LICENSE": "LICENSE",
"NOTICE": "java/src/main/binary-resources/META-INF/NOTICE",
"LICENSE-binary": "LICENSE-binary-ffi",
}
@@ -79,6 +78,20 @@ def require_canonical_content(archive, artifact,
archive_prefix, sources):
raise ValueError(f"{artifact}!/{entry} does not match repository
{source}")
+def binary_license_content(inventory):
+ return (ROOT / "LICENSE").read_bytes().rstrip() + b"\n\n" + (
+ ROOT / inventory
+ ).read_bytes()
+
+
+def require_binary_license(archive, artifact, entry, inventory):
+ if archive.read(entry) != binary_license_content(inventory):
+ raise ValueError(
+ f"{artifact}!/{entry} must contain the Apache license and the "
+ f"complete third-party license inventory from {inventory}"
+ )
+
+
def verify_wheel(artifact):
with zipfile.ZipFile(artifact) as archive:
names = archive.namelist()
@@ -91,6 +104,8 @@ def verify_wheel(artifact):
dist_legal = [f"{dist_info}licenses/{name}" for name in LEGAL_FILES]
package_legal = [f"mosaic/{name}" for name in LEGAL_FILES]
require_entries(archive, artifact, dist_legal + package_legal)
+ for entry in ("mosaic/LICENSE", f"{dist_info}licenses/LICENSE"):
+ require_binary_license(archive, artifact, entry,
"LICENSE-binary-ffi")
require_canonical_content(
archive, artifact, "mosaic", WHEEL_LEGAL_SOURCES
)
@@ -126,6 +141,7 @@ def verify_jar(artifact, native_files):
"org/apache/paimon/mosaic/NativeLib.class",
) + tuple(native_files)
require_entries(archive, artifact, required)
+ require_binary_license(archive, artifact, "META-INF/LICENSE",
"LICENSE-binary")
require_canonical_content(
archive,
artifact,
@@ -187,6 +203,12 @@ def resolved_runtime_dependencies(metadata, root_name):
def verify_source_legal_inventory():
+ java_license = ROOT / "java/src/main/binary-resources/META-INF/LICENSE"
+ if java_license.read_bytes() != binary_license_content("LICENSE-binary"):
+ raise ValueError(
+ "Java binary LICENSE is stale: regenerate it from LICENSE and "
+ "LICENSE-binary with tools/generate_license_reports.py"
+ )
metadata_by_target = [cargo_metadata(target) for target in
SUPPORTED_TARGETS]
for root_name, license_name in (
("paimon-mosaic-ffi", "LICENSE-binary-ffi"),