Resolving existing gradle distributions, aka built-in wrapper
This commit is contained in:
@@ -1,20 +1,24 @@
|
||||
import re
|
||||
from hashlib import md5
|
||||
from os import environ
|
||||
from os.path import join, splitext
|
||||
from typing import NamedTuple
|
||||
from hashlib import md5, sha256
|
||||
from os import environ, walk
|
||||
from os.path import basename, dirname, isdir, isfile, join, splitext
|
||||
from typing import NamedTuple, Optional
|
||||
|
||||
from .utils import encode_int
|
||||
from .fetch import queue_download_request, retrieve_bytes
|
||||
from .output_directory import FileLock
|
||||
from .utils import AttributeZipFile, encode_int, ensure_directory, remove_tree
|
||||
|
||||
# (numeric part, major version, minor version), (stage part, stage, patch number), (commit part, commit/date, timezone)
|
||||
GRADLE_VERSION_REGEX = re.compile(r"((\d+)(\.\d+)+)(-([^\W\d_]+)-(\w+))?(-(SNAPSHOT|\d{14}([-+]\d{4})?))?")
|
||||
COMPARABLE_VERSION_REGEX = re.compile(r"(\d+)(\.\d+)")
|
||||
|
||||
class GradleVersion(NamedTuple):
|
||||
version: str
|
||||
comparable: float
|
||||
major: int
|
||||
minor: int
|
||||
snapshot: bool
|
||||
|
||||
def get_gradle_home() -> str:
|
||||
def find_gradle_home() -> str:
|
||||
gradle_home = environ.get("GRADLE_USER_HOME")
|
||||
if gradle_home is None:
|
||||
from .output_directory import get_user_directory
|
||||
@@ -23,15 +27,16 @@ def get_gradle_home() -> str:
|
||||
|
||||
def parse_gradle_specification(version: str) -> GradleVersion:
|
||||
if version == "latest" or version == "nightly" or version == "release-nightly" or version == "release-candidate":
|
||||
return GradleVersion(version, 0.0, version != "latest" and version != "release-candidate")
|
||||
return GradleVersion(version, 0, 0, version != "latest" and version != "release-candidate")
|
||||
|
||||
spec = GRADLE_VERSION_REGEX.fullmatch(version)
|
||||
if spec is None:
|
||||
raise ValueError(f"Specify a valid Gradle release listed on https://gradle.org/releases/. Got: {version!r}.")
|
||||
comparable_spec = COMPARABLE_VERSION_REGEX.match(spec.group(1))
|
||||
assert comparable_spec
|
||||
|
||||
comparable = float(spec.group(2) + spec.group(3))
|
||||
snapshot = spec.group(5) in ("snapshot", "commit") or spec.group(8) is not None
|
||||
return GradleVersion(spec.string, comparable, snapshot)
|
||||
return GradleVersion(spec.string, int(comparable_spec.group(1)), int(comparable_spec.group(2)), snapshot)
|
||||
|
||||
def get_gradle_distribution_url(spec: GradleVersion, type: str = "bin") -> str:
|
||||
repository = "distributions" if not spec.snapshot else "distributions-snapshots"
|
||||
@@ -52,4 +57,80 @@ def url_to_local_gradle_distribution(url: str) -> str:
|
||||
|
||||
archive_name = splitext(archive_path)[0]
|
||||
url_checksum = url_as_gradle_checksum(url)
|
||||
return join("wrapper", "dists", archive_name, url_checksum, archive_path)
|
||||
return join(archive_name, url_checksum, archive_path)
|
||||
|
||||
def get_user_gradle_disribution(relative_path: str) -> str:
|
||||
return join(find_gradle_home(), "wrapper", "dists", relative_path)
|
||||
|
||||
def verify_gradle_installation(archive_path: str, without_marker: bool = False) -> Optional[str]:
|
||||
distribution_directory = dirname(archive_path)
|
||||
marker_file = join(distribution_directory, f"{basename(archive_path)}.ok")
|
||||
if not isdir(distribution_directory) or (not without_marker and not isfile(marker_file)):
|
||||
return None
|
||||
for dirpath, dirnames, filenames in walk(distribution_directory, followlinks=True):
|
||||
for relative_path in dirnames:
|
||||
gradle_home = join(dirpath, relative_path)
|
||||
if find_gradle_launcher(gradle_home):
|
||||
return gradle_home
|
||||
break
|
||||
|
||||
def find_gradle_launcher(gradle_home: str) -> Optional[str]:
|
||||
executable_directory = join(gradle_home, "lib")
|
||||
if not isdir(executable_directory):
|
||||
return None
|
||||
for dirpath, dirnames, filenames in walk(executable_directory, followlinks=True):
|
||||
for relative_path in filenames:
|
||||
if relative_path[:16] == "gradle-launcher-" and relative_path[-4:] == ".jar":
|
||||
return join(dirpath, relative_path)
|
||||
|
||||
def verify_gradle_remote_checksum(archive_path: str, url: str) -> bool:
|
||||
if not isfile(archive_path):
|
||||
return False
|
||||
local_hash = sha256()
|
||||
with open(archive_path, "rb") as file:
|
||||
while True:
|
||||
chunk = file.read(4096)
|
||||
if not chunk:
|
||||
break
|
||||
local_hash.update(chunk)
|
||||
remote_hash = str(retrieve_bytes(url), encoding="ascii")
|
||||
return remote_hash == local_hash.hexdigest()
|
||||
|
||||
def download_gradle_version(archive_path: str, url: str) -> str:
|
||||
distribution_directory = dirname(archive_path)
|
||||
ensure_directory(distribution_directory)
|
||||
marker_file = join(distribution_directory, f"{basename(archive_path)}.ok")
|
||||
|
||||
remove_tree(marker_file)
|
||||
for dirpath, dirnames, filenames in walk(distribution_directory, followlinks=True):
|
||||
for relative_path in dirnames:
|
||||
remove_tree(join(dirpath, relative_path))
|
||||
|
||||
if not verify_gradle_remote_checksum(archive_path, f"{url}.sha256"):
|
||||
remove_tree(archive_path)
|
||||
queue_download_request(url, output_path=archive_path)
|
||||
if not verify_gradle_remote_checksum(archive_path, f"{url}.sha256"):
|
||||
raise ValueError(f"SHA256 mismatch, failed to confirm validity of {basename(archive_path)} archive!")
|
||||
with AttributeZipFile(archive_path, "r") as archive:
|
||||
archive.extractall(distribution_directory)
|
||||
|
||||
gradle_home = verify_gradle_installation(archive_path, without_marker=True)
|
||||
if not gradle_home:
|
||||
raise ValueError(f"Unsupported distribution {basename(archive_path)}, please retry task with different version!")
|
||||
open(marker_file, "x").close()
|
||||
remove_tree(archive_path)
|
||||
return gradle_home
|
||||
|
||||
def resolve_gradle_version(version: str) -> str:
|
||||
gradle_specification = parse_gradle_specification(version)
|
||||
distribution_url = get_gradle_distribution_url(gradle_specification)
|
||||
local_path = url_to_local_gradle_distribution(distribution_url)
|
||||
archive_path = get_user_gradle_disribution(local_path)
|
||||
|
||||
with FileLock(f"{archive_path}.lck", delete=False):
|
||||
from time import sleep
|
||||
sleep(2)
|
||||
gradle_home = verify_gradle_installation(archive_path)
|
||||
if not gradle_home:
|
||||
gradle_home = download_gradle_version(archive_path, distribution_url)
|
||||
return gradle_home
|
||||
|
||||
Reference in New Issue
Block a user