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

Another attempt to add license file to CRAN recipes. #3284

Merged
merged 3 commits into from
Dec 10, 2018
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
45 changes: 45 additions & 0 deletions conda_build/skeletons/cran.py
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@
license: {license}
{summary_comment}summary:{summary}
license_family: {license_family}
{license_file}

{extra_recipe_maintainers}

Expand Down Expand Up @@ -1097,6 +1098,7 @@ def skeletonize(in_packages, output_dir=".", output_suffix="", add_maintainer=No
# XXX: We should maybe normalize these
d['license'] = cran_package.get("License", "None")
d['license_family'] = guess_license_family(d['license'], allowed_license_families)
d['license_file'] = get_license_file(d['license'])

if 'License_is_FOSS' in cran_package:
d['license'] += ' (FOSS)'
Expand Down Expand Up @@ -1403,3 +1405,46 @@ def up_to_date(cran_metadata, package):
return False

return True


def get_license_file(license_text):
'''
Most R packages on CRAN do not include a license file. Instead, to avoid
duplication, R base ships with common software licenses:

complete: AGPL-3, Artistic-2.0, GPL-2, GPL-3, LGPL-2, LGPL-2.1, LGPL-3
template: BSD_2_clause BSD_3_clause, MIT

The complete licenses can be included in conda binaries by pointing to the
license file shipped with R base. The template files are more complicated
because they would need to be combined with the license information provided
by the package authors (e.g. copyright owners and date).

This function returns the path to the license file for the unambiguous
cases. Any time an R package refers to one of the templates or a custom
license file (e.g. 'GPL-2 | file LICENSE'), an empty string is returned.
'''

# The list order matters. The first element should be the name of the
# license file shipped with r-base.
d_license = {'agpl3': ['AGPL-3', 'AGPL (>= 3)', 'AGPL',
'GNU Affero General Public License'],
'artistic2': ['Artistic-2.0', 'Artistic License 2.0'],
'gpl2': ['GPL-2', 'GPL (>= 2)', 'GNU General Public License (>= 2)'],
'gpl3': ['GPL-3', 'GPL (>= 3)', 'GNU General Public License (>= 3)',
'GPL', 'GNU General Public License'],
'lgpl2': ['LGPL-2', 'LGPL (>= 2)'],
'lgpl21': ['LGPL-2.1', 'LGPL (>= 2.1)'],
'lgpl3': ['LGPL-3', 'LGPL (>= 3)', 'LGPL',
'GNU Lesser General Public License']}

license_file_template = 'license_file: \'{{{{ environ["PREFIX"] }}}}/lib/R/share/licenses/{license_id}\''

for license_id in d_license.keys():
if license_text in d_license[license_id]:
license_file = license_file_template.format(license_id=d_license[license_id][0])
break
else:
license_file = ''

return license_file
22 changes: 22 additions & 0 deletions tests/test_api_skeleton.py
Original file line number Diff line number Diff line change
Expand Up @@ -180,3 +180,25 @@ def test_pypi_section_order_preserved(testing_workdir):
assert list(recipe['requirements']) == REQUIREMENTS_ORDER
for k, v in PYPI_META_STATIC.items():
assert list(v.keys()) == list(recipe[k])


# CRAN packages to test license_file entry.
# (package, license_id, license_family, license_file)
cran_packages = [('r-usethis', 'GPL-3', 'GPL3', 'GPL-3'),
('r-abf2', 'Artistic-2.0', 'OTHER', 'Artistic-2.0'),
('r-cortools', 'Artistic License 2.0', 'OTHER', 'Artistic-2.0'),
('r-ruchardet', 'MPL', 'OTHER', ''),
]


@pytest.mark.parametrize("package, license_id, license_family, license_file", cran_packages)
def test_cran_license(package, license_id, license_family, license_file, testing_workdir, testing_config):
api.skeletonize(packages=package, repo='cran', output_dir=testing_workdir,
config=testing_config)
m = api.render(os.path.join(package, 'meta.yaml'))[0][0]
m_license_id = m.get_value('about/license')
assert m_license_id == license_id
m_license_family = m.get_value('about/license_family')
assert m_license_family == license_family
m_license_file = m.get_value('about/license_file', '')
assert os.path.basename(m_license_file) == license_file