Skip to content

Commit 9a340fc

Browse files
authored
Merge pull request #3855 from aboutcode-org/3837-refactor-swift-assembly
Consolidate Swift package assembly under a single BaseSwiftDatafileHandler
2 parents e3a94cd + 61eb4c4 commit 9a340fc

File tree

7 files changed

+1677
-178
lines changed

7 files changed

+1677
-178
lines changed

src/packagedcode/swift.py

+125-159
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,129 @@ def logger_debug(*args):
4747
return logger.debug(" ".join(isinstance(a, str) and a or repr(a) for a in args))
4848

4949

50-
class SwiftShowDependenciesDepLockHandler(models.DatafileHandler):
50+
class BaseSwiftDatafileHandler(models.DatafileHandler):
51+
@classmethod
52+
def assemble(cls, package_data, resource, codebase, package_adder):
53+
swift_manifest_resource = None
54+
swift_show_dependencies_resource = None
55+
swift_resolved_package_resource = None
56+
processed_package = None
57+
add_datafile_paths = []
58+
add_datasource_ids = []
59+
processed_dependencies = []
60+
61+
for r in resource.siblings(codebase):
62+
if r.name in ("Package.swift.json", "Package.swift.deplock"):
63+
swift_manifest_resource = r
64+
elif r.name in ("Package.resolved", ".package.resolved"):
65+
swift_resolved_package_resource = r
66+
elif r.name == "swift-show-dependencies.deplock":
67+
swift_show_dependencies_resource = r
68+
69+
# If only Package.resolved is available then yield all dependency as package.
70+
if (
71+
not swift_manifest_resource
72+
and not swift_show_dependencies_resource
73+
and resource.name in ("Package.resolved", ".package.resolved")
74+
):
75+
processed_package = package_data
76+
processed_dependencies = package_data.dependencies
77+
# If no manifest but have dependency graph from `deplock` then use it construct top-level package.
78+
elif (
79+
not swift_manifest_resource
80+
and resource.name == "swift-show-dependencies.deplock"
81+
):
82+
processed_package = package_data
83+
processed_dependencies = package_data.dependencies
84+
# If manifest is available then use the manifest to construct top-level package.
85+
elif swift_manifest_resource and resource.name in (
86+
"Package.swift.json",
87+
"Package.swift.deplock",
88+
):
89+
processed_dependencies = package_data.dependencies
90+
# Dependencies from `swift-show-dependencies.deplock` supersedes dependencies from other datafiles.
91+
if swift_show_dependencies_resource:
92+
swift_show_dependencies_package_data = models.PackageData.from_dict(
93+
swift_show_dependencies_resource.package_data[0]
94+
)
95+
processed_dependencies = (
96+
swift_show_dependencies_package_data.dependencies
97+
)
98+
# Use dependencies from `Package.resolved` when `swift-show-dependencies.deplock` is not present.
99+
elif swift_resolved_package_resource:
100+
swift_resolved_package_data = (
101+
swift_resolved_package_resource.package_data
102+
)
103+
104+
resolved_dependencies = []
105+
for package in swift_resolved_package_data:
106+
version = package.get("version")
107+
name = package.get("name")
108+
109+
purl = PackageURL(
110+
type=cls.default_package_type, name=name, version=version
111+
)
112+
resolved_dependencies.append(
113+
models.DependentPackage(
114+
purl=purl.to_string(),
115+
scope="dependencies",
116+
is_runtime=True,
117+
is_optional=False,
118+
is_resolved=True,
119+
extracted_requirement=version,
120+
)
121+
)
122+
123+
for dependency in processed_dependencies[:]:
124+
dependency_purl = PackageURL.from_string(dependency.purl)
125+
126+
if dependency_purl.name == name:
127+
processed_dependencies.remove(dependency)
128+
129+
processed_dependencies.extend(resolved_dependencies)
130+
131+
processed_package = package_data
132+
if swift_show_dependencies_resource:
133+
add_datafile_paths.append(swift_show_dependencies_resource.path)
134+
add_datasource_ids.append(
135+
SwiftShowDependenciesDepLockHandler.datasource_id
136+
)
137+
elif swift_resolved_package_resource:
138+
add_datafile_paths.append(swift_resolved_package_resource.path)
139+
add_datasource_ids.append(SwiftPackageResolvedHandler.datasource_id)
140+
141+
if processed_package and processed_package.purl:
142+
package = models.Package.from_package_data(
143+
package_data=processed_package,
144+
datafile_path=resource.path,
145+
)
146+
147+
package.datafile_paths.extend(add_datafile_paths)
148+
package.datasource_ids.extend(add_datasource_ids)
149+
150+
package.populate_license_fields()
151+
yield package
152+
153+
parent = resource.parent(codebase)
154+
cls.assign_package_to_resources(
155+
package=package,
156+
resource=parent,
157+
codebase=codebase,
158+
package_adder=package_adder,
159+
)
160+
161+
if processed_dependencies:
162+
yield from models.Dependency.from_dependent_packages(
163+
dependent_packages=processed_dependencies,
164+
datafile_path=resource.path,
165+
datasource_id=processed_package.datasource_id,
166+
package_uid=package.package_uid,
167+
)
168+
169+
yield resource
170+
171+
172+
class SwiftShowDependenciesDepLockHandler(BaseSwiftDatafileHandler):
51173
datasource_id = "swift_package_show_dependencies"
52174
path_patterns = ("*/swift-show-dependencies.deplock",)
53175
default_package_type = "swift"
@@ -86,32 +208,8 @@ def parse(cls, location, package_only=False):
86208

