Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add third-party license information #179

Merged
merged 1 commit into from
Jan 5, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions THIRDPARTY.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
This file lists third-party software included in
'jar-with-dependencies' binary distribution. Where multiple licenses
are available, we choose the most permissive license to apply to the
corresponding part of the binary distribution.

For full license text and copyrights (where applicable) please refer
to the [NOTICE](src/main/resources/META-INF/NOTICE) file.

| Group | Artifact | Version | Developers | License | License URL |
|-|-|-|-|-|-|
| com.github.jnr | jffi | 1.2.23 | Wayne Meissner | The Apache Software License, Version 2.0 | http://www.apache.org/licenses/LICENSE-2.0.txt |
| com.github.jnr | jnr-a64asm | 1.0.0 | ossdev | The Apache Software License, Version 2.0 | http://www.apache.org/licenses/LICENSE-2.0.txt |
| com.github.jnr | jnr-constants | 0.9.17 | Wayne Meissner, Charles Oliver Nutter | The Apache Software License, Version 2.0 | http://www.apache.org/licenses/LICENSE-2.0.txt |
| com.github.jnr | jnr-enxio | 0.30 | Wayne Meissner | The Apache Software License, Version 2.0 | http://www.apache.org/licenses/LICENSE-2.0.txt |
| com.github.jnr | jnr-ffi | 2.1.16 | Wayne Meissner, Charles Oliver Nutter | The Apache Software License, Version 2.0 | http://www.apache.org/licenses/LICENSE-2.0.txt |
| com.github.jnr | jnr-posix | 3.0.61 | Thomas E Enebo, Wayne Meissner, Charles Oliver Nutter | Eclipse Public License - v 2.0 | https://www.eclipse.org/legal/epl-2.0/ |
| com.github.jnr | jnr-unixsocket | 0.36 | Wayne Meissner, Fritz Elfert | The Apache Software License, Version 2.0 | http://www.apache.org/licenses/LICENSE-2.0.txt |
| com.github.jnr | jnr-x86asm | 1.0.2 | Wayne Meissner | MIT License | http://www.opensource.org/licenses/mit-license.php |
| org.ow2.asm | asm | 7.1 | Eric Bruneton, Eugene Kuleshov, Remi Forax | BSD | http://asm.ow2.org/license.html |
| org.ow2.asm | asm-analysis | 7.1 | Eric Bruneton, Eugene Kuleshov, Remi Forax | BSD | http://asm.ow2.org/license.html |
| org.ow2.asm | asm-commons | 7.1 | Eric Bruneton, Eugene Kuleshov, Remi Forax | BSD | http://asm.ow2.org/license.html |
| org.ow2.asm | asm-tree | 7.1 | Eric Bruneton, Eugene Kuleshov, Remi Forax | BSD | http://asm.ow2.org/license.html |
| org.ow2.asm | asm-util | 7.1 | Eric Bruneton, Eugene Kuleshov, Remi Forax | BSD | http://asm.ow2.org/license.html |
159 changes: 159 additions & 0 deletions gen_notice.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
#!/usr/bin/env python3

"""
Generate third-party license information.
- NOTICE file for the binary distribution
- THIRDPARTY.md to be displayed on github

When using this script to update license information, verify that the
sources included (this script unpacks them into target/dependency)
matches the license.
"""

import functools
import os, os.path, re
import xml.etree.ElementTree as ElementTree
import urllib.request
from collections import namedtuple

Dep = namedtuple('Dep', ['groupId', 'artifactId', 'version'])
def list_dependencies():
pattern = re.compile(".* (?P<groupId>[^:]*):(?P<artifactId>[^:]*):jar:(?P<version>[^:]*):compile")
with os.popen("mvn dependency:list") as l:
for line in l:
m = pattern.match(line)
if not m:
continue
yield Dep(**{k: m[k] for k in ['groupId', 'artifactId', 'version']})

def unpack_dependencies():
if not os.path.isdir("target/dependency"):
os.system("mvn dependency:copy-dependencies -Dmdep.copyPom -Dmdep.useRepositoryLayout")
os.system("mvn dependency:unpack-dependencies -DincludeScope=compile -Dmdep.useRepositoryLayout")
os.system("mvn dependency:unpack-dependencies -Dclassifier=sources -DincludeScope=compile -Dmdep.useRepositoryLayout")

def dep_path(dep):
return os.path.join(
'target', 'dependency',
*dep.groupId.split('.'),
dep.artifactId,
dep.version)

