1
0
mirror of https://github.com/ansible/mazer.git synced 2026-02-05 12:45:17 +01:00
Files
mazer/ansible_galaxy/models/collection_info.py
Adrian Likins f4390adace Load spdx data from json on first use only
Generate a short concise ansible_galaxy/data/spdx_license.json
from the verbose upstream data.

ansible_galaxy.data.spdx_license is a module that caches the
data loaded from json on first use of get_spdx.

- Add tool (spdx_update.py) to build a condensed json file
with data from spdx.json

Use this to parse spdx json data when it is updated
and generated a new source file.

- Add a 'dev/spdx-update' make target

This target pulls down the latest SPDX license
info from https://github.com/spdx/license-list-data
to data/spdx_licenses.json

Then use spdx_update.py to generate the condensed
ansible_galaxy/data/spdx_licenses.json based
on data/spdx_licenses.json

- Validate CollectionInfo off static dict of spdx info.

Previously everytime a CollectionInfo() was created, the
spdx_data was being loaded and parsed.

Now check it against a set of data in ansible_galaxy.data.spdx_licenses

If a license id is in the SPDX_LICENSES dict, it is acceptable.
If the license items value is True, then it is deprecated and
a warning is printed.

TODO: mv the deprecated license check so it only runs on 'build'
and not anytime a collection is loaded
2019-01-23 13:28:29 -05:00

97 lines
3.4 KiB
Python

from __future__ import print_function
import attr
import logging
import re
import semver
from ansible_galaxy.data import spdx_licenses
log = logging.getLogger(__name__)
TAG_REGEXP = re.compile('^[a-z0-9]+$')
NAME_REGEXP = re.compile(r'^[a-z0-9_]+$')
# see https://github.com/ansible/galaxy/issues/957
@attr.s(frozen=True)
class CollectionInfo(object):
namespace = attr.ib(default=None)
name = attr.ib(default=None)
version = attr.ib(default=None)
license = attr.ib(default=None)
description = attr.ib(default=None)
authors = attr.ib(factory=list)
keywords = attr.ib(factory=list)
readme = attr.ib(default='README.md')
# Note galaxy.yml 'dependencies' field is what mazer and ansible
# consider 'requirements'. ie, install time requirements.
dependencies = attr.ib(factory=list)
@property
def label(self):
return '%s.%s' % (self.namespace, self.name)
@staticmethod
def value_error(msg):
raise ValueError("Invalid collection metadata. %s" % msg)
@namespace.validator
@name.validator
@version.validator
@license.validator
@description.validator
def _check_required(self, attribute, value):
if value is None:
self.value_error("'%s' is required" % attribute.name)
@version.validator
def _check_version_format(self, attribute, value):
try:
semver.parse_version_info(value)
except ValueError:
self.value_error("Expecting 'version' to be in semantic version format, "
"instead found '%s'." % value)
@license.validator
def _check_license(self, attribute, value):
# load or return already loaded data
licenses = spdx_licenses.get_spdx()
valid = licenses.get(value, None)
if valid is None:
self.value_error("Expecting 'license' to be a valid SPDX license ID, instead found '%s'. "
"For more info, visit https://spdx.org" % value)
# license was in list, but is deprecated
if valid and valid.get('deprecated', None):
print("Warning: collection metadata 'license' value '%s' is "
"deprecated." % value)
@authors.validator
@keywords.validator
@dependencies.validator
def _check_list_type(self, attribute, value):
if not isinstance(value, list):
self.value_error("Expecting '%s' to be a list" % attribute.name)
@keywords.validator
def _check_keywords(self, attribute, value):
for k in value:
if not re.match(TAG_REGEXP, k):
self.value_error("Expecting keywords to contain alphanumeric characters only, "
"instead found '%s'." % k)
@name.validator
@namespace.validator
def _check_name(self, attribute, value):
if '.' in value:
self.value_error("Expecting 'name' and 'namespace' to not include any '.' but '%s' has a '.'" % value)
if not re.match(NAME_REGEXP, value):
self.value_error("Expecting 'name' and 'namespace' to contain only alphanumeric characters or '_' only but '%s' contains others" % value)
# since the NAME_REGEXP catches use of hyphen '-' at all, the next check doesn't need to check for leading hyphen
if value.startswith(('_',)):
self.value_error("Expecting 'name' and 'namespace' to not start with '_' but '%s' did" % value)