87209
yield cls._parse(swift_dependency_relation, package_only)
88210

89-
@classmethod
90-
def assemble(
91-
cls, package_data, resource, codebase, package_adder=models.add_to_package
92-
):
93-
siblings = resource.siblings(codebase)
94-
swift_manifest_resource = [
95-
r
96-
for r in siblings
97-
if r.name in ("Package.swift.json", "Package.swift.deplock")
98-
]
99-
100-
# Skip the assembly if the Swift manifest is present.
101-
# SwiftManifestJsonHandler's assembly will take care of the
102-
# dependencies from swift-show-dependencies.deplock file.
103-
if swift_manifest_resource:
104-
return []
105-
106-
yield from super(SwiftShowDependenciesDepLockHandler, cls).assemble(
107-
package_data=package_data,
108-
resource=resource,
109-
codebase=codebase,
110-
package_adder=package_adder,
111-
)
112211

113-
114-
class SwiftManifestJsonHandler(models.DatafileHandler):
212+
class SwiftManifestJsonHandler(BaseSwiftDatafileHandler):
115213
datasource_id = "swift_package_manifest_json"
116214
path_patterns = ("*/Package.swift.json", "*/Package.swift.deplock")
117215
default_package_type = "swift"
@@ -149,116 +247,8 @@ def parse(cls, location, package_only=False):
149247

150248
yield cls._parse(swift_manifest, package_only)
151249

152-
@classmethod
153-
def assemble(
154-
cls,
155-
package_data,
156-
resource,
157-
codebase,
158-
package_adder=models.add_to_package,
159-
):
160-
"""
161-
Use the dependencies from `Package.resolved` to create the
162-
top-level package with resolved dependencies.
163-
"""
164-
siblings = resource.siblings(codebase)
165-
processed_dependencies = []
166-
swift_resolved_package_resource = [
167-
r for r in siblings if r.name == "Package.resolved"
168-
]
169-
170-
swift_show_dependencies_resources = [
171-
r for r in siblings if r.name == "swift-show-dependencies.deplock"
172-
]
173-
174-
if swift_show_dependencies_resources:
175-
swift_show_dependencies_resource = swift_show_dependencies_resources[0]
176-
swift_show_dependencies_package_data = (
177-
swift_show_dependencies_resource.package_data
178-
)
179-
180-
# Dependencies from `swift-show-dependencies.deplock` supersede dependencies from other datafiles.
181-
processed_dependencies = swift_show_dependencies_package_data[0][
182-
"dependencies"
183-
]
184-
processed_dependencies = [
185-
models.DependentPackage.from_dict(i) for i in processed_dependencies
186-
]
187-
188-
# Use dependencies from `Package.resolved` when `swift-show-dependencies.deplock` is not present.
189-
else:
190-
dependencies_from_manifest = package_data.dependencies
191-
192-
if swift_resolved_package_resource:
193-
swift_resolved_package_resource = swift_resolved_package_resource[0]
194-
swift_resolved_package_data = (
195-
swift_resolved_package_resource.package_data
196-
)
197-
198-
for package in swift_resolved_package_data:
199-
version = package.get("version")
200-
name = package.get("name")
201-
202-
purl = PackageURL(
203-
type=cls.default_package_type, name=name, version=version
204-
)
205-
processed_dependencies.append(
206-
models.DependentPackage(
207-
purl=purl.to_string(),
208-
scope="dependencies",
209-
is_runtime=True,
210-
is_optional=False,
211-
is_resolved=True,
212-
extracted_requirement=version,
213-
)
214-
)
215-
216-
for dependency in dependencies_from_manifest[:]:
217-
dependency_purl = PackageURL.from_string(dependency.purl)
218-
219-
if dependency_purl.name == name:
220-
dependencies_from_manifest.remove(dependency)
221250

