diff --git a/swh/indexer/data/composer.csv b/swh/indexer/data/composer.csv new file mode 100644 --- /dev/null +++ b/swh/indexer/data/composer.csv @@ -0,0 +1,68 @@ +Property,codemeta-V1,Composer +codeRepository,codeRepository,support.source +programmingLanguage,programmingLanguage, +runtimePlatform,, +targetProduct,, +applicationCategory,, +applicationSubCategory,, +downloadUrl,downloadLink, +fileSize,, +installUrl,, +memoryRequirements,, +operatingSystem,operatingSystems, +permissions,, +processorRequirements,, +releaseNotes,, +softwareHelp,, +softwareRequirements,depends,require +softwareVersion,,version +storageRequirements,, +supportingData,, +author,agents,authors +citation,relatedLink, +contributor,, +copyrightHolder,agents [role=copyrightHolder], +copyrightYear,, +dateCreated,dateCreated, +dateModified,dateModified, +datePublished,datePublished, +editor,, +encoding,, +fileFormat,, +funder,fundingReference.funderName, +keywords,controlledTerms,keywords +license,licenseId,license +producer,, +provider,, +publisher,publisher, +sponsor,, +version,version,version +isAccessibleForFree,, +isPartOf,, +hasPart,, +position,, +description,description,description +identifier,identifier,name +name,name,name +sameAs,, +url,URL,homepage +relatedLink,, +givenName,, +familyName,, +email,email,author.email +affiliation,affiliation, +identifier,identifier, +name,,author.name +address,, +type,, +id,, +softwareSuggestions,suggests,suggest +maintainer,uploadedBy, +contIntegration,contIntegration, +buildInstructions,buildInstructions, +developmentStatus,developmentStatus, +embargoDate,embargoDate, +funding,funding, +issueTracker,issueTracker,support.issues +referencePublication,relatedPublications, +readme,readme, \ No newline at end of file diff --git a/swh/indexer/metadata_dictionary/__init__.py b/swh/indexer/metadata_dictionary/__init__.py --- a/swh/indexer/metadata_dictionary/__init__.py +++ b/swh/indexer/metadata_dictionary/__init__.py @@ -2,7 +2,7 @@ import click -from . import cff, codemeta, maven, npm, python, ruby +from . import cff, codemeta, composer, maven, npm, python, ruby MAPPINGS = { "CodemetaMapping": codemeta.CodemetaMapping, @@ -11,6 +11,7 @@ "PythonPkginfoMapping": python.PythonPkginfoMapping, "GemspecMapping": ruby.GemspecMapping, "CffMapping": cff.CffMapping, + "ComposerMapping": composer.ComposerMapping, } diff --git a/swh/indexer/metadata_dictionary/composer.py b/swh/indexer/metadata_dictionary/composer.py new file mode 100644 --- /dev/null +++ b/swh/indexer/metadata_dictionary/composer.py @@ -0,0 +1,59 @@ +# Copyright (C) 2022 The Software Heritage developers +# See the AUTHORS file at the top-level directory of this distribution +# License: GNU General Public License version 3, or any later version +# See top-level LICENSE file for more information + +import os.path + +from swh.indexer.codemeta import _DATA_DIR, SCHEMA_URI, _read_crosstable + +from .base import JsonMapping + +COMPOSER_TABLE_PATH = os.path.join(_DATA_DIR, "composer.csv") + +with open(COMPOSER_TABLE_PATH) as fd: + (CODEMETA_TERMS, COMPOSER_TABLE) = _read_crosstable(fd) + + +class ComposerMapping(JsonMapping): + """Dedicated class for Packagist(composer.json) mapping and translation""" + + name = "composer" + mapping = COMPOSER_TABLE["Composer"] + filename = b"composer.json" + string_fields = [ + "name", + "description", + "version", + "keywords", + "homepage", + "readme", + "license", + "author", + "authors", + ] + + def normalize_homepage(self, s): + if isinstance(s, str): + return {"@id": s} + + def normalize_license(self, s): + if isinstance(s, str): + return {"@id": "https://spdx.org/licenses/" + s} + + def normalize_authors(self, author_list): + authors = [] + for author in author_list: + author_obj = {"@type": SCHEMA_URI + "Person"} + + if isinstance(author, dict): + if isinstance(author.get("name", None), str): + author_obj[SCHEMA_URI + "name"] = author.get("name", None) + if isinstance(author.get("email", None), str): + author_obj[SCHEMA_URI + "email"] = author.get("email", None) + if isinstance(author.get("role", None), str): + author_obj[SCHEMA_URI + "role"] = author.get("role", None) + + authors.append(author_obj) + + return {"@list": authors} diff --git a/swh/indexer/tests/test_cli.py b/swh/indexer/tests/test_cli.py --- a/swh/indexer/tests/test_cli.py +++ b/swh/indexer/tests/test_cli.py @@ -95,6 +95,7 @@ [ "cff", "codemeta", + "composer", "gemspec", "maven", "npm", diff --git a/swh/indexer/tests/test_metadata.py b/swh/indexer/tests/test_metadata.py --- a/swh/indexer/tests/test_metadata.py +++ b/swh/indexer/tests/test_metadata.py @@ -64,6 +64,7 @@ self.pkginfo_mapping = MAPPINGS["PythonPkginfoMapping"]() self.gemspec_mapping = MAPPINGS["GemspecMapping"]() self.cff_mapping = MAPPINGS["CffMapping"]() + self.composer_mapping = MAPPINGS["ComposerMapping"]() def test_compute_metadata_none(self): """ @@ -616,6 +617,83 @@ # then assert expected_results == results + def test_compute_metadata_composer(self): + raw_content = """{ + "name": "symfony/polyfill-mbstring", + "type": "library", + "description": "Symfony polyfill for the Mbstring extension", + "keywords": [ + "polyfill", + "shim", + "compatibility", + "portable" + ], + "homepage": "https://symfony.com", + "license": "MIT", + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "require": { + "php": ">=7.1" + }, + "provide": { + "ext-mbstring": "*" + }, + "autoload": { + "files": [ + "bootstrap.php" + ] + }, + "suggest": { + "ext-mbstring": "For best performance" + }, + "minimum-stability": "dev", + "extra": { + "branch-alias": { + "dev-main": "1.26-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + } +} + """.encode( + "utf-8" + ) + + result = self.composer_mapping.translate(raw_content) + + expected = { + "@context": "https://doi.org/10.5063/schema/codemeta-2.0", + "type": "SoftwareSourceCode", + "name": "symfony/polyfill-mbstring", + "keywords": ["polyfill", "shim", "compatibility", "portable"], + "description": "Symfony polyfill for the Mbstring extension", + "url": "https://symfony.com", + "license": "https://spdx.org/licenses/MIT", + "author": [ + { + "type": "Person", + "name": "Nicolas Grekas", + "email": "p@tchwork.com", + }, + { + "type": "Person", + "name": "Symfony Community", + }, + ], + } + + assert result == expected + def test_compute_metadata_valid_codemeta(self): raw_content = b"""{ "@context": "https://doi.org/10.5063/schema/codemeta-2.0",