Skip to content

Commit adc0862

Browse files
committed
Adopt new handler design for Dart pub packages
We now have these data file handlers: * DartPubspecYamlHandler * DartPubspecLockHandler And we assemble these in Packages correctly. Signed-off-by: Philippe Ombredanne <[email protected]>
1 parent 3dc5dd8 commit adc0862

12 files changed

+137
-161
lines changed

src/packagedcode/pubspec.py

Lines changed: 85 additions & 118 deletions
Original file line numberDiff line numberDiff line change
@@ -7,40 +7,17 @@
77
# See https://aboutcode.org for more information about nexB OSS projects.
88
#
99

10-
import logging
11-
import sys
1210
import warnings
1311

14-
import attr
1512
import saneyaml
16-
from commoncode import filetype
1713
from packageurl import PackageURL
1814

1915
from packagedcode import models
2016
from packagedcode.utils import combine_expressions
21-
22-
TRACE = False
23-
24-
25-
def logger_debug(*args):
26-
pass
27-
28-
29-
logger = logging.getLogger(__name__)
30-
31-
if TRACE:
32-
logging.basicConfig(stream=sys.stdout)
33-
logger.setLevel(logging.DEBUG)
34-
35-
def logger_debug(*args):
36-
return logger.debug(''.join(isinstance(a, str) and a or repr(a) for a in args))
37-
3817
"""
3918
Collect data from Dart pub packages.
4019
See https://dart.dev/tools/pub/pubspec
41-
"""
4220
43-
"""
4421
TODO:
4522
- license is only in a LICENSE file
4623
https://dart.dev/tools/pub/publishing#preparing-to-publish
@@ -56,34 +33,51 @@ def logger_debug(*args):
5633
See https://github.com/dart-lang/pub/blob/master/doc/repository-spec-v2.md
5734
"""
5835

36+
# FIXME: warnings reported here DO NOT work. We should have a better way
5937

60-
@attr.s()
61-
class PubspecPackageData(models.PackageData):
62-
default_type = 'pubspec'
63-
default_primary_language = 'dart'
64-
default_web_baseurl = 'https://pub.dev/packages'
65-
default_download_baseurl = 'https://pub.dartlang.org/packages'
66-
default_api_baseurl = 'https://pub.dev/api/packages'
6738

68-
def repository_homepage_url(self, baseurl=default_web_baseurl):
69-
return f'{baseurl}/{self.name}/versions/{self.version}'
39+
class BaseDartPubspecHandler(models.DatafileHandler):
40+
41+
@classmethod
42+
def assemble(cls, package_data, resource, codebase):
43+
datafile_name_patterns = \
44+
DartPubspecYamlHandler.path_patterns + DartPubspecLockHandler.path_patterns
45+
46+
if resource.has_parent():
47+
dir_resource=resource.parent(codebase)
48+
else:
49+
dir_resource=resource
7050

71-
def repository_download_url(self, baseurl=default_download_baseurl):
72-
# A URL should be in the form of:
73-
# https://pub.dartlang.org/packages/url_launcher/versions/6.0.9.tar.gz
74-
# And it may resolve to:
75-
# https://storage.googleapis.com/pub-packages/packages/http-0.13.2.tar.gz
76-
# as seen in the pub.dev web pages
77-
return f'{baseurl}/{self.name}/versions/{self.version}.tar.gz'
51+
yield from cls.assemble_from_many_datafiles(
52+
datafile_name_patterns=datafile_name_patterns,
53+
directory=dir_resource,
54+
codebase=codebase,
55+
)
7856

79-
def api_data_url(self, baseurl=default_api_baseurl):
80-
return f'{baseurl}/{self.name}/versions/{self.version}'
57+
@classmethod
58+
def compute_normalized_license(cls, package):
59+
return compute_normalized_license(package.declared_license)
8160

82-
def compute_normalized_license(self):
83-
return compute_normalized_license(self.declared_license)
8461

62+
class DartPubspecYamlHandler(BaseDartPubspecHandler):
63+
datasource_id = 'pubspec_yaml'
64+
path_patterns = ('*pubspec.yaml',)
65+
default_package_type = 'pubspec'
66+
default_primary_language = 'dart'
67+
description = 'Dart pubspec manifest'
68+
documentation_url = 'https://dart.dev/tools/pub/pubspec'
8569

