Skip to content

Commit 9ed2cb4

Browse files
authored
Merge pull request #2748 from nexB/2098-top-level-packages
Add PackageManifest Class
2 parents 6d02ff8 + 7b5cf8c commit 9ed2cb4

220 files changed

Lines changed: 16428 additions & 14508 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

src/packagedcode/__init__.py

Lines changed: 58 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
from packagedcode import freebsd
2121
from packagedcode import golang
2222
from packagedcode import haxe
23+
from packagedcode import jar_manifest
2324
from packagedcode import maven
2425
from packagedcode import models
2526
from packagedcode import msi
@@ -38,73 +39,99 @@
3839

3940
# Note: the order matters: from the most to the least specific
4041
# Package classes MUST be added to this list to be active
41-
PACKAGE_TYPES = [
42-
rpm.RpmPackage,
42+
PACKAGE_MANIFEST_TYPES = [
43+
rpm.RpmManifest,
4344
debian.DebianPackage,
4445

4546
models.JavaJar,
47+
jar_manifest.JavaManifest,
4648
models.JavaEar,
4749
models.JavaWar,
4850
maven.MavenPomPackage,
49-
models.IvyJar,
51+
jar_manifest.IvyJar,
5052
models.JBossSar,
5153
models.Axis2Mar,
5254

53-
about.AboutPackage,
54-
npm.NpmPackage,
55-
phpcomposer.PHPComposerPackage,
56-
haxe.HaxePackage,
57-
cargo.RustCargoCrate,
58-
cocoapods.CocoapodsPackage,
59-
opam.OpamPackage,
55+
about.Aboutfile,
56+
npm.PackageJson,
57+
npm.PackageLockJson,
58+
npm.YarnLockJson,
59+
phpcomposer.ComposerJson,
60+
phpcomposer.ComposerLock,
61+
haxe.HaxelibJson,
62+
cargo.CargoToml,
63+
cargo.CargoLock,
64+
cocoapods.Podspec,
65+
cocoapods.PodfileLock,
66+
cocoapods.PodspecJson,
67+
opam.OpamFile,
6068
models.MeteorPackage,
61-
bower.BowerPackage,
62-
freebsd.FreeBSDPackage,
69+
bower.BowerJson,
70+
freebsd.CompactManifest,
6371
models.CpanModule,
64-
rubygems.RubyGem,
72+
rubygems.GemArchive,
73+
rubygems.GemArchiveExtracted,
74+
rubygems.GemSpec,
75+
rubygems.GemfileLock,
6576
models.AndroidApp,
6677
models.AndroidLibrary,
6778
models.MozillaExtension,
6879
models.ChromeExtension,
6980
models.IOSApp,
70-
pypi.PythonPackage,
71-
golang.GolangPackage,
81+
pypi.MetadataFile,
82+
pypi.BinaryDistArchive,
83+
pypi.SourceDistArchive,
84+
pypi.SetupPy,
85+
pypi.DependencyFile,
86+
pypi.PipfileLock,
87+
pypi.RequirementsFile,
88+
golang.GoMod,
89+
golang.GoSum,
7290
models.CabPackage,
7391
models.InstallShieldPackage,
7492
models.NSISInstallerPackage,
75-
nuget.NugetPackage,
93+
nuget.Nuspec,
7694
models.SharPackage,
7795
models.AppleDmgPackage,
7896
models.IsoImagePackage,
7997
models.SquashfsPackage,
80-
chef.ChefPackage,
98+
chef.MetadataJson,
99+
chef.Metadatarb,
81100
build.BazelPackage,
82101
build.BuckPackage,
83102
build.AutotoolsPackage,
84-
conda.CondaPackage,
85-
win_pe.WindowsExecutable,
86-
readme.ReadmePackage,
103+
conda.Condayml,
104+
win_pe.WindowsExecutableManifest,
105+
readme.ReadmeManifest,
87106
build.MetadataBzl,
88107
msi.MsiInstallerPackage,
89-
windows.MicrosoftUpdateManifestPackage,
90-
pubspec.PubspecPackage,
108+
windows.MicrosoftUpdateManifest,
109+
pubspec.PubspecYaml,
110+
pubspec.PubspecLock
91111
]
92112

93-
PACKAGES_BY_TYPE = {cls.default_type: cls for cls in PACKAGE_TYPES}
94-
113+
PACKAGE_MANIFESTS_BY_TYPE = {
114+
(
115+
cls.package_manifest_type
116+
if isinstance(cls, models.PackageManifest)
117+
else cls.default_type
118+
): cls
119+
for cls in PACKAGE_MANIFEST_TYPES
120+
}
95121
# We cannot have two package classes with the same type
96-
if len(PACKAGES_BY_TYPE) != len(PACKAGE_TYPES):
122+
if len(PACKAGE_MANIFESTS_BY_TYPE) != len(PACKAGE_MANIFEST_TYPES):
97123
seen_types = {}
98-
for pt in PACKAGE_TYPES:
99-
assert pt.default_type
100-
seen = seen_types.get(pt.default_type)
124+
for pmt in PACKAGE_MANIFEST_TYPES:
125+
manifest = pmt()
126+
assert manifest.package_manifest_type
127+
seen = seen_types.get(manifest.package_manifest_type)
101128
if seen:
102129
msg = ('Invalid duplicated packagedcode.Package types: '
103130
'"{}:{}" and "{}:{}" have the same type.'
104-
.format(pt.default_type, pt.__name__, seen.default_type, seen.__name__,))
131+
.format(manifest.package_manifest_type, manifest.__name__, seen.package_manifest_type, seen.__name__,))
105132
raise Exception(msg)
106133
else:
107-
seen_types[pt.default_type] = pt
134+
seen_types[manifest.package_manifest_type] = manifest
108135

