|
13 | 13 | from typing import Any, Callable, Dict, Optional, Tuple, List
|
14 | 14 | from pathlib import Path
|
15 | 15 | import os.path
|
| 16 | +import urllib |
16 | 17 |
|
| 18 | +import git |
17 | 19 | from packageurl import PackageURL
|
18 | 20 |
|
| 21 | +from atomic_reactor import constants |
| 22 | +from atomic_reactor.utils import retries |
| 23 | + |
19 | 24 | logger = logging.getLogger(__name__)
|
20 | 25 |
|
21 | 26 |
|
@@ -287,4 +292,89 @@ def clone_only(remote_source: Dict[str, Any]) -> bool:
|
287 | 292 | if pkg_managers is not None and len(pkg_managers) == 0:
|
288 | 293 | return True
|
289 | 294 |
|
| 295 | + # only git-submodule |
| 296 | + if pkg_managers is not None and pkg_managers == ['git-submodule']: |
| 297 | + return True |
| 298 | + |
290 | 299 | return False
|
| 300 | + |
| 301 | + |
| 302 | +def has_git_submodule_manager(remote_source: Dict[str, Any]) -> bool: |
| 303 | + """Returns true when for specific remote source git-submodule manager is requested""" |
| 304 | + pkg_managers = remote_source.get("pkg_managers") or [] |
| 305 | + return 'git-submodule' in pkg_managers |
| 306 | + |
| 307 | + |
| 308 | +def update_submodules(repopath: Path): |
| 309 | + """Update submodules in the given repo""" |
| 310 | + cmd = ["git", "submodule", "update", "--init", "--filter=blob:none"] |
| 311 | + params = { |
| 312 | + "cwd": str(repopath), |
| 313 | + "timeout": constants.GIT_CMD_TIMEOUT, |
| 314 | + } |
| 315 | + retries.run_cmd(cmd, **params) |
| 316 | + |
| 317 | + |
| 318 | +def get_submodules_sbom_components(repo: git.Repo) -> List[Dict]: |
| 319 | + """Get SBOM components of submodules in the specified repository""" |
| 320 | + |
| 321 | + def to_vcs_purl(pkg_name, repo_url, ref): |
| 322 | + """ |
| 323 | + Generate the vcs purl representation of the package. |
| 324 | +
|
| 325 | + Use the most specific purl type possible, e.g. pkg:github if repo comes from |
| 326 | + github.com. Fall back to using pkg:generic with a ?vcs_url qualifier. |
| 327 | +
|
| 328 | + :param str pkg_name: name of package |
| 329 | + :param str repo_url: url of git repository for package |
| 330 | + :param str ref: git ref of package |
| 331 | + :return: the PURL string of the Package object |
| 332 | + :rtype: str |
| 333 | + """ |
| 334 | + repo_url = repo_url.rstrip("/") |
| 335 | + parsed_url = urllib.parse.urlparse(repo_url) |
| 336 | + |
| 337 | + pkg_type_for_hostname = { |
| 338 | + "github.com": "github", |
| 339 | + "bitbucket.org": "bitbucket", |
| 340 | + } |
| 341 | + pkg_type = pkg_type_for_hostname.get(parsed_url.hostname, "generic") |
| 342 | + |
| 343 | + if pkg_type == "generic": |
| 344 | + vcs_url = urllib.parse.quote(f"{repo_url}@{ref}", safe="") |
| 345 | + purl = f"pkg:generic/{pkg_name}?vcs_url={vcs_url}" |
| 346 | + else: |
| 347 | + # pkg:github and pkg:bitbucket use the same format |
| 348 | + namespace, repo = parsed_url.path.lstrip("/").rsplit("/", 1) |
| 349 | + if repo.endswith(".git"): |
| 350 | + repo = repo[: -len(".git")] |
| 351 | + purl = f"pkg:{pkg_type}/{namespace.lower()}/{repo.lower()}@{ref}" |
| 352 | + |
| 353 | + return purl |
| 354 | + |
| 355 | + submodules_sbom_components = [ |
| 356 | + { |
| 357 | + "type": "library", |
| 358 | + "name": sm.name, |
| 359 | + "version": f"{sm.url}#{sm.hexsha}", |
| 360 | + "purl": to_vcs_purl(sm.name, sm.url, sm.hexsha) |
| 361 | + } |
| 362 | + for sm in repo.submodules |
| 363 | + ] |
| 364 | + |
| 365 | + return submodules_sbom_components |
| 366 | + |
| 367 | + |
| 368 | +def get_submodules_request_json_deps(repo: git.Repo) -> List[Dict]: |
| 369 | + """Get dependencies for request.json from submodule""" |
| 370 | + submodules_request_json_dependencies = [ |
| 371 | + { |
| 372 | + "type": "git-submodule", |
| 373 | + "name": sm.name, |
| 374 | + "path": sm.name, |
| 375 | + "version": f"{sm.url}#{sm.hexsha}", |
| 376 | + } |
| 377 | + for sm in repo.submodules |
| 378 | + ] |
| 379 | + |
| 380 | + return submodules_request_json_dependencies |
0 commit comments