-
Notifications
You must be signed in to change notification settings - Fork 9
Automatic installation of GitHub CLI, Git and Git LFS #34
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
Open
user21t
wants to merge
9
commits into
ProjectBorealis:main
Choose a base branch
from
user21t:main
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
9 commits
Select commit
Hold shift + click to select a range
50b67bf
Update pbsync/__main__.py related to ticket #7
user21t 4aad38b
Update Pipfile related to ticket #7
user21t 32e75ed
Merge branch 'ProjectBorealis:main' into main
user21t 4175d57
Merge branch 'ProjectBorealis:main' into main
user21t 889271a
Create pbhttp.py
user21t 1f7c88c
Separate HTTP logic from main program
user21t d9ef61f
Add downloaded file path as an argument to the download function in p…
user21t fe75c62
Add "pbhttp" module to pbsteamcmd.py
user21t 4d75de4
Add "pbhttp" module to pbunreal.py
user21t 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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,25 @@ | ||
| import requests | ||
| from requests.adapters import HTTPAdapter | ||
| from urllib3.util import Retry | ||
|
|
||
| def setup(): | ||
| retry_strategy = Retry( | ||
| total=5, # Maximum number of retries | ||
| status_forcelist=[429, 500, 502, 503, 504], # Retry on these status codes | ||
| backoff_factor=1 # Wait 1 sec before retrying, then increase by 1 sec each retry | ||
| ) | ||
|
|
||
| adapter = HTTPAdapter(max_retries=retry_strategy) | ||
| http = requests.Session() | ||
| http.mount("https://", adapter) | ||
|
|
||
| def download(url: str, downloaded_file: str): | ||
| setup() | ||
| response = http.get(url, stream=True) | ||
|
|
||
| try: | ||
| with open(downloaded_file, 'wb') as file: | ||
| for chunk in response.iter_content(chunk_size=10 * 1024): | ||
| file.write(chunk) | ||
| except OSError as e: # For file I/O errors (e.g., disk full, permission denied) | ||
| pblog.error(f"File I/O error: {e}") |
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 |
|---|---|---|
|
|
@@ -2,7 +2,10 @@ | |
| import multiprocessing | ||
| import os | ||
| import os.path | ||
| import platform | ||
| import sys | ||
| import shutil | ||
| import subprocess | ||
| import threading | ||
| import time | ||
| import webbrowser | ||
|
|
@@ -15,6 +18,7 @@ | |
| pbdispatch, | ||
| pbgh, | ||
| pbgit, | ||
| pbhttp, | ||
| pblog, | ||
| pbpy_version, | ||
| pbsteamcmd, | ||
|
|
@@ -31,6 +35,52 @@ | |
|
|
||
| default_config_name = "PBSync.xml" | ||
|
|
||
| def check_gh_cli(): | ||
| try: | ||
| result = subprocess.run(["gh", "--version"], capture_output=True, text=True, check=True) | ||
| pblog.info(result.stdout.strip()) | ||
| return True | ||
| except FileNotFoundError: | ||
| return False | ||
|
|
||
| def install_gh_cli(): | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. GitHub CLI is expected to be in |
||
| pblog.info("GitHub CLI not found. Installing...") | ||
| gh_ver="2.63.0" | ||
| # Download GitHub CLI | ||
| match sys.platform: | ||
| case "win32": | ||
| url = f"https://github.com/cli/cli/releases/download/v{gh_ver}/gh_{gh_ver}_windows_amd64.msi" | ||
| downloaded_file = 'gh.msi' | ||
| case "darwin": | ||
| url = f"https://github.com/cli/cli/releases/download/v{gh_ver}/gh_{gh_ver}_macOS_universal.pkg" | ||
| downloaded_file = 'gh.pkg' | ||
| case _: | ||
| pblog.error("Your operation system is not supported") | ||
| return None | ||
|
|
||
| pbhttp.download(url) | ||
|
|
||
| # Install GitHub CLI | ||
| try: | ||
| match sys.platform: | ||
| case "win32": subprocess.run(['msiexec', '/i', downloaded_file, '/passive'], check=True) | ||
| case "darwin": subprocess.run(['sudo', 'installer', '-pkg', downloaded_file, '-target', '/'], check=True) | ||
| except subprocess.CalledProcessError as e: | ||
| pblog.error(f"Command failed with return code {e.returncode}") | ||
|
|
||
| pblog.info("GitHub CLI installed.") | ||
| result = subprocess.run(['gh', '--version'], capture_output=True, text=True, check=True) | ||
| pblog.info(result.stdout.strip()) | ||
| # Delete installation file | ||
| os.remove(downloaded_file) | ||
|
|
||
| try: | ||
| subprocess.run(['gh', 'auth', 'login'], check=True) | ||
| except: | ||
| pass | ||
|
|
||
| if not check_gh_cli(): | ||
| install_gh_cli() | ||
|
|
||
| def config_handler(config_var, config_parser_func): | ||
| if not pbconfig.generate_config(config_var, config_parser_func): | ||
|
|
@@ -43,7 +93,6 @@ def config_handler(config_var, config_parser_func): | |
|
|
||
|
|
||
| def sync_handler(sync_val: str, repository_val=None): | ||
|
|
||
| sync_val = sync_val.lower() | ||
|
|
||
| if sync_val == "all" or sync_val == "force" or sync_val == "partial": | ||
|
|
@@ -55,76 +104,30 @@ def sync_handler(sync_val: str, repository_val=None): | |
|
|
||
| detected_git_version = pbgit.get_git_version() | ||
| supported_git_version = pbconfig.get("supported_git_version") | ||
| needs_git_update = False | ||
| if detected_git_version == supported_git_version: | ||
| pblog.info(f"Current Git version: {detected_git_version}") | ||
| else: | ||
| pblog.warning("Git is not updated to the supported version in your system") | ||
| pblog.warning( | ||
| f"Supported Git Version: {pbconfig.get('supported_git_version')}" | ||
| ) | ||
| pblog.warning(f"Current Git Version: {detected_git_version}") | ||
| needs_git_update = True | ||
| repo = "microsoft/git" | ||
| version = f"v{supported_git_version}" | ||
| if ( | ||
| "vfs" in detected_git_version | ||
| and sys.platform == "win32" | ||
| or sys.platform == "darwin" | ||
| ): | ||
| pblog.info("Auto-updating Git...") | ||
| if sys.platform == "win32": | ||
| directory = "Saved/PBSyncDownloads" | ||
| download = f"Git-{supported_git_version}-64-bit.exe" | ||
| if ( | ||
| pbgh.download_release_file( | ||
| version, | ||
| download, | ||
| directory=directory, | ||
| repo=f"https://github.com/{repo}", | ||
| ) | ||
| != 0 | ||
| ): | ||
| pblog.error( | ||
| "Git auto-update failed, please download and install manually." | ||
| ) | ||
| webbrowser.open( | ||
| f"https://github.com/{repo}/releases/download/{version}/{download}" | ||
| ) | ||
| else: | ||
| download_path = f"Saved\\PBSyncDownloads\\{download}" | ||
| proc = pbtools.run([download_path]) | ||
| if proc.returncode: | ||
| pblog.error("Git auto-update failed. Please try manually:") | ||
| webbrowser.open( | ||
| f"https://github.com/{repo}/releases/download/{version}/{download}" | ||
| ) | ||
| else: | ||
| needs_git_update = False | ||
| # reconfigure credential manager to make sure we have the proper path | ||
| pbtools.run([*pbgit.get_gcm_executable(), "configure"]) | ||
| os.remove(download_path) | ||
| else: | ||
| proc = pbtools.run( | ||
| [pbgit.get_git_executable(), "update-microsoft-git"] | ||
| ) | ||
| # if non-zero, error out | ||
| if proc.returncode: | ||
| pblog.error( | ||
| "Git auto-update failed, please download and install manually." | ||
| ) | ||
| else: | ||
| needs_git_update = False | ||
| input( | ||
| "Launching Git update, please press enter when done installing. " | ||
| ) | ||
| if needs_git_update: | ||
| pblog.error( | ||
| f"Please install the supported Git version from https://github.com/{repo}/releases/tag/{version}" | ||
| ) | ||
| pblog.error( | ||
| f"Visit {pbconfig.get('git_instructions')} for installation instructions" | ||
| ) | ||
| try: | ||
| match sys.platform: | ||
| case "win32": subprocess.run(['gh', 'release', 'download', supported_git_version, '-p', 'Git*.exe', '-R', 'microsoft/git'], check=True) | ||
| case "darwin": subprocess.run(['gh', 'release', 'download', supported_git_version, '-p', 'git*.pkg', '-R', 'microsoft/git'], check=True) | ||
| except subprocess.CalledProcessError as e: | ||
| pblog.error(f"Command failed with return code {e.returncode}") | ||
|
|
||
| git_installer = [file for file in os.listdir() if file.startswith("Git") or file.startswith("git")][0] | ||
|
|
||
| # Install Git | ||
| try: | ||
| match sys.platform: | ||
| case "win32": subprocess.run([git_installer], '/VERYSILENT', check=True) | ||
| case "darwin": subprocess.run(['sudo', 'installer', '-pkg', git_installer, '-target', '/'], check=True) | ||
| pblog.info(f'Installing Git {supported_git_version}...') | ||
| except subprocess.CalledProcessError as e: | ||
| pblog.error(f"Command failed with return code {e.returncode}") | ||
|
|
||
| pblog.info(f'Git {supported_git_version} installed successfully.') | ||
| # Delete installation file | ||
| os.remove(git_installer) | ||
|
|
||
| if ( | ||
| os.name == "nt" | ||
|
|
@@ -195,55 +198,38 @@ def sync_handler(sync_val: str, repository_val=None): | |
| if detected_lfs_version == supported_lfs_version: | ||
| pblog.info(f"Current Git LFS version: {detected_lfs_version}") | ||
| else: | ||
| pblog.warning( | ||
| "Git LFS is not updated to the supported version in your system" | ||
| ) | ||
| pblog.warning(f"Supported Git LFS Version: {supported_lfs_version}") | ||
| pblog.warning(f"Current Git LFS Version: {detected_lfs_version}") | ||
| version = f"v{supported_lfs_version}" | ||
| needs_git_update = True | ||
| repo = "git-lfs/git-lfs" | ||
| if os.name == "nt": | ||
| pblog.info("Auto-updating Git LFS...") | ||
| directory = "Saved/PBSyncDownloads" | ||
| download = f"git-lfs-windows-{version}.exe" | ||
| result = pbgh.download_release_file( | ||
| version, | ||
| download, | ||
| directory=directory, | ||
| repo=f"https://github.com/{repo}", | ||
| ) | ||
| if result != 0: | ||
| pblog.error( | ||
| "Git LFS auto-update failed, please download and install manually." | ||
| ) | ||
| webbrowser.open( | ||
| f"https://github.com/{repo}/releases/download/{version}/{download}" | ||
| ) | ||
| else: | ||
| download_path = f"Saved\\PBSyncDownloads\\{download}" | ||
| proc = pbtools.run([download_path]) | ||
| if proc.returncode: | ||
| pblog.error( | ||
| "Git LFS auto-update failed, please download and install manually." | ||
| ) | ||
| webbrowser.open( | ||
| f"https://github.com/{repo}/releases/download/{version}/{download}" | ||
| ) | ||
| else: | ||
| # install LFS for the user | ||
| current_drive = Path().resolve() | ||
| current_drive = current_drive.drive or current_drive.root | ||
| pbtools.run( | ||
| [pbgit.get_lfs_executable(), "install"], cwd=current_drive | ||
| ) | ||
| needs_git_update = False | ||
| os.remove(download_path) | ||
|
|
||
| if needs_git_update: | ||
| pblog.error( | ||
| f"Please install the supported Git LFS version from https://github.com/{repo}/releases/tag/{version}" | ||
| ) | ||
| # Download Git LFS | ||
| try: | ||
| match sys.platform: | ||
| case "win32": subprocess.run(['gh', 'release', 'download', supported_lfs_version, '-p', '*.exe', '-R', 'git-lfs/git-lfs'], check=True) | ||
| case "darwin": | ||
| if platform.machine() == "AMD64": | ||
| subprocess.run(['gh', 'release', 'download', supported_lfs_version, '-p', '*darwin-amd64*', '-R', 'git-lfs/git-lfs'], check=True) | ||
| else: | ||
| subprocess.run(['gh', 'release', 'download', supported_lfs_version, '-p', '*darwin-arm64*', '-R', 'git-lfs/git-lfs'], check=True) | ||
| except subprocess.CalledProcessError as e: | ||
| pblog.error(f"Command failed with return code {e.returncode}") | ||
|
|
||
| # Find the downloaded .exe (Windows) or folder (Mac OS) | ||
| lfs_installer = [file for file in os.listdir() if file.startswith("git-lfs")][0] | ||
|
|
||
| try: | ||
| match sys.platform: | ||
| case "win32": subprocess.run([lfs_installer], '/VERYSILENT', check=True) | ||
| case "darwin": | ||
| subprocess.run(['unzip', lfs_installer], check=True) | ||
| subprocess.run(['sudo', f"./{lfs_installer}/install.sh"], check=True) | ||
| pblog.info(f"Installing Git LFS {supported_lfs_version}...") | ||
| except subprocess.CalledProcessError as e: | ||
| pblog.error(f"Command failed with return code {e.returncode}") | ||
|
|
||
| pblog.info(f'Git LFS {supported_lfs_version} installed successfully.') | ||
|
|
||
| # Delete installation file/folder | ||
| if path.isfile(lfs_installer): | ||
| os.remove(lfs_installer) | ||
| elif path.isdir(lfs_installer): | ||
| shutil.rmtree(lfs_installer) | ||
|
|
||
| # check if Git LFS was installed to a different path | ||
| if os.name == "nt" and pbgit.get_lfs_executable() == "git-lfs": | ||
|
|
@@ -978,3 +964,4 @@ def pbsync_config_parser_func(root): | |
| # Working directory fix for scripts calling PBSync from Scripts folder | ||
| os.chdir("..") | ||
| main(sys.argv[1:]) | ||
|
|
||
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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We use
urllib.requestin other places, so if we are including the requests package, we should probably avoid importingurllib.requestthroughout.