From 12f52f94f7f0b784e20cb6abf8cf087c8eb52cfc Mon Sep 17 00:00:00 2001 From: Wanlin Du Date: Tue, 19 Aug 2025 23:37:40 +0000 Subject: [PATCH 1/2] feat: add an install script to download the golang test-server. This PR introduces an install.py script to automate the download, verification, and installation of the test-server binary from its GitHub Releases page. --- .gitignore | 4 + sdks/python/LICENSE | 202 +++++++++++++++++++++++++++++++++++++ sdks/python/checksums.json | 82 +++++++++++++++ sdks/python/install.py | 159 +++++++++++++++++++++++++++++ 4 files changed, 447 insertions(+) create mode 100644 sdks/python/LICENSE create mode 100644 sdks/python/checksums.json create mode 100644 sdks/python/install.py diff --git a/.gitignore b/.gitignore index 3831da5..1e2ba30 100644 --- a/.gitignore +++ b/.gitignore @@ -20,6 +20,7 @@ test-server.sln test-server /recordings dist/ +.vscode # TypeScript SDK specific sdks/typescript/node_modules/ @@ -29,3 +30,6 @@ sdks/typescript/bin/ # TypeScript SDK Sample specific sdks/typescript/sample/node_modules/ sdks/typescript/sample/dist/ + +# Python SDK specific +sdks/python/bin/ diff --git a/sdks/python/LICENSE b/sdks/python/LICENSE new file mode 100644 index 0000000..d645695 --- /dev/null +++ b/sdks/python/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/sdks/python/checksums.json b/sdks/python/checksums.json new file mode 100644 index 0000000..ae20cd5 --- /dev/null +++ b/sdks/python/checksums.json @@ -0,0 +1,82 @@ +{ + "v0.0.1": { + "test-server_Darwin_arm64.tar.gz": "8d5ff282451b8d49fa6f290ec11d4ee9fcc948f28ae2713f928f4e3eeaf35d2e", + "test-server_Darwin_x86_64.tar.gz": "793b97d96d1a4a65fdef4510266047725aca6a7f39be3958f039b5f5d377c5f3", + "test-server_Linux_arm64.tar.gz": "b77c68d7549eb8f1ba0569434f11236cb08222bead8235bef2f6dc194eff4318", + "test-server_Linux_i386.tar.gz": "e9ec96227854a9def19cd112dfc22bfc776a6595314fb104b80f9d74d27a8ba2", + "test-server_Linux_x86_64.tar.gz": "35a157c5c9fbf2639ac8f8282f45186397ebd428b31808780421e2fa34923866", + "test-server_Windows_arm64.zip": "bf708e74aa1e6fd15529031c9a8f7d75b8fcc35cb7ef24c8c81a5b3e1ba2fca4", + "test-server_Windows_i386.zip": "13c5a1cde66b2795cb49b02dc672da66bbc2f934c67f733b7313ad4c10c68c96", + "test-server_Windows_x86_64.zip": "6105a98d7b245a3b8868c173d2e36c0e2a41c9e88a0e266b0f318b21f96a313f" + }, + "v0.2.0": { + "test-server_Darwin_arm64.tar.gz": "87a63147c318e012e5963fd4ae706aede56267db1913272baeeafe4b9aef95c0", + "test-server_Darwin_x86_64.tar.gz": "79dee942fd1673d4000f99742464cb7cf238b773523a0da294da9017f30e43c4", + "test-server_Linux_arm64.tar.gz": "50b3667ee7c7543b08decff81936654cb878a8ad84d1ed2f9d4f40108f027be1", + "test-server_Linux_i386.tar.gz": "9599bf857fac1594ef38ed44193f8da7374ac2d1e82e5aa169d474b6ffece04b", + "test-server_Linux_x86_64.tar.gz": "84b5b2ef12e002461fa9961d689d415fec80780231d8dd107c6eb40bbc327759", + "test-server_Windows_arm64.zip": "d00178c9bc523ee9c37576efff94f1ba09c4b30e375636b603e9b46ca5be5a25", + "test-server_Windows_i386.zip": "1beff64cd68fffa7bd4936d6a2df8641cc371b0822a9ef647e3ab15710ced045", + "test-server_Windows_x86_64.zip": "dfa622a481a8abad115a177e12fd5bfc7fc0270cb37618511ba183b34ad6f0d1" + }, + "v0.2.1": { + "test-server_Darwin_arm64.tar.gz": "3bd64892e9943e65e2bd769b15a212f6d54021ff526ef42c0e4f8dc13be25eb9", + "test-server_Darwin_x86_64.tar.gz": "35941ef52f8c2fd3ac49b1128f964b81e04ceedb5e1f359cd51ece7dde15ff98", + "test-server_Linux_arm64.tar.gz": "e284be5cdc497db55ea09471e6dfcd3768b40d3f0eff915794b04386a6d0f18e", + "test-server_Linux_i386.tar.gz": "12cb4f8167baca5965b90cf4d2157bff78380f1f7853ccf45b87e26abd63f52d", + "test-server_Linux_x86_64.tar.gz": "5dab0a8041cfee8801a91ded6a98a682a3952649d35e6a05c3edfb2c32383c7b", + "test-server_Windows_arm64.zip": "884e84dc43491ecbfbb2c03f6d98ec8d247a4eb7c80a3cac61849c1ccbcfc92c", + "test-server_Windows_i386.zip": "51980525c42121674aef6953eddb0579d4897576c06ae411064ad92e828a45e7", + "test-server_Windows_x86_64.zip": "e368ac54ec00443ddcde0c63ee806b7b865be403388b69f256992ac49acad7e1" + }, + "v0.2.2": { + "test-server_Darwin_arm64.tar.gz": "1e568d5447597dd06f535806a5e52fe2063c7f9b57edf3b590699a9bd0675b8d", + "test-server_Darwin_x86_64.tar.gz": "a6e3127cf5622332c4b4200957ce5ddab2ff84e91b4ff984514071a716877852", + "test-server_Linux_arm64.tar.gz": "87789743585853dddca65a88aaaccd7463fc2b714671438f0f711dac1cea8ea4", + "test-server_Linux_i386.tar.gz": "0482509d6dcd80be203988aadf3e5421e2116e43b33971c8540148de80bfa0da", + "test-server_Linux_x86_64.tar.gz": "89798849206ae210309cad36b3275c333a19d12d45941327384279be17dca07d", + "test-server_Windows_arm64.zip": "be8500c4577da4930397ecfebd626b2a090ab045975e594550c16f087ee343b7", + "test-server_Windows_i386.zip": "345f894e0e789442802a66806623f7a28b95cafac6d10ac5d7aa44084fb73bc5", + "test-server_Windows_x86_64.zip": "8d64f303463a697550903bb3587f63e8a37efa96b9eea1929d5cbd825f2840e4" + }, + "v0.2.3": { + "test-server_Darwin_arm64.tar.gz": "e7ed97903e1850755321da023838bc27c30bf44365d4c347d0405ad2db80d901", + "test-server_Darwin_x86_64.tar.gz": "33af03f84b644efb7113371433a78bc35cf406fc909eac1f33f6003fec8afd38", + "test-server_Linux_arm64.tar.gz": "c1355f56d5c8480c71ad7c8c4e01160cd9b60e977af3bc15ae6599ae04958cd1", + "test-server_Linux_i386.tar.gz": "50619693d9b6a27a05d72a6af7d364333f67aa9b5c67428c85e0e8dbadd44dd3", + "test-server_Linux_x86_64.tar.gz": "7af3c0502b5c242565cb494a50a50188d38c342e08523f8168198ebb73506062", + "test-server_Windows_arm64.zip": "dc5cc3b28404fec303b5afc31da45de24cb69ce36a74590985b2b054d7cf78b9", + "test-server_Windows_i386.zip": "b42b75ae4d538aa1df3893612458c449ad6c132cae99feb9deaac075b04bd1dd", + "test-server_Windows_x86_64.zip": "22b7d25b7ad3bb3b586a6fba2996420f67a795131b9be3a06ccffe92cfd3f234" + }, + "v0.2.4": { + "test-server_Darwin_arm64.tar.gz": "a80eca2362245ceb0f0b60cbc7121dc2bb35c0d95224051f7c5bb815f9cb3bb7", + "test-server_Darwin_x86_64.tar.gz": "4c55c667b1419ec09aef536cdf753d20ddb29af29199a099273ffed732e2b4f1", + "test-server_Linux_arm64.tar.gz": "c0a2a6b74a29dc6e2b4d17079872f0e64d9a3d392dc35d4ac8a6b02ba2b5278d", + "test-server_Linux_i386.tar.gz": "c20dbbbb89d00dcbd15ded3077d270111cf59118beff45e68114ff8f0bb3e79c", + "test-server_Linux_x86_64.tar.gz": "acddf79900182c4e7a0dfb03562f0dd24bfde922d50ec5f767cb234942b204fa", + "test-server_Windows_arm64.zip": "07bf8adc4a9c5aa353d95ce0afbf075c4c069c926ac14178ecfb283f6d072b4d", + "test-server_Windows_i386.zip": "62e5bc50e64ffa0fd0878203b351a393a990d70c75800572831d273a99b9d2b4", + "test-server_Windows_x86_64.zip": "5902ebf807667243b29af5ca1b7622aba7be5fc2d50378b35f066bea85832f8b" + }, + "v0.2.5": { + "test-server_Darwin_arm64.tar.gz": "fe652704eee0f4568a2d4f8c3a43732dc28cab4d2bd9dfc6294372f6587e4e2b", + "test-server_Darwin_x86_64.tar.gz": "cf1a4bca0297b394173deaf1515cba6382dd73cad7e53057a5f2e77d6f3c0d33", + "test-server_Linux_arm64.tar.gz": "874b3799f6669dfd278cade47c1c3ac1f40754ffc8dc296e5143381eae76bd84", + "test-server_Linux_i386.tar.gz": "5ae39f7e06e9fefd9574674aee3450d73b77c3cab3a7b81aea5688320c823978", + "test-server_Linux_x86_64.tar.gz": "716d4bde33a842f4a97a8a8c9037027bd6a314cf4b4a769ee0acd7a37ca5e171", + "test-server_Windows_arm64.zip": "9894d08f6e9c2e58991c78418e65a6f8a12712c86a4ac98b18d74783c601f6f7", + "test-server_Windows_i386.zip": "b0daa8cac3133470afa9a049ad08a283c5c48c929a139c685773dee31b20d99e", + "test-server_Windows_x86_64.zip": "88c55b9208d66516a674b79be59fed3ec0262f4f96a499628b9ea609f13e3fc8" + }, + "v0.2.6": { + "test-server_Darwin_arm64.tar.gz": "8e3f9b5a7ab4d5e398f44c0bdbe4e8f009b863b63d31dfadf00834d306c7b746", + "test-server_Darwin_x86_64.tar.gz": "4a59bb73ae6009ac92a274b4a0e6ce534b7ff90b0afb7312f8ae7e015cbcefe8", + "test-server_Linux_arm64.tar.gz": "f3273dce4bb2f492cc703fe790af37b6e0db1b258e94f770bd86493b5aa5558e", + "test-server_Linux_i386.tar.gz": "3f3878103935bf1507836360ba103bf7a5d1034fd21a285074574b22e67f58a4", + "test-server_Linux_x86_64.tar.gz": "f007c2a940dade8a1e4c08f2c954f768a351e3fa3b050dcc1753bf65e637b983", + "test-server_Windows_arm64.zip": "466137be1dad084fcdef86a8894080a2ef1086dfd3ee15bc123a6d2053515841", + "test-server_Windows_i386.zip": "6980c83e2118ed739dad53af29dc302b78ec89804f7ff7d7b5e39dcadbab3e83", + "test-server_Windows_x86_64.zip": "8a4e36c8fa2d17a256a31956a3cb2851d27a30f423449911caf0b3ec76b9a602" + } +} \ No newline at end of file diff --git a/sdks/python/install.py b/sdks/python/install.py new file mode 100644 index 0000000..647c69c --- /dev/null +++ b/sdks/python/install.py @@ -0,0 +1,159 @@ +# Copyright 2025 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import hashlib +import os +import platform +import stat +import sys +import tarfile +import zipfile +import json +from pathlib import Path +import requests + +# --- Configuration --- +TEST_SERVER_VERSION = "v0.2.6" +GITHUB_OWNER = "google" +GITHUB_REPO = "test-server" +PROJECT_NAME = "test-server" +BIN_DIR = Path(__file__).parent / "bin" + +CHECKSUMS_PATH = Path(__file__).parent / "checksums.json" +try: + with open(CHECKSUMS_PATH, "r") as f: + ALL_EXPECTED_CHECKSUMS = json.load(f) +except (FileNotFoundError, json.JSONDecodeError) as e: + print(f"Error loading checksums.json: {e}") + sys.exit(1) + + +def get_platform_details(): + """Determines the OS and architecture to download the correct binary.""" + os_platform = sys.platform + arch = platform.machine() + + if os_platform.startswith("darwin"): + go_os = "Darwin" + archive_extension = ".tar.gz" + elif os_platform.startswith("linux"): + go_os = "Linux" + archive_extension = ".tar.gz" + elif os_platform.startswith("win32"): + go_os = "Windows" + archive_extension = ".zip" + else: + raise OSError(f"Unsupported platform: {os_platform}") + + if arch in ["x86_64", "AMD64"]: + go_arch = "x86_64" + elif arch in ["arm64", "aarch64"]: + go_arch = "arm64" + else: + raise OSError(f"Unsupported architecture: {arch}") + + binary_name = f"{PROJECT_NAME}.exe" if go_os == "Windows" else PROJECT_NAME + return go_os, go_arch, archive_extension, binary_name + + +def calculate_file_sha256(file_path): + """Calculates and returns the SHA256 checksum of a file.""" + sha256 = hashlib.sha256() + with open(file_path, "rb") as f: + for chunk in iter(lambda: f.read(4096), b""): + sha256.update(chunk) + return sha256.hexdigest() + + +def download_and_verify(download_url, archive_path, version, archive_name): + """Downloads the binary archive and verifies its checksum.""" + print(f"Downloading {archive_name} from {download_url}...") + try: + with requests.get(download_url, stream=True, timeout=60) as r: + r.raise_for_status() + with open(archive_path, "wb") as f: + for chunk in r.iter_content(chunk_size=8192): + f.write(chunk) + print("Download complete.") + + print("Verifying checksum...") + expected_checksum = ALL_EXPECTED_CHECKSUMS.get(version, {}).get(archive_name) + if not expected_checksum: + raise ValueError(f"Checksum for {archive_name} (version {version}) not found.") + + actual_checksum = calculate_file_sha256(archive_path) + if actual_checksum != expected_checksum: + raise ValueError(f"Checksum mismatch! Expected {expected_checksum}, got {actual_checksum}") + print("Checksum verified successfully.") + + except Exception as e: + # Clean up partial download on failure + if archive_path.exists(): + archive_path.unlink() + print(f"❌ Failed during download or verification: {e}") + raise + + +def extract_archive(archive_path, archive_extension): + """Extracts the binary from the downloaded archive.""" + print(f"Extracting binary from {archive_path} to {BIN_DIR}...") + try: + if archive_extension == ".zip": + with zipfile.ZipFile(archive_path, "r") as zip_ref: + zip_ref.extractall(BIN_DIR) + elif archive_extension == ".tar.gz": + with tarfile.open(archive_path, "r:gz") as tar_ref: + tar_ref.extractall(BIN_DIR) + print("Extraction complete.") + finally: + # Clean up the archive file + if archive_path.exists(): + archive_path.unlink() + print(f"Cleaned up {archive_path}.") + + +def ensure_binary_is_executable(binary_path, go_os): + """Sets executable permissions on the binary for non-Windows systems.""" + if go_os != "Windows": + st = os.stat(binary_path) + os.chmod(binary_path, st.st_mode | stat.S_IEXEC) + print(f"Set executable permission for {binary_path}") + + +def main(): + """Main function to orchestrate the installation.""" + go_os, go_arch, archive_extension, binary_name = get_platform_details() + binary_path = BIN_DIR / binary_name + + if binary_path.exists(): + print(f"{PROJECT_NAME} binary already exists at {binary_path}. Removing it for a fresh install.") + binary_path.unlink() # This deletes the file + + BIN_DIR.mkdir(parents=True, exist_ok=True) + + version = TEST_SERVER_VERSION + archive_name = f"{PROJECT_NAME}_{go_os}_{go_arch}{archive_extension}" + download_url = f"https://github.com/{GITHUB_OWNER}/{GITHUB_REPO}/releases/download/{version}/{archive_name}" + archive_path = BIN_DIR / archive_name + + try: + download_and_verify(download_url, archive_path, version, archive_name) + extract_archive(archive_path, archive_extension) + ensure_binary_is_executable(binary_path, go_os) + print(f"✅ {PROJECT_NAME} binary is ready at {binary_path}") + except Exception as e: + sys.exit(1) # Exit with an error code + +if __name__ == "__main__": + main() \ No newline at end of file From 84092150f963e4d1a8db9337009b6f54fe217d36 Mon Sep 17 00:00:00 2001 From: Wanlin Du Date: Fri, 22 Aug 2025 21:03:04 +0000 Subject: [PATCH 2/2] fix format --- sdks/python/install.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdks/python/install.py b/sdks/python/install.py index 080b323..cb88ad8 100644 --- a/sdks/python/install.py +++ b/sdks/python/install.py @@ -156,4 +156,4 @@ def main(): sys.exit(1) # Exit with an error code if __name__ == "__main__": - main() \ No newline at end of file + main()