def scan_unpacked(dep, ignored={'module-info.class'}):
classdirs = set()
prefix = dep_path(dep)
for dirpath, _, filenames in os.walk(prefix):
for f in filenames:
if f.endswith('.class') and f not in ignored:
if dirpath.removeprefix(prefix).removeprefix('/') == '':
raise ValueError(dirpath, prefix)
classdirs.add(dirpath.removeprefix(prefix).removeprefix('/'))

return unify_paths(classdirs)

def unify_paths(paths):
res = set()
for p in sorted(paths):
if not any(p.startswith(r) for r in res):
res.add(p)
return res

Pom = namedtuple('Pom', ['authors', 'license'])
PomLicense = namedtuple('PomLicense', ['name', 'url'])
def read_pom(dep, ns={'pom': 'http://maven.apache.org/POM/4.0.0'}):
path = os.path.join(dep_path(dep), f"{dep.artifactId}-{dep.version}.pom")
pom = ElementTree.parse(path)
auth = pom.findall('.//pom:developers/pom:developer/pom:name', ns)
auth = ', '.join(a.text for a in auth)
lic = pom.find('.//pom:licenses/pom:license', ns)
return Pom(auth, PomLicense(
lic.findtext('./pom:name', None, ns),
lic.findtext('./pom:url', None, ns),
))

LICENSES = {
# Links to the project front-page.
'org.ow2.asm': 'https://raw.githubusercontent.com/llbit/ow2-asm/master/LICENSE.txt',
# These two link to generic license text without copyrights.
'com.github.jnr/jnr-posix': 'https://raw.githubusercontent.com/jnr/jnr-posix/jnr-posix-{version}/LICENSE.txt',
'com.github.jnr/jnr-x86asm': 'https://raw.githubusercontent.com/jnr/jnr-x86asm/{version}/LICENSE',
}

@functools.cache
def fetch(url):
print(f'... fetching {url}')
with urllib.request.urlopen(url) as f:
return clean(f.read().decode('ascii'))

def clean(s, remove=re.compile('[^\n\t !-~]', re.A)):
return remove.sub('', s)

def write_notice(notice, dep, classdirs, license_text):
"""
NOTICE file to be included with the binary distribution and
fullfill third-party license requirements.
"""
header = f'{dep.groupId} {dep.artifactId} {dep.version}'
print(header, file=notice)
print('-' * len(header), file=notice)

repo_path = '/'.join([*dep.groupId.split('.'), dep.artifactId, dep.version])
print(f'Sources are available at https://repo.maven.apache.org/maven2/{repo_path}/\n', file=notice)

print('Files in the following directories:', ' '.join(sorted(classdirs)), file=notice)
print('are distributed under the terms of the following license:\n', file=notice)

print(license_text, file=notice)
print('\n', file=notice)

LISTING_HEADER = """\
This file lists third-party software included in
'jar-with-dependencies' binary distribution. Where multiple licenses
are available, we choose the most permissive license to apply to the
corresponding part of the binary distribution.

For full license text and copyrights (where applicable) please refer
to the [NOTICE](src/main/resources/META-INF/NOTICE) file.

| Group | Artifact | Version | Developers | License | License URL |
|-|-|-|-|-|-|
"""

def write_listing(listing, dep, pom):
"""
THIRDPARTY.md provides an overview of third-party licenses that
will apply to the binary distribution.
"""
print(f'| {dep.groupId} | {dep.artifactId} | {dep.version} ', end='', file=listing)
print(f'| {pom.authors} ', end='', file=listing)
print(f'| {pom.license.name} | {pom.license.url} ', end='', file=listing)
print(f'|', file=listing)

def gen_all(notice, listing):
deps = list_dependencies()
unpack_dependencies()

print(LISTING_HEADER, end='', file=listing)

for dep in sorted(deps):
classdirs = scan_unpacked(dep)
pom = read_pom(dep)

license_url = LICENSES.get(f'{dep.groupId}/{dep.artifactId}') or LICENSES.get(dep.groupId)
if license_url:
license_url = license_url.format(**dep._asdict())
else:
license_url = pom.license.url
if not license_url:
print(f'License is missing for {dep}')
break

license_text = fetch(license_url)

write_notice(notice, dep, classdirs, license_text)
write_listing(listing, dep, pom)

if __name__ == '__main__':
with open('src/main/resources/META-INF/NOTICE', 'w') as notice:
with open('THIRDPARTY.md', 'w') as listing:
gen_all(notice, listing)
Loading