Skip to content

Add support for buildpack.toml files #4031

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

Open
wants to merge 8 commits into
base: develop
Choose a base branch
from
Open
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
3 changes: 3 additions & 0 deletions src/packagedcode/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
from packagedcode import alpine
from packagedcode import bower
from packagedcode import build
from packagedcode import buildpack
from packagedcode import build_gradle
from packagedcode import cargo
from packagedcode import chef
Expand Down Expand Up @@ -62,6 +63,8 @@
build.BuckMetadataBzlHandler,
build.BuckPackageHandler,

buildpack.BuildpackHandler,

cargo.CargoLockHandler,
cargo.CargoTomlHandler,

Expand Down
152 changes: 152 additions & 0 deletions src/packagedcode/buildpack.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
#
# Copyright (c) nexB Inc. and others. All rights reserved.
# ScanCode is a trademark of nexB Inc.
# SPDX-License-Identifier: Apache-2.0
# See http://www.apache.org/licenses/LICENSE-2.0 for the license text.
# See https://github.com/nexB/scancode-toolkit for support or download.
# See https://aboutcode.org for more information about nexB OSS projects.
#

import toml
from packagedcode import models
from packageurl import PackageURL
import yaml

class BuildpackHandler(models.NonAssemblableDatafileHandler):
"""
Handle buildpack.toml manifests.
See https://buildpacks.io/ for details on buildpack format.
"""
datasource_id = "buildpack_toml"
path_patterns = ("*buildpack.toml",)
default_package_type = "generic"
description = "Cloud Native Buildpack manifest"
documentation_url = "https://buildpacks.io/"

@classmethod
def parse(cls, location, package_only=False):
"""
Parse the buildpack.toml file at `location` and yield PackageData.
"""
with open(location, "r", encoding="utf-8") as f:
data = toml.load(f)

api_version = data.get("api")
buildpack = data.get("buildpack", {})
if not buildpack:
return

buildpack_id = buildpack.get("id")
name = buildpack.get("name")

if buildpack_id:
namespace, name = buildpack_id.split("/", 1)

# Initialize common package data
package_data = dict(
datasource_id=cls.datasource_id,
type=cls.default_package_type,
name=name,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are extracting namespace above but not including it in PackageData here.

version=buildpack.get("version"),
description=buildpack.get("description"),
homepage_url=buildpack.get("homepage"),
keywords=buildpack.get("keywords", []),
extracted_license_statement=None,
dependencies=[],
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You don't need to add dependencies and extra_data like this, as these are initialized by default. Remove these two lines.

extra_data={}
)

if api_version:
package_data["extra_data"]["api_version"] = api_version

# Handle Paketo-specific fields if present
if "api" in data:
cls.handle_paketo_buildpack(data, buildpack, package_data)

# Handle Heroku-specific fields if present
elif "publish" in data and "Ignore" in data["publish"]:
cls.handle_heroku_buildpack(data, buildpack, package_data)

yield models.PackageData.from_data(package_data, package_only)

@staticmethod
def handle_paketo_buildpack(data, buildpack, package_data):
buildpack_id = buildpack.get("id")
if buildpack_id:
package_data["extra_data"]["id"] = buildpack_id

package_data.update({
"version": buildpack.get("version"),
"description": buildpack.get("description"),
"homepage_url": buildpack.get("homepage"),
"keywords": buildpack.get("keywords", []),
})

licenses = buildpack.get("licenses", [])
if licenses:
license_statements = [
yaml.dump({"type": license_entry.get("type")}).strip()
for license_entry in licenses
if license_entry.get("type")
]
package_data["extracted_license_statement"] = "\n".join(license_statements)


dependencies = []
metadata = data.get("metadata", {})
metadata_dependencies = metadata.get("dependencies", [])
for dep in metadata_dependencies:
dep_purl = dep.get("purl")
dep_name = dep.get("name")
dep_version = dep.get("version")
dep_cpes = dep.get("cpes", [])
extra_data = {"cpes": dep_cpes} if dep_cpes else {}

if not dep_purl and dep_name and dep_version:
dep_purl = PackageURL(type="generic", name=dep_name, version=dep_version).to_string()

if dep_purl:
dependencies.append(
models.DependentPackage(
purl=dep_purl,
scope="runtime",
is_runtime=True,
is_optional=False,
extra_data=extra_data,
)
)

orders = data.get("order", [])
for order in orders:
for group in order.get("group", []):
group_id = group.get("id")
group_version = group.get("version")
if group_id and group_version:
dependencies.append(
models.DependentPackage(
purl=PackageURL(type="buildpack", name=group_id, version=group_version).to_string(),
scope="runtime",
is_runtime=True,
is_optional=group.get("optional", False),
)
)

package_data["dependencies"] = dependencies

targets = data.get("targets", [])
if targets:
package_data["extra_data"]["targets"] = targets

