Skip to content

Commit 9671a19

Browse files
committed
first commit
0 parents  commit 9671a19

File tree

6 files changed

+236
-0
lines changed

6 files changed

+236
-0
lines changed

.github/workflows/main.yml

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
name: Build
2+
on:
3+
push:
4+
branches:
5+
- main
6+
paths:
7+
- '**.py'
8+
- '**.yml'
9+
10+
workflow_dispatch:
11+
12+
jobs:
13+
build:
14+
runs-on: windows-latest
15+
permissions:
16+
contents: write
17+
18+
steps:
19+
- name: Checkout repo
20+
uses: actions/checkout@v4
21+
22+
- name: Setup Python
23+
uses: actions/setup-python@v5
24+
with:
25+
python-version: 3.12.5
26+
cache: 'pip'
27+
28+
- name: Install requirements
29+
run: |
30+
pip install -r requirements.txt
31+
32+
- name: Make Build
33+
run: |
34+
python builder.py
35+
36+
- name: Upload artifact
37+
uses: actions/upload-artifact@v4
38+
with:
39+
name: CollapseUpdater
40+
path: ${{ env.ARTIFACT_PATH }}
41+
42+
- name: Get MD5 Hash of build
43+
run: |
44+
$MD5_HASH=Get-FileHash ${{ env.ARTIFACT_PATH }} -Algorithm MD5
45+
echo "MD5 hash of build $($MD5_HASH.Hash) check it to make sure you downloaded a clean build without viruses."
46+
echo "MD5_HASH=$($MD5_HASH.Hash)" | Out-File -FilePath $env:GITHUB_ENV -Append -Encoding utf8
47+
48+
- name: Make release
49+
uses: ncipollo/release-action@v1
50+
with:
51+
body: "${{ env.ARTIFACT_PATH }}\nMD5 hash: ${{ env.MD5_HASH }}"
52+
name: 'Github actions build: ${{ env.ARTIFACT_HASH }}'
53+
tag: 'autorelease-${{ env.ARTIFACT_HASH }}'
54+
prerelease: true
55+
artifacts: '*.exe'

.gitignore

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# Byte-compiled / optimized / DLL files
2+
__pycache__/
3+
*.py[cod]
4+
*$py.class
5+
6+
# Updater unused files
7+
*.exe
8+
data/

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
# CollapseUpdater, a program that downloads the latest release of [CollapseLoader](https://github.com/dest4590/CollapseLoader)

builder.py

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
import os
2+
import shutil
3+
from glob import glob
4+
5+
6+
class Builder:
7+
"""Class to build to .exe file"""
8+
9+
def __init__(self, name: str = 'CollapseUpdater', icon: str = 'logo.ico'):
10+
self.name = name
11+
self.icon = icon
12+
13+
def build(self, removeBuild: bool = True):
14+
"""Starts the build"""
15+
16+
# Remove old .exe builds
17+
for file in glob('*.exe'):
18+
os.remove(file)
19+
20+
os.system(f'''pyinstaller --onefile --clean --console --name "{self.name}" --icon "collapse\\assets\\{self.icon}" run.py''')
21+
22+
# Move .exe file to root
23+
for file in glob('dist/*.exe'):
24+
shutil.move(file, './')
25+
26+
# Remove build folder
27+
if removeBuild:
28+
self.clear_all()
29+
30+
def clear_all(self):
31+
"""Deletes all unnecessary files"""
32+
33+
if os.path.exists('build/'):
34+
shutil.rmtree('build/')
35+
36+
if os.path.exists('dist/'):
37+
shutil.rmtree('dist/')
38+
39+
# Remove spec file
40+
for spec in glob('*.spec'):
41+
os.remove(spec)
42+
43+
44+
Builder(name='CollapseUpdater_Dev_Build').build()