86-
def compute_normalized_license(declared_license, location=None):
70+
@classmethod
71+
def parse(cls, location):
72+
with open(location) as inp:
73+
pubspec_data = saneyaml.load(inp.read())
74+
75+
package_data = build_package(pubspec_data)
76+
if package_data:
77+
yield package_data
78+
79+
80+
def compute_normalized_license(declared_license):
8781
"""
8882
Return a normalized license expression string detected from a list of
8983
declared license items.
@@ -106,79 +100,27 @@ def compute_normalized_license(declared_license, location=None):
106100
return combine_expressions(detected_licenses)
107101

108102

109-
@attr.s()
110-
class PubspecYaml(PubspecPackageData, models.PackageDataFile):
111-
112-
file_patterns = ('*pubspec.yaml',)
113-
extensions = ('.yaml',)
114-
115-
@classmethod
116-
def is_package_data_file(cls, location):
117-
"""
118-
Return True if the file at ``location`` is likely a manifest of this type.
119-
"""
120-
return file_endswith(location, 'pubspec.yaml')
121-
122-
@classmethod
123-
def recognize(cls, location, compute_normalized_license=False):
124-
"""
125-
Yield one or more Package manifest objects given a file ``location`` pointing to a
126-
package archive, manifest or similar.
127-
"""
128-
with open(location) as inp:
129-
package_data = saneyaml.load(inp.read())
130-
131-
package = build_package(cls, package_data)
132-
if package and compute_normalized_license:
133-
package.compute_normalized_license()
134-
yield package
135-
136-
137-
def file_endswith(location, endswith):
138-
"""
139-
Check if the file at ``location`` ends with ``endswith`` string or tuple.
140-
"""
141-
return filetype.is_file(location) and location.endswith(endswith)
142-
143-
144-
@attr.s()
145-
class PubspecLock(PubspecPackageData, models.PackageDataFile):
146-
147-
file_patterns = ('*pubspec.lock',)
148-
extensions = ('.lock',)
149-
150-
@classmethod
151-
def is_package_data_file(cls, location):
152-
"""
153-
Return True if the file at ``location`` is likely a manifest of this type.
154-
"""
155-
return file_endswith(location, 'pubspec.lock')
103+
class DartPubspecLockHandler(BaseDartPubspecHandler):
104+
datasource_id = 'pubspec_lock'
105+
path_patterns = ('*pubspec.lock',)
106+
default_package_type = 'pubspec'
107+
default_primary_language = 'dart'
108+
description = 'Dart pubspec lockfile'
109+
documentation_url = 'https://web.archive.org/web/20220330081004/https://gpalma.pt/blog/what-is-the-pubspec-lock/'
156110

157111
@classmethod
158-
def recognize(cls, location):
159-
"""
160-
Yield one or more Package manifest objects given a file ``location`` pointing to a
161-
package archive, manifest or similar.
162-
"""
112+
def parse(cls, location):
163113
with open(location) as inp:
164114
locks_data = saneyaml.load(inp.read())
165115

166-
yield cls(dependencies=list(collect_locks(locks_data)))
167-
168-
169-
@attr.s()
170-
class PubspecPackage(PubspecPackageData, models.Package):
171-
"""
172-
A Pubspec Package that is created out of one/multiple pubspec package
173-
manifests.
174-
"""
116+
dependencies = list(collect_locks(locks_data))
175117

176-
@property
177-
def manifests(self):
178-
return [
179-
PubspecYaml,
180-
PubspecLock
181-
]
118+
yield models.PackageData(
119+
datasource_id=cls.datasource_id,
120+
type=cls.default_package_type,
121+
primary_language=cls.default_primary_language,
122+
dependencies=dependencies
123+
)
182124

183125

184126
def collect_locks(locks_data):
@@ -303,10 +245,17 @@ def build_dep(name, version, scope, is_runtime=True, is_optional=False):
303245

304246
if version.replace('.', '').isdigit():
305247
# version is pinned exactly if it is only made of dots and digits
306-
purl = PackageURL(type='pubspec', name=name, version=version)
248+
purl = PackageURL(
249+
type='pubspec',
250+
name=name,
251+
version=version,
252+
)
307253
is_resolved = True
308254
else:
309-
purl = PackageURL(type='pubspec', name=name)
255+
purl = PackageURL(
256+
type='pubspec',
257+
name=name,
258+
)
310259
is_resolved = False
311260

312261
dep = models.DependentPackage(
@@ -320,7 +269,7 @@ def build_dep(name, version, scope, is_runtime=True, is_optional=False):
320269
return dep
321270

322271

323-
def build_package(cls, pubspec_data):
272+
def build_package(pubspec_data):
324273
"""
325274
Return a package object from a package data mapping or None
326275
"""
@@ -332,6 +281,18 @@ def build_package(cls, pubspec_data):
332281
vcs_url = pubspec_data.get('repository')
333282
download_url = pubspec_data.get('archive_url')
334283

284+
api_data_url = name and version and f'https://pub.dev/api/packages/{name}/versions/{version}'
285+
repository_homepage_url = name and version and f'https://pub.dev/packages/{name}/versions/{version}'
286+
287+
# A URL should be in the form of:
288+
# https://pub.dartlang.org/packages/url_launcher/versions/6.0.9.tar.gz
289+
# And it may resolve to:
290+
# https://storage.googleapis.com/pub-packages/packages/http-0.13.2.tar.gz
291+
# as seen in the pub.dev web pages
292+
repository_download_url = name and version and f'https://pub.dartlang.org/packages/{name}/versions/{version}.tar.gz'
293+
294+
download_url = download_url or repository_download_url
295+
335296
# Author and authors are deprecated
336297
authors = []
337298
author = pubspec_data.get('author')
@@ -385,20 +346,26 @@ def add_to_extra_if_present(_key):
385346
add_to_extra_if_present('executables')
386347
add_to_extra_if_present('publish_to')
387348

388-
package = cls(
349+
package = models.PackageData(
350+
datasource_id=DartPubspecYamlHandler.datasource_id,
351+
type=DartPubspecYamlHandler.default_primary_language,
352+
primary_language=DartPubspecYamlHandler.default_primary_language,
389353
name=name,
390354
version=version,
355+
download_url=download_url,
391356
vcs_url=vcs_url,
392357
description=description,
393358
declared_license=declared_license,
394359
parties=parties,
395360
homepage_url=homepage_url,
396361
dependencies=package_dependencies,
397362
extra_data=extra_data,
363+
repository_homepage_url=repository_homepage_url,
364+
api_data_url=api_data_url,
365+
repository_download_url=repository_download_url,
398366
)
399367

400-
if not download_url:
401-
package.download_url = package.repository_download_url()
368+
if not package.license_expression and package.declared_license:
369+
package.license_expression = models.compute_normalized_license(package.declared_license)
402370

403371
return package
404-

tests/packagedcode/data/pubspec/locks/dart-pubspec.lock-expected.json

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,8 @@
2525
"license_expression": null,
2626
"declared_license": null,
2727
"notice_text": null,
28-
"contains_source_code": null,
2928
"source_packages": [],
29+
"file_references": [],
3030
"extra_data": {},
3131
"dependencies": [
3232
{
@@ -543,9 +543,10 @@
543543
"resolved_package": {}
544544
}
545545
],
546-
"purl": null,
547546
"repository_homepage_url": null,
548547
"repository_download_url": null,
549-
"api_data_url": null
548+
"api_data_url": null,
549+
"datasource_id": "pubspec_lock",
550+
"purl": null
550551
}
551552
]

tests/packagedcode/data/pubspec/locks/stock-pubspec.lock-expected.json

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,8 @@
2525
"license_expression": null,
2626
"declared_license": null,
2727
"notice_text": null,
28-
"contains_source_code": null,
2928
"source_packages": [],
29+
"file_references": [],
3030
"extra_data": {},
3131
"dependencies": [
3232
{
@@ -417,9 +417,10 @@
417417
"resolved_package": {}
418418
}
419419
],
420-
"purl": null,
421420
"repository_homepage_url": null,
422421
"repository_download_url": null,
423-
"api_data_url": null
422+
"api_data_url": null,
423+
"datasource_id": "pubspec_lock",
424+
"purl": null
424425
}
425426
]

tests/packagedcode/data/pubspec/locks/weather-pubspec.lock-expected.json

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,8 @@
2525
"license_expression": null,
2626
"declared_license": null,
2727
"notice_text": null,
28-
"contains_source_code": null,
2928
"source_packages": [],
29+
"file_references": [],
3030
"extra_data": {},
3131
"dependencies": [
3232
{
@@ -660,9 +660,10 @@
660660
"resolved_package": {}
661661
}
662662
],
663-
"purl": null,
664663
"repository_homepage_url": null,
665664
"repository_download_url": null,
666-
"api_data_url": null
665+
"api_data_url": null,
666+
"datasource_id": "pubspec_lock",
667+
"purl": null
667668
}
668669
]

tests/packagedcode/data/pubspec/mini-pubspec.lock-expected.json

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,8 @@
2525
"license_expression": null,
2626
"declared_license": null,
2727
"notice_text": null,
28-
"contains_source_code": null,
2928
"source_packages": [],
29+
"file_references": [],
3030
"extra_data": {},
3131
"dependencies": [
3232
{
@@ -93,9 +93,10 @@
9393
"resolved_package": {}
9494
}
9595
],
96-
"purl": null,
9796
"repository_homepage_url": null,
9897
"repository_download_url": null,
99-
"api_data_url": null
98+
"api_data_url": null,
99+
"datasource_id": "pubspec_lock",
100+
"purl": null
100101
}
101102
]

0 commit comments

Comments
 (0)