commit 801a85da0862a08dbe070fd28757af9a4b359659 Author: Alexis Delhaie Date: Sun Aug 9 19:00:43 2020 +0200 v1.0 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5391d87 --- /dev/null +++ b/.gitignore @@ -0,0 +1,138 @@ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ +cover/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +.pybuilder/ +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +# For a library or package, you might want to ignore these files since the code is +# intended to run in multiple environments; otherwise, check them in: +# .python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +# pytype static type analyzer +.pytype/ + +# Cython debug symbols +cython_debug/ \ No newline at end of file diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..bf736dc --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Datasource local storage ignored files +/../../../../../../:\Users\robof\PycharmProjects\pythonProject\.idea/dataSources/ +/dataSources.local.xml +# Editor-based HTTP Client requests +/httpRequests/ diff --git a/.idea/inspectionProfiles/profiles_settings.xml b/.idea/inspectionProfiles/profiles_settings.xml new file mode 100644 index 0000000..105ce2d --- /dev/null +++ b/.idea/inspectionProfiles/profiles_settings.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..f56ad02 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..e15ec35 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/pythonProject.iml b/.idea/pythonProject.iml new file mode 100644 index 0000000..74d515a --- /dev/null +++ b/.idea/pythonProject.iml @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..5ff0ff1 --- /dev/null +++ b/README.md @@ -0,0 +1,9 @@ +# Installer bootstrap +This bootstrap is for Chronos installer ([Github](https://github.com/alexlegarnd/chronos-installer)) but it can be used to bootstrap other software +This installer is developed in Python 3 and packaged to an EXE with PyInstaller + +## Build + +Just run this command: + + ./build.bat diff --git a/app.ico b/app.ico new file mode 100644 index 0000000..d74cfc1 Binary files /dev/null and b/app.ico differ diff --git a/build.bat b/build.bat new file mode 100644 index 0000000..64c2472 --- /dev/null +++ b/build.bat @@ -0,0 +1,16 @@ +@echo off +call clean.bat +pip install -r requirements.txt +IF EXIST "build" ( + RMDIR /S /Q build +) +IF EXIST "dist" ( + RMDIR /S /Q dist +) +IF EXIST "__pycache__" ( + RMDIR /S /Q __pycache__ +) +IF EXIST "main.spec" ( + ERASE main.spec +) +pyinstaller --onefile --uac-admin --icon=app.ico main.py \ No newline at end of file diff --git a/clean.bat b/clean.bat new file mode 100644 index 0000000..9542e4e --- /dev/null +++ b/clean.bat @@ -0,0 +1,13 @@ +@echo off +IF EXIST "build" ( + RMDIR /S /Q build +) +IF EXIST "dist" ( + RMDIR /S /Q dist +) +IF EXIST "__pycache__" ( + RMDIR /S /Q __pycache__ +) +IF EXIST "main.spec" ( + ERASE main.spec +) \ No newline at end of file diff --git a/main.py b/main.py new file mode 100644 index 0000000..4818d51 --- /dev/null +++ b/main.py @@ -0,0 +1,123 @@ +import requests +import os +import subprocess +from rich.progress import Progress +from rich import print +import ctypes +import sys +import shutil + +REPO_URL = "https://alexisdelhaie.ovh/dlcenter/chronos-repo/installer/" +VERSION_FILE = "version" +COMPANY_NAME = "alexlegarnd" +SOFTWARE_NAME = "chronos-installer" +CACHE_FOLDER = "cache" +INSTALL_FOLDER = "{}\\{}\\{}".format(os.getenv('APPDATA'), COMPANY_NAME, SOFTWARE_NAME) +CACHE_FOLDER_PATH = "{}\\{}".format(INSTALL_FOLDER, CACHE_FOLDER) +INSTALLED_VERSION_PATH = "{}\\{}".format(INSTALL_FOLDER, VERSION_FILE) +EXECUTABLE = "Install.exe" +EXECUTABLE_PATH = "{}\\{}".format(INSTALL_FOLDER, EXECUTABLE) +FILES = ["libeay32.dll", "ssleay32.dll", "7z.dll", EXECUTABLE] + + +def get_installed_version(): + print('[bold green]INFO[/] Checking installed version') + if os.path.exists(INSTALLED_VERSION_PATH): + file = open(INSTALLED_VERSION_PATH, "r") + version = file.read() + file.close() + print('[bold green]INFO[/] {} found'.format(version)) + return version + print('[bold green]INFO[/] no version installed') + return "0.0.0" + + +def is_admin(): + try: + return ctypes.windll.shell32.IsUserAnAdmin() + except: + return False + + +def get_version_from_repo(): + print('[bold green]INFO[/] Getting version on repo') + url = "{}{}".format(REPO_URL, VERSION_FILE) + r = requests.get(url, allow_redirects=True) + return r.text + + +def download_file_from_repo(filename): + url = "{}{}".format(REPO_URL, filename) + with open("{}\\{}".format(INSTALL_FOLDER, filename), 'wb') as f: + response = requests.get(url, stream=True) + total_length = response.headers.get('content-length') + + if total_length is None: # no content length header + f.write(response.content) + else: + with Progress() as progress: + task = progress.add_task("Fetching {}".format(filename), total=int(total_length)) + for data in response.iter_content(chunk_size=4096): + f.write(data) + progress.update(task, advance=len(data)) + + +def create_install_folder(): + company_directory = "{}\\{}".format(os.getenv('APPDATA'), COMPANY_NAME) + if not os.path.exists(company_directory): + os.mkdir(company_directory) + print('[bold green]INFO[/] Creating {} folder'.format(company_directory)) + if not os.path.exists(INSTALL_FOLDER): + os.mkdir(INSTALL_FOLDER) + print('[bold green]INFO[/] Creating {} folder'.format(INSTALL_FOLDER)) + + +def clean_folder(path): + if os.path.exists(path): + for filename in os.listdir(path): + if filename != CACHE_FOLDER: + file_path = os.path.join(path, filename) + try: + if os.path.isfile(file_path) or os.path.islink(file_path): + os.unlink(file_path) + elif os.path.isdir(file_path): + shutil.rmtree(file_path) + except Exception as e: + print('[bold red]ERROR[/] Failed to delete {}. Reason: {}'.format(file_path, e)) + + +def clean(): + if '--clean' in sys.argv: + clean_folder(INSTALL_FOLDER) + clean_folder(CACHE_FOLDER_PATH) + if '--clean-cache' in sys.argv: + clean_folder(CACHE_FOLDER_PATH) + if '--clean-installer' in sys.argv: + clean_folder(INSTALL_FOLDER) + + +def main(): + if not is_admin(): + print('[bold red]ERROR[/] This app need to be launched eleveted') + sys.exit(0) + version = get_version_from_repo() + create_install_folder() + clean() + if get_installed_version() != version: + clean_folder(INSTALL_FOLDER) + for file in FILES: + download_file_from_repo(file) + if os.path.exists(INSTALLED_VERSION_PATH): + os.remove(INSTALLED_VERSION_PATH) + file = open(INSTALLED_VERSION_PATH, "w") + file.write(version) + file.close() + if os.path.exists(EXECUTABLE_PATH): + print('[bold green]INFO[/] Starting installer') + subprocess.Popen([EXECUTABLE_PATH], cwd=INSTALL_FOLDER) + else: + print('[bold red]ERROR[/] Executable not found') + input('-- Press enter key to quit --') + + +main() diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..850d442 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,3 @@ +requests +rich +pyinstaller \ No newline at end of file