main.py

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
import argparse
2+
import glob
3+
import os
4+
import sys
5+
6+
import requests
7+
from rich.console import Console
8+
from rich.panel import Panel
9+
from rich.progress import (BarColumn, DownloadColumn, Progress, TextColumn,
10+
TimeRemainingColumn, TransferSpeedColumn)
11+
12+
github_repo = "dest4590/CollapseLoader"
13+
14+
console = Console(highlight=False)
15+
16+
parser = argparse.ArgumentParser(description="CollapseLoader")
17+
parser.add_argument("--prelease", action="store_true", help="Download pre-release")
18+
args, unknown = parser.parse_known_args()
19+
20+
class Updater:
21+
"""Class to update the program"""
22+
23+
def __init__(self, github_repo: str):
24+
console.print(Panel(f"[bold blue]Updater for {github_repo}[/]", expand=False))
25+
26+
self.github_repo = github_repo
27+
self.latest_release = self.get_latest_release()
28+
29+
def get_latest_release(self) -> bool:
30+
"""Get the latest release from the GitHub API"""
31+
if args.prelease:
32+
url = f"https://api.github.com/repos/{github_repo}/releases"
33+
else:
34+
url = f"https://api.github.com/repos/{github_repo}/releases/latest"
35+
36+
try:
37+
response = requests.get(url)
38+
response.raise_for_status()
39+
40+
if response.status_code == 429:
41+
console.print(
42+
"[bold red]Error:[/] Rate limit exceeded! Please wait a while before trying again."
43+
)
44+
return False
45+
46+
elif response.status_code != 200:
47+
console.print("[bold red]Error:[/] Failed to fetch latest release!")
48+
return False
49+
50+
except requests.exceptions.RequestException as e:
51+
console.print("[bold red]Error:[/] Failed to fetch latest release!")
52+
print(e)
53+
return False
54+
55+
if args.prelease:
56+
console.print("[blue]Fetching latest pre-release...[/]")
57+
for release in response.json():
58+
if release['prerelease']:
59+
return release
60+
console.print("[bold red]Error:[/] No pre-release found!")
61+
return False
62+
else:
63+
return response.json()
64+
65+
def download_latest_release(self):
66+
"""Download the latest release from the GitHub API"""
67+
release = self.latest_release
68+
if not release:
69+
return
70+
71+
asset = release["assets"][0]
72+
if args.prelease:
73+
console.print(f"[blue]Downloading latest pre-release:[/]: {asset['name']}")
74+
else:
75+
console.print(f"[blue]Downloading latest release:[/] {asset['name']}")
76+
77+
with Progress(
78+
TextColumn("[bold blue]{task.description}", justify="right"),
79+
BarColumn(),
80+
"[progress.percentage]{task.percentage:>3.1f}%",
81+
"•",
82+
DownloadColumn(),
83+
"•",
84+
TransferSpeedColumn(),
85+
"•",
86+
TimeRemainingColumn(),
87+
) as progress:
88+
task = progress.add_task(
89+
"[green]Downloading", filename=asset["name"], total=asset["size"]
90+
)
91+
92+
download_url = asset["browser_download_url"]
93+
with requests.get(download_url, stream=True) as response:
94+
response.raise_for_status()
95+
with open(asset["name"], "wb") as file:
96+
for chunk in response.iter_content(chunk_size=8192):
97+
file.write(chunk)
98+
progress.update(task, advance=len(chunk))
99+
100+
console.print(f"[green]Downloaded successfully:[/] {asset['name']}")
101+
102+
def delete_old_releases(self, exclude_file=None):
103+
"""Delete old releases of CollapseLoader, optionally excluding a file"""
104+
old_releases = glob.glob("CollapseLoader*")
105+
for old_release in old_releases:
106+
if old_release != exclude_file and os.path.isfile(old_release):
107+
os.remove(old_release)
108+
console.print(f"[yellow]Deleted old release:[/] {old_release}")
109+
110+
def main(self):
111+
"""Main function to update the program"""
112+
if self.latest_release:
113+
latest_release_filename = self.latest_release['assets'][0]['name']
114+
115+
self.delete_old_releases(exclude_file=latest_release_filename)
116+
117+
if not os.path.exists(latest_release_filename):
118+
self.download_latest_release()
119+
else:
120+
console.print("[yellow]Latest version already downloaded.[/]")
121+
122+
console.print("[blue]Starting CollapseLoader...[/]")
123+
command = [latest_release_filename] + sys.argv[1:]
124+
os.system(" ".join(command))
125+
126+
# Prevent running the updater when pyinstaller is building the .exe file
127+
if '_child.py' not in sys.argv[0]:
128+
Updater(github_repo).main()

requirements.txt

Whitespace-only changes.

0 commit comments

Comments
 (0)