| 13 | |
| 14 | |
| 15 | class Tarball: |
| 16 | def __init__(self) -> None: |
| 17 | self.base_download_url: str = '' |
| 18 | self.local_location: Path = tc_build.utils.UNINIT_PATH |
| 19 | self.remote_tarball_name: str = '' |
| 20 | self.remote_checksum_name: str = '' |
| 21 | |
| 22 | def download(self) -> None: |
| 23 | if not tc_build.utils.path_is_set(self.local_location): |
| 24 | msg = 'No local tarball location specified?' |
| 25 | raise RuntimeError(msg) |
| 26 | if self.local_location.exists(): |
| 27 | return # Already downloaded |
| 28 | |
| 29 | if not self.base_download_url: |
| 30 | msg = 'No tarball download URL specified?' |
| 31 | raise RuntimeError(msg) |
| 32 | if not self.remote_tarball_name: |
| 33 | self.remote_tarball_name = self.local_location.name |
| 34 | |
| 35 | full_url = f"{self.base_download_url}/{self.remote_tarball_name}" |
| 36 | tc_build.utils.print_info(f"Downloading {full_url} to {self.local_location}...") |
| 37 | tc_build.utils.curl(full_url, destination=self.local_location) |
| 38 | |
| 39 | # If there is a remote checksum file, download it, find the checksum |
| 40 | # for the particular tarball, compute the downloaded file's checksum, |
| 41 | # and finally compare the two. |
| 42 | if self.remote_checksum_name: |
| 43 | checksums = tc_build.utils.curl(f"{self.base_download_url}/{self.remote_checksum_name}") |
| 44 | if not ( |
| 45 | match := re.search( |
| 46 | rf"([0-9a-f]+)\s+{self.remote_tarball_name}$", checksums, flags=re.MULTILINE |
| 47 | ) |
| 48 | ): |
| 49 | msg = f"Could not find checksum for {self.remote_tarball_name}?" |
| 50 | raise RuntimeError(msg) |
| 51 | |
| 52 | if 'sha256' in self.remote_checksum_name: |
| 53 | file_hash = hashlib.sha256() |
| 54 | elif 'sha512' in self.remote_checksum_name: |
| 55 | file_hash = hashlib.sha512() |
| 56 | else: |
| 57 | msg = f"No supported hashlib for {self.remote_checksum_name}, add support for it?" |
| 58 | raise RuntimeError(msg) |
| 59 | with self.local_location.open('rb') as file: |
| 60 | while data := file.read(BYTES_TO_READ): |
| 61 | file_hash.update(data) |
| 62 | |
| 63 | computed_checksum = file_hash.hexdigest() |
| 64 | expected_checksum = match.groups()[0] |
| 65 | if computed_checksum != expected_checksum: |
| 66 | msg = f"Computed checksum of {self.local_location} ('{computed_checksum}') differs from expected checksum ('{expected_checksum}'), remove it and try again?" |
| 67 | raise RuntimeError(msg) |
| 68 | |
| 69 | def extract(self, extraction_location: Path) -> None: |
| 70 | if not tc_build.utils.path_is_set(self.local_location): |
| 71 | msg = 'No local tarball location specified?' |
| 72 | raise RuntimeError(msg) |