This is an automated email from the ASF dual-hosted git repository.
JingsongLi 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 12c5a43 fix(release): package complete native license files (#97)
12c5a43 is described below
commit 12c5a436f0eef0a5761eee189904e2dd2ef92690
Author: jianguotian <[email protected]>
AuthorDate: Thu Sep 24 16:37:16 2026 +0800
fix(release): package complete native license files (#97)
---
.gitattributes | 2 +-
.github/workflows/ci.yml | 5 +-
.github/workflows/release-java.yml | 20 +-
.github/workflows/release-python-publish.yml | 5 +
.github/workflows/release-python.yml | 19 ++
LICENSE-binary | 426 +++++++++++++++++++++++++++
LICENSE-binary-ffi | 374 +++++++++++++++++++++++
java/pom.xml | 37 +++
python/pyproject.toml | 16 +-
python/setup.py | 60 +++-
python/tests/test_packaging.py | 81 +++++
tools/check_license_headers.py | 2 +
tools/deploy_java_staging.sh | 6 +-
tools/tests/deploy_java_staging_test.sh | 14 +
tools/tests/test_release_vote_workflow.py | 20 ++
tools/verify_binary_artifact.py | 281 ++++++++++++++++++
16 files changed, 1343 insertions(+), 25 deletions(-)
diff --git a/.gitattributes b/.gitattributes
index 95a71ce..10b43bb 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -17,5 +17,5 @@
# operating systems are collected by the publish job.
*.html text eol=lf
*.txt text eol=lf
-LICENSE text eol=lf
+LICENSE* text eol=lf
NOTICE text eol=lf
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 9bbab44..8b7c691 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -51,6 +51,9 @@ jobs:
- name: Check dependency licenses (Apache-compatible)
run: cargo deny check licenses
+ - name: Check binary legal inventory
+ run: python3 tools/verify_binary_artifact.py --source
+
- name: Format
run: cargo fmt --all -- --check
@@ -185,7 +188,7 @@ jobs:
- name: Install Python dependencies
working-directory: python
- run: pip install pyarrow pytest
+ run: pip install pyarrow pytest build "setuptools>=77" wheel
- name: Run Python tests
working-directory: python
diff --git a/.github/workflows/release-java.yml
b/.github/workflows/release-java.yml
index b3d2a7f..ffd4573 100644
--- a/.github/workflows/release-java.yml
+++ b/.github/workflows/release-java.yml
@@ -188,24 +188,20 @@ jobs:
test -s "$artifact"
done
- if jar tf "$sources_jar" | grep -Eq '^native/'; then
- echo "Sources JAR contains native resources" >&2
- exit 1
- fi
+ python3 tools/verify_binary_artifact.py --jar "$jar_file"
for entry in \
- org/apache/paimon/mosaic/NativeLib.class \
- native/linux/x86_64/libpaimon_mosaic_jni.so \
- native/linux/aarch64/libpaimon_mosaic_jni.so \
- native/macos/aarch64/libpaimon_mosaic_jni.dylib \
- native/windows/x86_64/paimon_mosaic_jni.dll \
- META-INF/LICENSE \
- META-INF/NOTICE \
- META-INF/DEPENDENCIES
+ META-INF/DEPENDENCIES \
+ org/apache/paimon/mosaic/NativeLib.class
do
jar tf "$jar_file" | grep -qx "$entry"
done
+ if jar tf "$sources_jar" | grep -Eq
'^(native/|META-INF/LICENSE-binary$)'; then
+ echo "Sources JAR contains binary-only resources" >&2
+ exit 1
+ fi
+
java -cp "$jar_file:java/target/test-classes" \
org.apache.paimon.mosaic.MosaicNativeLoaderSmokeTest
diff --git a/.github/workflows/release-python-publish.yml
b/.github/workflows/release-python-publish.yml
index 2dcc5c3..cd23062 100644
--- a/.github/workflows/release-python-publish.yml
+++ b/.github/workflows/release-python-publish.yml
@@ -41,12 +41,17 @@ jobs:
needs: [release-preflight]
runs-on: ubuntu-latest
steps:
+ - uses: actions/checkout@v6
+
- uses: actions/download-artifact@v5
with:
pattern: wheels-*
merge-multiple: true
path: dist
+ - name: Verify wheel legal and native contents
+ run: python3 tools/verify_binary_artifact.py --wheel "dist/*.whl"
+
- name: Verify wheel versions
env:
TAG_NAME: ${{ github.ref_name }}
diff --git a/.github/workflows/release-python.yml
b/.github/workflows/release-python.yml
index 0497f2c..7f4b377 100644
--- a/.github/workflows/release-python.yml
+++ b/.github/workflows/release-python.yml
@@ -75,6 +75,12 @@ jobs:
cargo build --release -p paimon-mosaic-ffi &&
cp target/release/libpaimon_mosaic_ffi.so {package}/mosaic/
+ - name: Verify and load wheel
+ run: |
+ python3 tools/verify_binary_artifact.py --wheel "wheelhouse/*.whl"
+ python -m pip install --force-reinstall wheelhouse/*.whl
+ python -c "import mosaic; print(mosaic.__file__)"
+
- name: Upload wheels
uses: actions/upload-artifact@v5
with:
@@ -133,6 +139,12 @@ jobs:
rm python/dist/*.whl
mv python/dist/repaired/*.whl python/dist/
+ - name: Verify and load wheel
+ run: |
+ python3 tools/verify_binary_artifact.py --wheel "python/dist/*.whl"
+ python -m pip install --force-reinstall python/dist/*.whl
+ python -c "import mosaic; print(mosaic.__file__)"
+
- name: Upload wheel
uses: actions/upload-artifact@v5
with:
@@ -176,6 +188,13 @@ jobs:
working-directory: python
run: python -m build --wheel
+ - name: Verify and load wheel
+ shell: bash
+ run: |
+ python tools/verify_binary_artifact.py --wheel "python/dist/*.whl"
+ python -m pip install --force-reinstall python/dist/*.whl
+ python -c "import mosaic; print(mosaic.__file__)"
+
- name: Upload wheel
uses: actions/upload-artifact@v5
with:
diff --git a/LICENSE-binary b/LICENSE-binary
new file mode 100644
index 0000000..6901fa5
--- /dev/null
+++ b/LICENSE-binary
@@ -0,0 +1,426 @@
+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/LICENSE-binary-ffi b/LICENSE-binary-ffi
new file mode 100644
index 0000000..ed0bf61
--- /dev/null
+++ b/LICENSE-binary-ffi
@@ -0,0 +1,374 @@
+Apache Paimon Mosaic Python binary distributions
+================================================
+
+The Python wheels include the compiled paimon-mosaic-ffi 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.
+
+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.
+
+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/java/pom.xml b/java/pom.xml
index a1259fe..438ac23 100644
--- a/java/pom.xml
+++ b/java/pom.xml
@@ -114,6 +114,41 @@
<id>release</id>
<build>
<plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-resources-plugin</artifactId>
+ <version>3.3.1</version>
+ <executions>
+ <execution>
+ <id>copy-binary-legal-resources</id>
+ <phase>prepare-package</phase>
+ <goals>
+ <goal>copy-resources</goal>
+ </goals>
+ <configuration>
+
<outputDirectory>${project.build.outputDirectory}</outputDirectory>
+ <overwrite>true</overwrite>
+ <resources>
+ <resource>
+
<directory>${project.basedir}/..</directory>
+ <targetPath>META-INF</targetPath>
+ <filtering>false</filtering>
+ <includes>
+
<include>LICENSE-binary</include>
+ </includes>
+ </resource>
+ <resource>
+
<directory>src/main/binary-resources</directory>
+ <filtering>false</filtering>
+ <includes>
+
<include>META-INF/NOTICE</include>
+ </includes>
+ </resource>
+ </resources>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-gpg-plugin</artifactId>
@@ -150,6 +185,8 @@
<configuration>
<excludes>
<exclude>native/**</exclude>
+ <exclude>LICENSE-binary</exclude>
+ <exclude>**/LICENSE-binary</exclude>
</excludes>
</configuration>
</plugin>
diff --git a/python/pyproject.toml b/python/pyproject.toml
index 746ee1c..b9b2e72 100644
--- a/python/pyproject.toml
+++ b/python/pyproject.toml
@@ -16,22 +16,30 @@
# under the License.
[build-system]
-requires = ["setuptools>=64"]
+requires = ["setuptools>=77", "wheel"]
build-backend = "setuptools.build_meta"
[project]
name = "paimon-mosaic"
version = "0.3.0"
description = "Python bindings for the Mosaic columnar-bucket hybrid file
format"
-license = {text = "Apache-2.0"}
+license = "Apache-2.0"
+license-files = ["LICENSE", "NOTICE", "LICENSE-binary"]
requires-python = ">=3.9"
dependencies = ["pyarrow"]
[project.optional-dependencies]
-test = ["pytest"]
+test = ["pytest", "build", "setuptools>=77", "wheel"]
[tool.setuptools.packages.find]
include = ["mosaic*"]
[tool.setuptools.package-data]
-mosaic = ["libpaimon_mosaic_ffi.dylib", "libpaimon_mosaic_ffi.so",
"paimon_mosaic_ffi.dll"]
+mosaic = [
+ "LICENSE",
+ "NOTICE",
+ "LICENSE-binary",
+ "libpaimon_mosaic_ffi.dylib",
+ "libpaimon_mosaic_ffi.so",
+ "paimon_mosaic_ffi.dll",
+]
diff --git a/python/setup.py b/python/setup.py
index d1a6569..8180fdf 100644
--- a/python/setup.py
+++ b/python/setup.py
@@ -15,7 +15,7 @@
# specific language governing permissions and limitations
# under the License.
-"""Build helper: copies the pre-built native library into the package
directory."""
+"""Build helper: stages the native library and binary-distribution legal
files."""
import os
import platform
@@ -26,6 +26,14 @@ from setuptools.command.build_py import build_py
from wheel.bdist_wheel import bdist_wheel
+LEGAL_FILES = ("LICENSE", "NOTICE", "LICENSE-binary")
+LEGAL_SOURCE_FILES = {
+ "LICENSE": "../LICENSE",
+ "NOTICE": "../java/src/main/binary-resources/META-INF/NOTICE",
+ "LICENSE-binary": "../LICENSE-binary-ffi",
+}
+
+
def _lib_name():
system = platform.system()
if system == "Darwin":
@@ -53,6 +61,34 @@ def _find_native_lib():
return None
+def _stage_legal_files(destination_dir):
+ here = os.path.dirname(os.path.abspath(__file__))
+ staged = []
+
+ for name in LEGAL_FILES:
+ source = os.path.join(here, LEGAL_SOURCE_FILES[name])
+ destination = os.path.join(destination_dir, name)
+ if not os.path.isfile(source):
+ # An extracted sdist carries these files alongside setup.py.
+ source = os.path.join(here, name)
+ if not os.path.isfile(source):
+ raise RuntimeError(f"required binary legal file is missing:
{source}")
+ 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:
+ raise RuntimeError(
+ f"staged binary legal file does not match source:
{destination}"
+ )
+ continue
+ shutil.copy2(source, destination)
+ staged.append(destination)
+
+ return staged
+
+
class BuildPyWithNativeLib(build_py):
def run(self):
src = _find_native_lib()
@@ -61,7 +97,14 @@ class BuildPyWithNativeLib(build_py):
os.path.dirname(os.path.abspath(__file__)), "mosaic",
_lib_name()
)
shutil.copy2(src, dst)
- super().run()
+ staged_legal_files = _stage_legal_files(
+ os.path.join(os.path.dirname(os.path.abspath(__file__)), "mosaic")
+ )
+ try:
+ super().run()
+ finally:
+ for path in staged_legal_files:
+ os.remove(path)
class PlatformWheel(bdist_wheel):
@@ -83,7 +126,14 @@ class BinaryDistribution(Distribution):
return True
-setup(
- cmdclass={"build_py": BuildPyWithNativeLib, "bdist_wheel": PlatformWheel},
- distclass=BinaryDistribution,
+staged_distribution_legal_files = _stage_legal_files(
+ os.path.dirname(os.path.abspath(__file__))
)
+try:
+ setup(
+ cmdclass={"build_py": BuildPyWithNativeLib, "bdist_wheel":
PlatformWheel},
+ distclass=BinaryDistribution,
+ )
+finally:
+ for path in staged_distribution_legal_files:
+ os.remove(path)
diff --git a/python/tests/test_packaging.py b/python/tests/test_packaging.py
new file mode 100644
index 0000000..bd2904f
--- /dev/null
+++ b/python/tests/test_packaging.py
@@ -0,0 +1,81 @@
+# 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.
+
+import os
+from pathlib import Path
+import shutil
+import subprocess
+import sys
+import tarfile
+
+from mosaic._ffi import lib
+
+
+ROOT = Path(__file__).resolve().parents[2]
+
+
+def test_sdist_to_wheel_preserves_canonical_legal_files(tmp_path):
+ repository = tmp_path / "repository"
+ package = repository / "python"
+ shutil.copytree(
+ ROOT / "python/mosaic",
+ package / "mosaic",
+ ignore=shutil.ignore_patterns("__pycache__"),
+ )
+ for name in ("setup.py", "pyproject.toml"):
+ shutil.copy2(ROOT / "python" / name, package / name)
+ legal_sources = {
+ "LICENSE": "LICENSE",
+ "NOTICE": "java/src/main/binary-resources/META-INF/NOTICE",
+ "LICENSE-binary": "LICENSE-binary-ffi",
+ }
+ for source in legal_sources.values():
+ destination = repository / source
+ destination.parent.mkdir(parents=True, exist_ok=True)
+ shutil.copy2(ROOT / source, destination)
+
+ # The default build extracts its sdist outside the repository before
+ # building the wheel, so only the bundled legal files remain available.
+ result = subprocess.run(
+ [sys.executable, "-m", "build", "--no-isolation", str(package)],
+ env={**os.environ, "MOSAIC_LIB_PATH":
str(Path(lib._name).resolve().parent)},
+ capture_output=True,
+ text=True,
+ timeout=120,
+ )
+ assert result.returncode == 0, result.stdout + result.stderr
+
+ sdist, = (package / "dist").glob("*.tar.gz")
+ with tarfile.open(sdist) as archive:
+ prefix = sdist.name.removesuffix(".tar.gz")
+ for name, source in legal_sources.items():
+ with archive.extractfile(f"{prefix}/{name}") as legal_file:
+ assert legal_file.read() == (ROOT / source).read_bytes()
+
+ wheel, = (package / "dist").glob("*.whl")
+ result = subprocess.run(
+ [
+ sys.executable,
+ str(ROOT / "tools/verify_binary_artifact.py"),
+ "--wheel",
+ str(wheel),
+ ],
+ capture_output=True,
+ text=True,
+ timeout=30,
+ )
+ assert result.returncode == 0, result.stdout + result.stderr
diff --git a/tools/check_license_headers.py b/tools/check_license_headers.py
index 0ac20cc..a9e8c31 100755
--- a/tools/check_license_headers.py
+++ b/tools/check_license_headers.py
@@ -60,6 +60,8 @@ EXEMPT_FILES = {
"ffi/DEPENDENCIES.rust.tsv",
"jni/DEPENDENCIES.rust.tsv",
"LICENSE",
+ "LICENSE-binary",
+ "LICENSE-binary-ffi",
"NOTICE",
"core/LICENSE",
"core/NOTICE",
diff --git a/tools/deploy_java_staging.sh b/tools/deploy_java_staging.sh
index 8b5dee9..f4737d4 100755
--- a/tools/deploy_java_staging.sh
+++ b/tools/deploy_java_staging.sh
@@ -250,7 +250,7 @@ else
fi
check_java_package_inputs_clean() {
- local paths=(java tools/deploy_java_staging.sh)
+ local paths=(java LICENSE-binary tools/deploy_java_staging.sh
tools/verify_binary_artifact.py)
local untracked
if ! git -C "$REPO_DIR" diff --quiet -- "${paths[@]}" ||
@@ -543,7 +543,7 @@ validate_maven_artifacts() {
done
for artifact in "$sources_jar" "$ci_sources_jar"; do
- if grep -Eq '^native/' <<<"$(jar tf "$artifact")"; then
+ if grep -Eq '^(native/|META-INF/LICENSE-binary$)' <<<"$(jar tf
"$artifact")"; then
echo "Sources jar contains binary-only resources: $artifact" >&2
exit 1
fi
@@ -559,6 +559,7 @@ validate_maven_artifacts() {
native/windows/x86_64/paimon_mosaic_jni.dll \
META-INF/LICENSE \
META-INF/NOTICE \
+ META-INF/LICENSE-binary \
META-INF/DEPENDENCIES
do
if ! jar tf "$main_jar" | grep -qx "$entry"; then
@@ -566,6 +567,7 @@ validate_maven_artifacts() {
exit 1
fi
done
+ python3 "$REPO_DIR/tools/verify_binary_artifact.py" --jar "$main_jar"
done
local test_classes="$REPO_DIR/java/target/test-classes"
diff --git a/tools/tests/deploy_java_staging_test.sh
b/tools/tests/deploy_java_staging_test.sh
index ee6922b..9e08c2b 100755
--- a/tools/tests/deploy_java_staging_test.sh
+++ b/tools/tests/deploy_java_staging_test.sh
@@ -22,6 +22,7 @@ set -o nounset
set -o pipefail
SOURCE_REPO=$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)
+REAL_PYTHON=$(command -v python3)
TEST_ROOT=$(mktemp -d)
trap 'rm -rf "$TEST_ROOT"' EXIT
TESTS=0
@@ -131,11 +132,21 @@ native/macos/aarch64/libpaimon_mosaic_jni.dylib
native/windows/x86_64/paimon_mosaic_jni.dll
META-INF/LICENSE
META-INF/NOTICE
+META-INF/LICENSE-binary
META-INF/DEPENDENCIES
ENTRIES
if [[ "${OMIT_NATIVE_ENTRY:-0}" == 1 ]]; then
exit 0
fi
+MOCK
+ cat > "$MOCK_BIN/python3" <<'MOCK'
+#!/usr/bin/env bash
+set -euo pipefail
+if [[ "${1-}" == */tools/verify_binary_artifact.py ]]; then
+ printf 'python3 %s\n' "$*" >> "$MOCK_LOG"
+ exit 0
+fi
+exec "$REAL_PYTHON" "$@"
MOCK
# Rewrite the mock when an entry must be omitted; doing it here keeps the
# normal listing easy to audit.
@@ -184,6 +195,7 @@ run_stage() {
MOCK_LOG="$MOCK_LOG" \
MOCK_RUN_SHA="${MOCK_RUN_SHA:-$HEAD_SHA}" \
MOCK_TAG=v1.2.3-rc1 \
+ REAL_PYTHON="$REAL_PYTHON" \
OMIT_CI_JAVADOC="${OMIT_CI_JAVADOC:-0}" \
OMIT_LOCAL_MAIN="${OMIT_LOCAL_MAIN:-0}" \
"$FIXTURE/tools/deploy_java_staging.sh" \
@@ -207,6 +219,8 @@ done
assert_contains "$MOCK_LOG" "mvn clean verify -Prelease -Dgpg.skip=true
-DskipTests"
assert_not_contains "$MOCK_LOG" "mvn deploy"
[[ $(grep -c '^java ' "$MOCK_LOG") -eq 2 ]] || fail "dry-run must smoke local
and CI JARs"
+[[ $(grep -c '^python3 .*verify_binary_artifact.py' "$MOCK_LOG") -eq 2 ]] ||
+ fail "dry-run must verify local and CI JAR contents"
pass "successful dry-run validates all five artifacts and both JARs"
new_fixture
diff --git a/tools/tests/test_release_vote_workflow.py
b/tools/tests/test_release_vote_workflow.py
index ab83434..091393b 100644
--- a/tools/tests/test_release_vote_workflow.py
+++ b/tools/tests/test_release_vote_workflow.py
@@ -19,6 +19,7 @@ from __future__ import annotations
import copy
from pathlib import Path
+import subprocess
import pytest
import yaml
@@ -155,6 +156,25 @@ git diff --check "$(git merge-base HEAD
"${comparison_ref}")" HEAD
"""
+def test_binary_licenses_keep_canonical_bytes_with_autocrlf(tmp_path: Path) ->
None:
+ names = ("LICENSE-binary", "LICENSE-binary-ffi")
+ subprocess.run(["git", "init", "--quiet", str(tmp_path)], check=True)
+ for name in (".gitattributes", *names):
+ (tmp_path / name).write_bytes((ROOT / name).read_bytes())
+ subprocess.run(
+ ["git", "add", "--", ".gitattributes", *names], cwd=tmp_path,
check=True
+ )
+ for name in names:
+ (tmp_path / name).unlink()
+ subprocess.run(
+ ["git", "-c", "core.autocrlf=true", "checkout-index", "--", *names],
+ cwd=tmp_path,
+ check=True,
+ )
+ for name in names:
+ assert (tmp_path / name).read_bytes() == (ROOT / name).read_bytes(),
name
+
+
def load_workflow(path: Path) -> dict:
return yaml.load(path.read_text(encoding="utf-8"), Loader=yaml.BaseLoader)
diff --git a/tools/verify_binary_artifact.py b/tools/verify_binary_artifact.py
new file mode 100644
index 0000000..e3685a9
--- /dev/null
+++ b/tools/verify_binary_artifact.py
@@ -0,0 +1,281 @@
+#!/usr/bin/env python3
+
+#
+# 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.
+#
+
+"""Verify legal files and native resources in binary convenience artifacts."""
+
+import argparse
+import glob
+import json
+import subprocess
+import sys
+import zipfile
+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",
+}
+JAR_LEGAL_SOURCES = {
+ "NOTICE": "java/src/main/binary-resources/META-INF/NOTICE",
+ "LICENSE-binary": "LICENSE-binary",
+}
+JAR_NATIVE_FILES = (
+ "native/linux/x86_64/libpaimon_mosaic_jni.so",
+ "native/linux/aarch64/libpaimon_mosaic_jni.so",
+ "native/macos/aarch64/libpaimon_mosaic_jni.dylib",
+ "native/windows/x86_64/paimon_mosaic_jni.dll",
+)
+SUPPORTED_TARGETS = (
+ "x86_64-unknown-linux-gnu",
+ "aarch64-unknown-linux-gnu",
+ "aarch64-apple-darwin",
+ "x86_64-pc-windows-msvc",
+)
+
+
+def resolve_artifacts(patterns):
+ artifacts = []
+ for pattern in patterns:
+ matches = sorted(glob.glob(pattern))
+ if not matches:
+ raise ValueError(f"artifact pattern matched no files: {pattern}")
+ artifacts.extend(Path(match) for match in matches)
+ return artifacts
+
+
+def require_entries(archive, artifact, entries):
+ names = set(archive.namelist())
+ missing = [entry for entry in entries if entry not in names]
+ if missing:
+ raise ValueError(f"{artifact} is missing entries: {',
'.join(missing)}")
+
+
+def require_canonical_content(archive, artifact, archive_prefix, sources):
+ for name, source in sources.items():
+ entry = f"{archive_prefix}/{name}"
+ expected = (ROOT / source).read_bytes()
+ actual = archive.read(entry)
+ if actual != expected:
+ raise ValueError(f"{artifact}!/{entry} does not match repository
{source}")
+
+
+def verify_wheel(artifact):
+ with zipfile.ZipFile(artifact) as archive:
+ names = archive.namelist()
+ metadata = [name for name in names if
name.endswith(".dist-info/METADATA")]
+ if len(metadata) != 1:
+ raise ValueError(
+ f"{artifact} must contain exactly one .dist-info/METADATA
entry"
+ )
+ dist_info = metadata[0][: -len("METADATA")]
+ 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)
+ require_canonical_content(
+ archive, artifact, "mosaic", WHEEL_LEGAL_SOURCES
+ )
+ require_canonical_content(
+ archive,
+ artifact,
+ f"{dist_info}licenses".rstrip("/"),
+ WHEEL_LEGAL_SOURCES,
+ )
+
+ native_names = [
+ name
+ for name in names
+ if name.startswith("mosaic/")
+ and name.endswith((".so", ".dylib", ".dll"))
+ ]
+ if len(native_names) != 1:
+ raise ValueError(
+ f"{artifact} must contain exactly one platform native library,
found "
+ f"{len(native_names)}"
+ )
+
+ print(f"Verified Python wheel: {artifact}")
+
+
+def verify_jar(artifact, native_files):
+ with zipfile.ZipFile(artifact) as archive:
+ required = (
+ "META-INF/LICENSE",
+ "META-INF/NOTICE",
+ "META-INF/LICENSE-binary",
+ "META-INF/DEPENDENCIES",
+ "org/apache/paimon/mosaic/NativeLib.class",
+ ) + tuple(native_files)
+ require_entries(archive, artifact, required)
+ require_canonical_content(
+ archive,
+ artifact,
+ "META-INF",
+ JAR_LEGAL_SOURCES,
+ )
+
+ print(f"Verified Java JAR: {artifact}")
+
+
+def cargo_metadata(target):
+ return json.loads(
+ subprocess.check_output(
+ [
+ "cargo",
+ "metadata",
+ "--format-version",
+ "1",
+ "--locked",
+ "--filter-platform",
+ target,
+ ],
+ cwd=ROOT,
+ text=True,
+ )
+ )
+
+
+def resolved_runtime_dependencies(metadata, root_name):
+ packages = {package["id"]: package for package in metadata["packages"]}
+ nodes = {node["id"]: node for node in metadata["resolve"]["nodes"]}
+ roots = [
+ package["id"]
+ for package in metadata["packages"]
+ if package["source"] is None and package["name"] == root_name
+ ]
+ if len(roots) != 1:
+ raise ValueError(f"expected one workspace package named {root_name}")
+
+ resolved = set()
+ pending = roots
+ while pending:
+ package_id = pending.pop()
+ if package_id in resolved:
+ continue
+ resolved.add(package_id)
+ for dependency in nodes[package_id]["deps"]:
+ if any(
+ kind["kind"] in (None, "normal")
+ for kind in dependency["dep_kinds"]
+ ):
+ pending.append(dependency["pkg"])
+
+ return [
+ packages[package_id]
+ for package_id in resolved
+ if packages[package_id]["source"] is not None
+ ]
+
+
+def verify_source_legal_inventory():
+ metadata_by_target = [cargo_metadata(target) for target in
SUPPORTED_TARGETS]
+ for root_name, license_name in (
+ ("paimon-mosaic-ffi", "LICENSE-binary-ffi"),
+ ("paimon-mosaic-jni", "LICENSE-binary"),
+ ):
+ dependencies = {}
+ for metadata in metadata_by_target:
+ for package in resolved_runtime_dependencies(metadata, root_name):
+ marker = f"{package['name']} {package['version']}"
+ dependencies[marker] = package.get("license") or ""
+
+ binary_license = (ROOT / license_name).read_text(encoding="utf-8")
+ missing = []
+ for marker, expression in sorted(dependencies.items()):
+ needs_additional_text = (
+ "Apache-2.0" not in expression or " AND " in expression
+ )
+ if needs_additional_text and marker not in binary_license:
+ missing.append(f"{marker} ({expression})")
+
+ for marker in (
+ "Rust standard library 1.97.1",
+ "zstd-sys 2.0.16+zstd.1.5.7",
+ ):
+ if marker not in binary_license:
+ missing.append(marker)
+
+ if missing:
+ raise ValueError(
+ f"{license_name} does not account for {root_name} runtime "
+ f"dependencies: {', '.join(missing)}"
+ )
+
+ for name in (
+ "LICENSE",
+ "NOTICE",
+ "LICENSE-binary",
+ "LICENSE-binary-ffi",
+ "ffi/DEPENDENCIES.rust.tsv",
+ "jni/DEPENDENCIES.rust.tsv",
+ "java/src/main/binary-resources/META-INF/NOTICE",
+ ):
+ if not (ROOT / name).is_file():
+ raise ValueError(f"repository legal file is missing: {name}")
+
+ print("Verified binary legal inventory against native Rust dependencies")
+
+
+def main():
+ parser = argparse.ArgumentParser(description=__doc__)
+ parser.add_argument("--wheel", nargs="+", default=[], help="Wheel path or
glob")
+ parser.add_argument("--jar", nargs="+", default=[], help="JAR path or
glob")
+ parser.add_argument(
+ "--jar-native",
+ action="append",
+ choices=JAR_NATIVE_FILES,
+ help=(
+ "Native entry required in a JAR. Repeat for a partial-platform CI
build; "
+ "the default requires every release platform."
+ ),
+ )
+ parser.add_argument(
+ "--source",
+ action="store_true",
+ help="Verify LICENSE-binary against native Rust runtime dependencies",
+ )
+ args = parser.parse_args()
+
+ if not args.wheel and not args.jar and not args.source:
+ parser.error("at least one --source, --wheel, or --jar is required")
+
+ try:
+ if args.source:
+ verify_source_legal_inventory()
+ for artifact in resolve_artifacts(args.wheel):
+ verify_wheel(artifact)
+ for artifact in resolve_artifacts(args.jar):
+ verify_jar(artifact, args.jar_native or JAR_NATIVE_FILES)
+ except (
+ KeyError,
+ OSError,
+ subprocess.CalledProcessError,
+ ValueError,
+ zipfile.BadZipFile,
+ ) as error:
+ print(f"Binary artifact verification failed: {error}", file=sys.stderr)
+ return 1
+ return 0
+
+
+if __name__ == "__main__":
+ sys.exit(main())