222-
processed_dependencies.extend(dependencies_from_manifest)
223-
224-
datafile_path = resource.path
225-
if package_data.purl:
226-
package = models.Package.from_package_data(
227-
package_data=package_data,
228-
datafile_path=datafile_path,
229-
)
230-
231-
if swift_show_dependencies_resources:
232-
package.datafile_paths.append(swift_show_dependencies_resource.path)
233-
package.datasource_ids.append(
234-
SwiftShowDependenciesDepLockHandler.datasource_id
235-
)
236-
elif swift_resolved_package_resource:
237-
package.datafile_paths.append(swift_resolved_package_resource.path)
238-
package.datasource_ids.append(SwiftPackageResolvedHandler.datasource_id)
239-
240-
package.populate_license_fields()
241-
yield package
242-
243-
parent = resource.parent(codebase)
244-
cls.assign_package_to_resources(
245-
package=package,
246-
resource=parent,
247-
codebase=codebase,
248-
package_adder=package_adder,
249-
)
250-
251-
if processed_dependencies:
252-
yield from models.Dependency.from_dependent_packages(
253-
dependent_packages=processed_dependencies,
254-
datafile_path=datafile_path,
255-
datasource_id=package_data.datasource_id,
256-
package_uid=package.package_uid,
257-
)
258-
yield resource
259-
260-
261-
class SwiftPackageResolvedHandler(models.DatafileHandler):
251+
class SwiftPackageResolvedHandler(BaseSwiftDatafileHandler):
262252
datasource_id = "swift_package_resolved"
263253
path_patterns = ("*/Package.resolved", "*/.package.resolved")
264254
default_package_type = "swift"
@@ -282,30 +272,6 @@ def parse(cls, location, package_only=False):
282272
if resolved_doc_version == 1:
283273
yield from packages_from_resolved_v1(package_resolved)
284274

285-
@classmethod
286-
def assemble(
287-
cls, package_data, resource, codebase, package_adder=models.add_to_package
288-
):
289-
siblings = resource.siblings(codebase)
290-
swift_manifest_resource = [
291-
r
292-
for r in siblings
293-
if r.name in ("Package.swift.json", "Package.swift.deplock")
294-
]
295-
296-
# Skip the assembly if the ``Package.swift.json`` manifest is present.
297-
# SwiftManifestJsonHandler's assembly will take care of the resolved
298-
# dependencies from Package.resolved file.
299-
if swift_manifest_resource:
300-
return []
301-
302-
yield from super(SwiftPackageResolvedHandler, cls).assemble(
303-
package_data=package_data,
304-
resource=resource,
305-
codebase=codebase,
306-
package_adder=package_adder,
307-
)
308-
309275

310276
def packages_from_resolved_v2_and_v3(package_resolved):
311277
pinned = package_resolved.get("pins", [])
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,25 @@
11
{
2-
"object": {
3-
"pins": [
4-
{
5-
"package": "SwiftShell",
6-
"repositoryURL": "https://github.com/kareman/SwiftShell",
7-
"state": {
8-
"branch": null,
9-
"revision": "99680b2efc7c7dbcace1da0b3979d266f02e213c",
10-
"version": "5.1.0"
11-
}
12-
}
13-
]
14-
},
15-
"version": 1
2+
"object":{
3+
"pins":[
4+
{
5+
"package":"SwiftShell",
6+
"repositoryURL":"https://github.com/kareman/SwiftShell",
7+
"state":{
8+
"branch":null,
9+
"revision":"99680b2efc7c7dbcace1da0b3979d266f02e213c",
10+
"version":"5.1.0"
11+
}
12+
},
13+
{
14+
"package":"swift-atomics",
15+
"repositoryURL":"https://github.com/apple/swift-atomics.git",
16+
"state":{
17+
"branch":null,
18+
"revision":"6c89474e62719ddcc1e9614989fff2f68208fe10",
19+
"version":"1.1.0"
20+
}
21+
}
22+
]
23+
},
24+
"version":1
1625
}

0 commit comments

Comments
 (0)