|
| 1 | +# SPDX-License-Identifier: Apache-2.0 |
| 2 | +# |
| 3 | +# http://nexb.com and https://github.com/aboutcode-org/scancode.io |
| 4 | +# The ScanCode.io software is licensed under the Apache License version 2.0. |
| 5 | +# Data generated with ScanCode.io is provided as-is without warranties. |
| 6 | +# ScanCode is a trademark of nexB Inc. |
| 7 | +# |
| 8 | +# You may not use this software except in compliance with the License. |
| 9 | +# You may obtain a copy of the License at: http://apache.org/licenses/LICENSE-2.0 |
| 10 | +# Unless required by applicable law or agreed to in writing, software distributed |
| 11 | +# under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR |
| 12 | +# CONDITIONS OF ANY KIND, either express or implied. See the License for the |
| 13 | +# specific language governing permissions and limitations under the License. |
| 14 | +# |
| 15 | +# Data Generated with ScanCode.io is provided on an "AS IS" BASIS, WITHOUT WARRANTIES |
| 16 | +# OR CONDITIONS OF ANY KIND, either express or implied. No content created from |
| 17 | +# ScanCode.io should be considered or used as legal advice. Consult an Attorney |
| 18 | +# for any legal advice. |
| 19 | +# |
| 20 | +# ScanCode.io is a free software code scanning tool from nexB Inc. and others. |
| 21 | +# Visit https://github.com/aboutcode-org/scancode.io for support and download. |
| 22 | + |
| 23 | + |
| 24 | +from dataclasses import asdict |
| 25 | +from dataclasses import dataclass |
| 26 | +from dataclasses import field |
| 27 | +from pathlib import Path |
| 28 | + |
| 29 | +import saneyaml |
| 30 | + |
| 31 | +""" |
| 32 | +This module provides Python dataclass models for representing a package list |
| 33 | +in a format compatible with the OSS Review Toolkit (ORT) |
| 34 | +`CreateAnalyzerResultFromPackageListCommand`. |
| 35 | +
|
| 36 | +The models are simplified adaptations of the Kotlin classes from: |
| 37 | +https://github.com/oss-review-toolkit/ort/blob/main/cli-helper/src/main/kotlin/commands/CreateAnalyzerResultFromPackageListCommand.kt |
| 38 | +
|
| 39 | +This module is intended for generating ORT-compatible YAML package lists from Python |
| 40 | +objects, allowing integration with ORT's analyzer workflows or manual creation of |
| 41 | +package metadata. |
| 42 | +""" |
| 43 | + |
| 44 | + |
| 45 | +# private data class SourceArtifact( |
| 46 | +# val url: String, |
| 47 | +# val hash: Hash? = null |
| 48 | +# ) |
| 49 | +@dataclass |
| 50 | +class SourceArtifact: |
| 51 | + url: str |
| 52 | + # Cannot coerce empty String ("") to `org.ossreviewtoolkit.model.Hash` value |
| 53 | + # hash: str = None |
| 54 | + |
| 55 | + |
| 56 | +# private data class Vcs( |
| 57 | +# val type: String? = null, |
| 58 | +# val url: String? = null, |
| 59 | +# val revision: String? = null, |
| 60 | +# val path: String? = null |
| 61 | +# ) |
| 62 | +@dataclass |
| 63 | +class Vcs: |
| 64 | + type: str = None |
| 65 | + url: str = None |
| 66 | + revision: str = None |
| 67 | + path: str = None |
| 68 | + |
| 69 | + |
| 70 | +# private data class Dependency( |
| 71 | +# val id: Identifier, |
| 72 | +# val purl: String? = null, |
| 73 | +# val vcs: Vcs? = null, |
| 74 | +# val sourceArtifact: SourceArtifact? = null, |
| 75 | +# val declaredLicenses: Set<String> = emptySet(), |
| 76 | +# val concludedLicense: SpdxExpression? = null, |
| 77 | +# val description: String? = null, |
| 78 | +# val homepageUrl: String? = null, |
| 79 | +# val isExcluded: Boolean = false, |
| 80 | +# val isDynamicallyLinked: Boolean = false, |
| 81 | +# val labels: Map<String, String> = emptyMap() |
| 82 | +# ) |
| 83 | +@dataclass |
| 84 | +class Dependency: |
| 85 | + id: str |
| 86 | + purl: str = None |
| 87 | + vcs: Vcs = None |
| 88 | + sourceArtifact: SourceArtifact = None |
| 89 | + declaredLicenses: list = field(default_factory=set) |
| 90 | + # concludedLicense: str = None |
| 91 | + description: str = None |
| 92 | + homepageUrl: str = None |
| 93 | + # isExcluded: bool = False |
| 94 | + # isDynamicallyLinked: bool = False |
| 95 | + # labels: dict = field(default_factory=dict) |
| 96 | + |
| 97 | + |
| 98 | +# private data class PackageList( |
| 99 | +# val projectName: String? = null, |
| 100 | +# val projectVcs: Vcs? = null, |
| 101 | +# val dependencies: List<Dependency> = emptyList() |
| 102 | +# ) |
| 103 | +@dataclass |
| 104 | +class PackageList: |
| 105 | + projectName: str |
| 106 | + projectVcs: Vcs = field(default_factory=Vcs) |
| 107 | + dependencies: list = field(default_factory=list) |
| 108 | + |
| 109 | + def to_yaml(self): |
| 110 | + """Dump the Project object back to a YAML string.""" |
| 111 | + return saneyaml.dump(asdict(self)) |
| 112 | + |
| 113 | + def to_file(self, filepath): |
| 114 | + """Write the Project object to a YAML file.""" |
| 115 | + Path(filepath).write_text(self.to_yaml(), encoding="utf-8") |
| 116 | + |
| 117 | + |
| 118 | +def get_ort_project_type(project): |
| 119 | + """ |
| 120 | + Determine the ORT project type based on the project's input sources. |
| 121 | +
|
| 122 | + Currently, this function checks whether any of the project's |
| 123 | + input download URLs start with "docker://". |
| 124 | + If at least one Docker URL is found, it returns "docker". |
| 125 | + """ |
| 126 | + inputs_url = project.inputsources.values_list("download_url", flat=True) |
| 127 | + if any(url.startswith("docker://") for url in inputs_url): |
| 128 | + return "docker" |
| 129 | + |
| 130 | + |
| 131 | +def to_ort_package_list_yml(project): |
| 132 | + """Convert a project object into a YAML string in the ORT package list format.""" |
| 133 | + project_type = get_ort_project_type(project) |
| 134 | + |
| 135 | + dependencies = [] |
| 136 | + for package in project.discoveredpackages.all(): |
| 137 | + dependency = Dependency( |
| 138 | + id=f"{project_type or package.type}::{package.name}:{package.version}", |
| 139 | + purl=package.purl, |
| 140 | + sourceArtifact=SourceArtifact(url=package.download_url), |
| 141 | + declaredLicenses=[package.get_declared_license_expression_spdx()], |
| 142 | + vcs=Vcs(url=package.vcs_url), |
| 143 | + description=package.description, |
| 144 | + homepageUrl=package.homepage_url, |
| 145 | + ) |
| 146 | + dependencies.append(dependency) |
| 147 | + |
| 148 | + package_list = PackageList( |
| 149 | + projectName=project.name, |
| 150 | + dependencies=dependencies, |
| 151 | + ) |
| 152 | + |
| 153 | + return package_list.to_yaml() |
0 commit comments