generated from oracle/template-repo
-
Notifications
You must be signed in to change notification settings - Fork 28
feat: obtain Java and Python artifacts from .m2 or Python virtual environment from input #864
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
tromai
merged 16 commits into
staging
from
811-use-cached-artifacts-instead-of-downloading-them-when-possible
Dec 18, 2024
Merged
Changes from all commits
Commits
Show all changes
16 commits
Select commit
Hold shift + click to select a range
00c775c
chore: add --local-maven-repo as input option
tromai 5b1e99e
chore: improve run_macaron.sh on local maven repo mounting behavior a…
tromai 5ea77ee
chore: add maven local artifact finding
tromai d7a2712
chore: allow multiple artifact paths for a purl type
tromai 9be38a6
chore: refactor the local artifact finding logic and add pypi support
tromai bce54d6
chore: improve doc strings
tromai e64c7c9
chore: update command_analyze rst
tromai 072879c
chore: fix typo
tromai 33fed9a
chore: remove redundant os.path.exists
tromai 6283692
chore: use != instead of not ==
tromai c686684
refactor: use exceptions for errors in get_local_artifact_paths and r…
tromai 48460d2
chore: improve function names and documentation to highlight the retu…
tromai a857810
chore: improve description of the docker_local_maven_repo_input_error…
tromai 5936102
chore: update more doc strings and function name to highlight the ret…
tromai 6265fe0
chore: add exception catching in analyzer.py
tromai 9a1da36
chore: add a log message when the input python venv has multiple pyth…
tromai File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,249 @@ | ||
# Copyright (c) 2024 - 2024, Oracle and/or its affiliates. All rights reserved. | ||
# Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/. | ||
|
||
"""This module declares types and utilities for handling local artifacts.""" | ||
|
||
import fnmatch | ||
import glob | ||
import os | ||
|
||
from packageurl import PackageURL | ||
|
||
from macaron.artifact.maven import construct_maven_repository_path | ||
from macaron.errors import LocalArtifactFinderError | ||
|
||
|
||
def construct_local_artifact_dirs_glob_pattern_maven_purl(maven_purl: PackageURL) -> list[str] | None: | ||
"""Return a list of glob pattern(s) representing the directory that contains the local maven artifacts for ``maven_purl``. | ||
|
||
The glob pattern(s) can be used to search in `<...>/.m2/repository` directory. | ||
|
||
Parameters | ||
---------- | ||
maven_purl : PackageURL | ||
A maven type PackageURL instance. | ||
|
||
Returns | ||
------- | ||
list[str] | None | ||
A list of glob patterns or None if an error happened. | ||
|
||
Examples | ||
-------- | ||
>>> from packageurl import PackageURL | ||
>>> purl = PackageURL.from_string("pkg:maven/com.oracle.macaron/[email protected]") | ||
>>> construct_local_artifact_dirs_glob_pattern_maven_purl(purl) | ||
['com/oracle/macaron/macaron/0.13.0'] | ||
""" | ||
if maven_purl.type != "maven": | ||
return None | ||
|
||
group = maven_purl.namespace | ||
artifact = maven_purl.name | ||
version = maven_purl.version | ||
|
||
if group is None or version is None: | ||
return None | ||
|
||
return [construct_maven_repository_path(group, artifact, version)] | ||
|
||
|
||
def construct_local_artifact_dirs_glob_pattern_pypi_purl(pypi_purl: PackageURL) -> list[str] | None: | ||
"""Return a list of glob pattern(s) representing directories that contains the artifacts in a Python virtual environment. | ||
|
||
The glob pattern(s) can be used to search in `<...>/<python_venv>/lib/python3.x/site-packages` | ||
directory. | ||
|
||
Parameters | ||
---------- | ||
pypi_purl : PackageURL | ||
A pypi type PackageURL instance. | ||
|
||
Returns | ||
------- | ||
list[str] | None | ||
A list of glob patterns or None if an error happened. | ||
|
||
Examples | ||
-------- | ||
>>> from packageurl import PackageURL | ||
>>> purl = PackageURL.from_string("pkg:pypi/[email protected]") | ||
>>> construct_local_artifact_dirs_glob_pattern_pypi_purl(purl) | ||
['django', 'django-1.11.1.dist-info', 'django-1.11.1.data'] | ||
""" | ||
if pypi_purl.type != "pypi": | ||
return None | ||
|
||
name = pypi_purl.name | ||
version = pypi_purl.version | ||
|
||
if version is None: | ||
return None | ||
|
||
# These patterns are from the content of a wheel file, which are extracted into the site-packages | ||
# directory. References: | ||
# https://packaging.python.org/en/latest/specifications/binary-distribution-format/#file-contents | ||
glob_patterns = [] | ||
glob_patterns.append(name) | ||
glob_patterns.append(f"{name}-{version}.dist-info") | ||
glob_patterns.append(f"{name}-{version}.data") | ||
|
||
return glob_patterns | ||
|
||
|
||
def find_artifact_dirs_from_local_maven_repo( | ||
local_maven_repo: str, | ||
glob_patterns: list[str], | ||
) -> list[str]: | ||
"""Find directories that contains maven artifacts within a maven local repository. | ||
|
||
``local_maven_repo`` should be in format `<...>/.m2/repository`. | ||
|
||
Parameters | ||
---------- | ||
local_maven_repo: str | ||
The path to the directory to find artifacts. | ||
glob_patterns: list[str] | ||
The list of glob patterns that matches to artifact directory names. | ||
|
||
Returns | ||
------- | ||
list[str] | ||
The list of paths to artifact directories in the form of ``venv_site_package_path``/path/to/artifact_dir | ||
If no artifact directory is found, this list will be empty. | ||
|
||
Raises | ||
------ | ||
LocalArtifactFinderError | ||
If ``local_maven_repo`` doesn't exist. | ||
""" | ||
if not os.path.isdir(local_maven_repo): | ||
raise LocalArtifactFinderError(f"{local_maven_repo} doesn't exist.") | ||
|
||
artifact_paths = [] | ||
for pattern in glob_patterns: | ||
found_paths = glob.glob( | ||
root_dir=local_maven_repo, | ||
pathname=pattern, | ||
) | ||
|
||
for found_path in found_paths: | ||
full_path = os.path.join(local_maven_repo, found_path) | ||
if os.path.isdir(full_path): | ||
artifact_paths.append(full_path) | ||
|
||
return artifact_paths | ||
|
||
|
||
def find_artifact_dirs_from_python_venv( | ||
venv_site_package_path: str, | ||
glob_patterns: list[str], | ||
) -> list[str]: | ||
"""Find directories within a python virtual environment. | ||
|
||
For packages in the virtual environment, we will treat their name case-insensitively. | ||
https://packaging.python.org/en/latest/specifications/name-normalization/ | ||
|
||
``venv_site_package_path`` should be in format `<...>/lib/python3.*/site-packages/`. | ||
|
||
Parameters | ||
---------- | ||
venv_path: str | ||
The path to the local directory to find artifacts. | ||
glob_patterns: list[str] | ||
The list of glob patterns that matches to artifact directory names. | ||
|
||
Returns | ||
------- | ||
list[str] | ||
The list of paths to artifact directories in the form of ``venv_site_package_path``/path/to/artifact_dir | ||
If no artifact directory is found, this list will be empty. | ||
|
||
Raises | ||
------ | ||
LocalArtifactFinderError | ||
If ``venv_site_package_path`` doesn't exist or if we cannot view the sub-directory of it. | ||
""" | ||
if not os.path.isdir(venv_site_package_path): | ||
raise LocalArtifactFinderError(f"{venv_site_package_path} doesn't exist.") | ||
|
||
artifact_paths = [] | ||
|
||
try: | ||
venv_path_entries = os.listdir(venv_site_package_path) | ||
except (NotADirectoryError, PermissionError, FileNotFoundError) as error: | ||
error_msg = f"Cannot view the sub-directory of venv {venv_site_package_path}" | ||
raise LocalArtifactFinderError(error_msg) from error | ||
|
||
all_package_dirs: list[str] = [] | ||
for entry in venv_path_entries: | ||
entry_path = os.path.join(venv_site_package_path, entry) | ||
if os.path.isdir(entry_path): | ||
all_package_dirs.append(entry) | ||
|
||
for package_dir in all_package_dirs: | ||
for pattern in glob_patterns: | ||
if fnmatch.fnmatch(package_dir.lower(), pattern.lower()): | ||
full_path = os.path.join(venv_site_package_path, package_dir) | ||
artifact_paths.append(full_path) | ||
|
||
return artifact_paths | ||
benmss marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
|
||
def get_local_artifact_dirs( | ||
purl: PackageURL, | ||
local_artifact_repo_path: str, | ||
) -> list[str]: | ||
"""Return the paths to directories that store local artifacts for a PackageURL. | ||
|
||
We look for local artifacts of ``purl`` in ``local_artifact_repo_path``. | ||
|
||
This function returns a list of paths (as strings), each has the format | ||
``local_artifact_repo_path``/path/to/artifact_dir`` | ||
|
||
This will mean that no path to an artifact is returned. Therefore, it's the responsibility | ||
of this function caller to inspect the artifact directory to obtain the required | ||
artifact. | ||
|
||
We assume that ``local_artifact_repo_path`` exists. | ||
|
||
Parameters | ||
---------- | ||
purl : PackageURL | ||
The purl we want to find local artifacts | ||
local_artifact_repo_path : str | ||
The local artifact repo directory. | ||
|
||
Returns | ||
------- | ||
list[str] | ||
The list contains the artifact directory paths. It will be empty if no artifact can be found. | ||
|
||
Raises | ||
------ | ||
LocalArtifactFinderError | ||
If an error happens when looking for local artifacts. | ||
""" | ||
purl_type = purl.type | ||
|
||
if purl_type == "maven": | ||
maven_artifact_patterns = construct_local_artifact_dirs_glob_pattern_maven_purl(purl) | ||
if not maven_artifact_patterns: | ||
raise LocalArtifactFinderError(f"Cannot generate maven artifact patterns for {purl}") | ||
|
||
return find_artifact_dirs_from_local_maven_repo( | ||
local_maven_repo=local_artifact_repo_path, | ||
glob_patterns=maven_artifact_patterns, | ||
) | ||
|
||
if purl_type == "pypi": | ||
pypi_artifact_patterns = construct_local_artifact_dirs_glob_pattern_pypi_purl(purl) | ||
if not pypi_artifact_patterns: | ||
raise LocalArtifactFinderError(f"Cannot generate Python package patterns for {purl}") | ||
|
||
return find_artifact_dirs_from_python_venv( | ||
venv_site_package_path=local_artifact_repo_path, | ||
glob_patterns=pypi_artifact_patterns, | ||
) | ||
|
||
raise LocalArtifactFinderError(f"Unsupported PURL type {purl_type}") |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.