@staticmethod
def handle_heroku_buildpack(data, buildpack, package_data):
publish_section = data.get("publish", {})
if "Ignore" in publish_section:
ignore_files = publish_section["Ignore"].get("files", [])
if ignore_files:
package_data["extra_data"]["ignore_files"] = ignore_files
else:
package_data["extra_data"]["ignore_files"] = []
else:
package_data["extra_data"]["ignore_files"] = []

package_data["description"] = f"Heroku buildpack for {buildpack.get('name')}"
2 changes: 1 addition & 1 deletion src/packagedcode/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -582,7 +582,7 @@ class PackageData(IdentifiablePackageData):
download_url = String(
label='Download URL',
help='A direct download URL.')

size = Integer(
default=None,
label='download size',
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
[buildpack]
name = "Java"

[publish.Ignore]
files = [
"etc/",
"spec/",
"test/",
".gitignore",
".github/",
"hatchet.json",
"Gemfile",
"Gemfile.lock"
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
{
"packages": [],
"dependencies": [],
"files": [
{
"path": "buildpack.toml",
"type": "file",
"package_data": [
{
"type": "generic",
"namespace": null,
"name": "Java",
"version": null,
"qualifiers": {},
"subpath": null,
"primary_language": null,
"description": "Heroku buildpack for Java",
"release_date": null,
"parties": [],
"keywords": [],
"homepage_url": null,
"download_url": null,
"size": null,
"sha1": null,
"md5": null,
"sha256": null,
"sha512": null,
"bug_tracking_url": null,
"code_view_url": null,
"vcs_url": null,
"copyright": null,
"holder": null,
"declared_license_expression": null,
"declared_license_expression_spdx": null,
"license_detections": [],
"other_license_expression": null,
"other_license_expression_spdx": null,
"other_license_detections": [],
"extracted_license_statement": null,
"notice_text": null,
"source_packages": [],
"file_references": [],
"is_private": false,
"is_virtual": false,
"extra_data": {
"ignore_files": [
"etc/",
"spec/",
"test/",
".gitignore",
".github/",
"hatchet.json",
"Gemfile",
"Gemfile.lock"
]
},
"dependencies": [],
"repository_homepage_url": null,
"repository_download_url": null,
"api_data_url": null,
"datasource_id": "buildpack_toml",
"purl": "pkg:generic/Java"
}
],
"for_packages": [],
"scan_errors": []
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
[buildpack]
name = "PHP"

[publish.Ignore]
files = [
".github/",
".gitignore",
".rspec_parallel",
"support/build/",
"support/devcenter/",
"test/",
"Gemfile",
"Gemfile.lock",
"hatchet.json",
"hatchet.lock",
"requirements.txt",
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
{
"packages": [],
"dependencies": [],
"files": [
{
"path": "buildpack.toml",
"type": "file",
"package_data": [
{
"type": "generic",
"namespace": null,
"name": "PHP",
"version": null,
"qualifiers": {},
"subpath": null,
"primary_language": null,
"description": "Heroku buildpack for PHP",
"release_date": null,
"parties": [],
"keywords": [],
"homepage_url": null,
"download_url": null,
"size": null,
"sha1": null,
"md5": null,
"sha256": null,
"sha512": null,
"bug_tracking_url": null,
"code_view_url": null,
"vcs_url": null,
"copyright": null,
"holder": null,
"declared_license_expression": null,
"declared_license_expression_spdx": null,
"license_detections": [],
"other_license_expression": null,
"other_license_expression_spdx": null,
"other_license_detections": [],
"extracted_license_statement": null,
"notice_text": null,
"source_packages": [],
"file_references": [],
"is_private": false,
"is_virtual": false,
"extra_data": {
"ignore_files": [
".github/",
".gitignore",
".rspec_parallel",
"support/build/",
"support/devcenter/",
"test/",
"Gemfile",
"Gemfile.lock",
"hatchet.json",
"hatchet.lock",
"requirements.txt"
]
},
"dependencies": [],
"repository_homepage_url": null,
"repository_download_url": null,
"api_data_url": null,
"datasource_id": "buildpack_toml",
"purl": "pkg:generic/PHP"
}
],
"for_packages": [],
"scan_errors": []
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
api = "0.8"

[buildpack]
description = "A buildpack for running the `dotnet execute` command for an app"
homepage = "https://github.com/paketo-buildpacks/dotnet-execute"
id = "paketo-buildpacks/dotnet-execute"
keywords = ["dotnet"]
name = "Paketo Buildpack for .NET Execute"
sbom-formats = ["application/vnd.cyclonedx+json", "application/spdx+json", "application/vnd.syft+json"]

[[buildpack.licenses]]
type = "Apache-2.0"
uri = "https://github.com/paketo-buildpacks/dotnet-execute/blob/main/LICENSE"

[metadata]
include-files = ["bin/build", "bin/detect", "bin/run", "bin/port-chooser", "buildpack.toml"]
pre-package = "./scripts/build.sh"

[[stacks]]
id = "*"
Loading
Loading