Added the SWI Prolog (swipl) ecosystem (#3076)

* Add binary classifier for swipl

Signed-off-by: Laurent Goderre <laurent.goderre@docker.com>

* Added cataloger for SWI Prolog Pack packages

Signed-off-by: Laurent Goderre <laurent.goderre@docker.com>

---------

Signed-off-by: Laurent Goderre <laurent.goderre@docker.com>
This commit is contained in:
Laurent Goderre
2024-07-31 16:13:26 -04:00
committed by GitHub
parent a4b5dcd0df
commit 92d63df6f5
32 changed files with 2992 additions and 8 deletions
+15
View File
@@ -0,0 +1,15 @@
/*
Package swipl provides a Cataloger implementation relating to packages within the SWI Prolog language ecosystem.
*/
package swipl
import (
"github.com/anchore/syft/syft/pkg"
"github.com/anchore/syft/syft/pkg/cataloger/generic"
)
// NewSwiplPackCataloger returns a new SWI Prolog Pack package manager cataloger object.
func NewSwiplPackCataloger() pkg.Cataloger {
return generic.NewCataloger("swipl-pack-cataloger").
WithParserByGlobs(parsePackPackage, "**/pack.pl")
}
@@ -0,0 +1,32 @@
package swipl
import (
"testing"
"github.com/anchore/syft/syft/pkg/cataloger/internal/pkgtest"
)
func Test_Cataloger_Globs(t *testing.T) {
tests := []struct {
name string
fixture string
expected []string
}{
{
name: "obtain swipl pack files",
fixture: "test-fixtures/glob-paths",
expected: []string{
"pack.pl",
},
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
pkgtest.NewCatalogTester().
FromDirectory(t, test.fixture).
ExpectsResolverContentQueries(test.expected).
TestCataloger(t, NewSwiplPackCataloger())
})
}
}
+38
View File
@@ -0,0 +1,38 @@
package swipl
import (
// "strings"
"github.com/anchore/packageurl-go"
"github.com/anchore/syft/syft/file"
"github.com/anchore/syft/syft/pkg"
)
func newSwiplPackPackage(m pkg.SwiplPackEntry, locations ...file.Location) pkg.Package {
p := pkg.Package{
Name: m.Name,
Version: m.Version,
PURL: swiplpackPackageURL(m.Name, m.Version),
Locations: file.NewLocationSet(locations...),
Type: pkg.SwiplPackPkg,
Language: pkg.Swipl,
Metadata: m,
}
p.SetID()
return p
}
func swiplpackPackageURL(name, version string) string {
var qualifiers packageurl.Qualifiers
return packageurl.NewPackageURL(
"swiplpack",
"",
name,
version,
qualifiers,
"",
).ToString()
}
+33
View File
@@ -0,0 +1,33 @@
package swipl
import (
"testing"
"github.com/stretchr/testify/assert"
)
func Test_swiplpackPackageURL(t *testing.T) {
type args struct {
name string
version string
}
tests := []struct {
name string
args args
want string
}{
{
name: "go case",
args: args{
name: "name",
version: "v0.1.0",
},
want: "pkg:swiplpack/name@v0.1.0",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
assert.Equal(t, tt.want, swiplpackPackageURL(tt.args.name, tt.args.version))
})
}
}
+70
View File
@@ -0,0 +1,70 @@
package swipl
import (
"context"
"io"
"regexp"
"github.com/anchore/syft/internal/log"
"github.com/anchore/syft/syft/artifact"
"github.com/anchore/syft/syft/file"
"github.com/anchore/syft/syft/pkg"
"github.com/anchore/syft/syft/pkg/cataloger/generic"
)
func parsePackPackage(_ context.Context, _ file.Resolver, _ *generic.Environment, reader file.LocationReadCloser) ([]pkg.Package, []artifact.Relationship, error) {
var pkgs []pkg.Package
nameRe := regexp.MustCompile(`name\(\s*'?([^')]+)'?\s*\)`)
versionRe := regexp.MustCompile(`version\('([^']+)'\)`)
homeRe := regexp.MustCompile(`home\(\s*'([^']+)'\s*\)`)
authorRe := regexp.MustCompile(`(author|packager)\(\s*'([^']+)'\s*(?:,\s*'([^']+)'\s*)?\)`)
data, err := io.ReadAll(reader)
if err != nil {
log.WithFields("error", err).Trace("unable to parse Rockspec app")
return nil, nil, nil
}
name := nameRe.FindSubmatch(data)
version := versionRe.FindSubmatch(data)
if name == nil || version == nil {
log.Debugf("encountered pack.pl file without a name and/or version field, ignoring (path=%q)", reader.Path())
return nil, nil, nil
}
entry := pkg.SwiplPackEntry{
Name: string(name[1]),
Version: string(version[1]),
}
home := homeRe.FindSubmatch(data)
if home != nil {
entry.Homepage = string(home[1])
}
authors := authorRe.FindAllSubmatch(data, -1)
for _, a := range authors {
switch string(a[1]) {
case "author":
entry.Author = string(a[2])
entry.AuthorEmail = string(a[3])
case "packager":
entry.Packager = string(a[2])
entry.PackagerEmail = string(a[3])
}
}
pkgs = append(
pkgs,
newSwiplPackPackage(
entry,
reader.Location.WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation),
),
)
return pkgs, nil, nil
}
@@ -0,0 +1,39 @@
package swipl
import (
"testing"
"github.com/anchore/syft/syft/artifact"
"github.com/anchore/syft/syft/file"
"github.com/anchore/syft/syft/pkg"
"github.com/anchore/syft/syft/pkg/cataloger/internal/pkgtest"
)
func TestParsePackPackage(t *testing.T) {
fixture := "test-fixtures/pack.pl"
locations := file.NewLocationSet(file.NewLocation(fixture))
expectedPkgs := []pkg.Package{
{
Name: "hdt",
Version: "0.5.2",
PURL: "pkg:swiplpack/hdt@0.5.2",
Locations: locations,
Language: pkg.Swipl,
Type: pkg.SwiplPackPkg,
Metadata: pkg.SwiplPackEntry{
Name: "hdt",
Version: "0.5.2",
Author: "Jan Wielemaker",
AuthorEmail: "J.Wielemaker@vu.nl",
Packager: "Jan Wielemaker",
PackagerEmail: "J.Wielemaker@vu.nl",
Homepage: "https://github.com/JanWielemaker/hdt",
},
},
}
// TODO: no relationships are under test yet
var expectedRelationships []artifact.Relationship
pkgtest.TestFileParser(t, fixture, parsePackPackage, expectedPkgs, expectedRelationships)
}
@@ -0,0 +1 @@
bogus
@@ -0,0 +1,10 @@
name(hdt).
version('0.5.2').
% TODO: swipl_version([90121]).
title('Access RDF HDT files').
keywords(['RDF']).
author( 'Jan Wielemaker', 'J.Wielemaker@vu.nl' ).
packager( 'Jan Wielemaker', 'J.Wielemaker@vu.nl' ).
maintainer( 'Jan Wielemaker', 'J.Wielemaker@vu.nl' ).
home( 'https://github.com/JanWielemaker/hdt' ).
download( 'https://github.com/JanWielemaker/hdt/archive/V*.zip' ).