109136

110137
def get_package_class(scan_data, default=models.Package):
@@ -130,7 +157,7 @@ def get_package_class(scan_data, default=models.Package):
130157
if not ptype:
131158
# basic type for default package types
132159
return default
133-
ptype_class = PACKAGES_BY_TYPE.get(ptype)
160+
ptype_class = PACKAGE_MANIFESTS_BY_TYPE.get(ptype)
134161
return ptype_class or default
135162

136163

src/packagedcode/about.py

Lines changed: 52 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -30,12 +30,8 @@
3030

3131
@attr.s()
3232
class AboutPackage(models.Package):
33-
metafiles = ('*.ABOUT',)
34-
default_type = 'about'
3533

36-
@classmethod
37-
def recognize(cls, location):
38-
yield parse(location)
34+
default_type = 'about'
3935

4036
def get_package_root(self, manifest_resource, codebase):
4137
about_resource = self.extra_data.get('about_resource')
@@ -47,53 +43,54 @@ def get_package_root(self, manifest_resource, codebase):
4743
return manifest_resource
4844

4945

50-
def is_about_file(location):
51-
return (filetype.is_file(location)
52-
and location.lower().endswith(('.about',)))
53-
54-
55-
def parse(location):
56-
"""
57-
Return a Package object from an ABOUT file or None.
58-
"""
59-
if not is_about_file(location):
60-
return
61-
62-
with io.open(location, encoding='utf-8') as loc:
63-
package_data = saneyaml.load(loc.read())
64-
65-
return build_package(package_data)
66-
67-
68-
def build_package(package_data):
69-
"""
70-
Return a Package built from `package_data` obtained by an ABOUT file.
71-
"""
72-
name = package_data.get('name')
73-
# FIXME: having no name may not be a problem See #1514
74-
if not name:
75-
return
76-
77-
version = package_data.get('version')
78-
homepage_url = package_data.get('home_url') or package_data.get('homepage_url')
79-
download_url = package_data.get('download_url')
80-
declared_license = package_data.get('license_expression')
81-
copyright_statement = package_data.get('copyright')
82-
83-
owner = package_data.get('owner')
84-
if not isinstance(owner, str):
85-
owner = repr(owner)
86-
parties = [models.Party(type=models.party_person, name=owner, role='owner')]
87-
88-
about_package = AboutPackage(
89-
type='about',
90-
name=name,
91-
version=version,
92-
declared_license=declared_license,
93-
copyright=copyright_statement,
94-
parties=parties,
95-
homepage_url=homepage_url,
96-
download_url=download_url,
97-
)
98-
about_package.extra_data['about_resource'] = package_data.get('about_resource')
99-
return about_package
46+
@attr.s()
47+
class Aboutfile(AboutPackage, models.PackageManifest):
48+
49+
file_patterns = ('*.ABOUT',)
50+
extensions = ('.ABOUT',)
51+
52+
@classmethod
53+
def is_manifest(cls, location):
54+
"""
55+
Return True if the file at ``location`` is likely a manifest of this type.
56+
"""
57+
return filetype.is_file(location) and location.lower().endswith(('.about',))
58+
59+
@classmethod
60+
def recognize(cls, location):
61+
"""
62+
Yield one or more Package manifest objects given a file ``location`` pointing to a
63+
package archive, manifest or similar.
64+
"""
65+
with io.open(location, encoding='utf-8') as loc:
66+
package_data = saneyaml.load(loc.read())
67+
68+
name = package_data.get('name')
69+
# FIXME: having no name may not be a problem See #1514
70+
if not name:
71+
return
72+
73+
version = package_data.get('version')
74+
homepage_url = package_data.get('home_url') or package_data.get('homepage_url')
75+
download_url = package_data.get('download_url')
76+
declared_license = package_data.get('license_expression')
77+
copyright_statement = package_data.get('copyright')
78+
79+
owner = package_data.get('owner')
80+
if not isinstance(owner, str):
81+
owner = repr(owner)
82+
parties = [models.Party(type=models.party_person, name=owner, role='owner')]
83+
84+
about_package = cls(
85+
type='about',
86+
name=name,
87+
version=version,
88+
declared_license=declared_license,
89+
copyright=copyright_statement,
90+
parties=parties,
91+
homepage_url=homepage_url,
92+
download_url=download_url,
93+
)
94+
95+
about_package.extra_data['about_resource'] = package_data.get('about_resource')
96+
yield about_package

src/packagedcode/alpine.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727

2828

2929
@attr.s()
30-
class AlpinePackage(models.Package):
30+
class AlpinePackage(models.Package, models.PackageManifest):
3131
extensions = ('.apk', 'APKBUILD')
3232
default_type = 'alpine'
3333

0 commit comments

Comments
 (0)