This repository has been archived on 2022-06-22. You can view files and clone it, but cannot push or open issues or pull requests.
Kosmos/Builder/modules.py

537 lines
21 KiB
Python
Raw Normal View History

2020-03-15 13:38:33 +00:00
#
# Kosmos Builder
# Copyright (C) 2020 Nichole Mattera
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
# 02110-1301, USA.
#
import common
import config
from github import Github
from gitlab import Gitlab
import json
import os
import re
import shutil
import urllib.request
import uuid
2020-05-05 21:04:42 +00:00
import xmltodict
2020-03-15 13:38:33 +00:00
import zipfile
gh = Github(config.github_username, config.github_password)
gl = Gitlab('https://gitlab.com', private_token=config.gitlab_private_access_token)
gl.auth()
2020-05-05 21:04:42 +00:00
def get_latest_release(module, include_prereleases = True):
2020-03-15 13:38:33 +00:00
if common.GitService(module['git']['service']) == common.GitService.GitHub:
try:
repo = gh.get_repo(f'{module["git"]["org_name"]}/{module["git"]["repo_name"]}')
except:
print(f'[Error] Unable to find repo: {module["git"]["org_name"]}/{module["git"]["repo_name"]}')
return None
releases = repo.get_releases()
if releases.totalCount == 0:
print(f'[Error] Unable to find any releases for repo: {module["git"]["org_name"]}/{module["git"]["repo_name"]}')
return None
2020-05-05 21:04:42 +00:00
if include_prereleases:
return releases[0]
for release in releases:
if not release.prerelease:
return release
2020-03-15 13:38:33 +00:00
2020-05-05 21:04:42 +00:00
return None
elif common.GitService(module['git']['service']) == common.GitService.GitLab:
2020-03-15 13:38:33 +00:00
try:
project = gl.projects.get(f'{module["git"]["org_name"]}/{module["git"]["repo_name"]}')
except:
print(f'[Error] Unable to find repo: {module["git"]["org_name"]}/{module["git"]["repo_name"]}')
return None
tags = project.tags.list()
for tag in tags:
if tag.release is not None:
return tag
print(f'[Error] Unable to find any releases for repo: {module["git"]["org_name"]}/{module["git"]["repo_name"]}')
return None
2020-05-05 21:04:42 +00:00
else:
releases = None
with urllib.request.urlopen(f'https://sourceforge.net/projects/{module["git"]["repo_name"]}/rss?path=/') as fd:
releases = xmltodict.parse(fd.read().decode('utf-8'))
return releases
2020-03-15 13:38:33 +00:00
def download_asset(module, release, index):
pattern = module['git']['asset_patterns'][index]
if common.GitService(module['git']['service']) == common.GitService.GitHub:
if release is None:
return None
matched_asset = None
for asset in release.get_assets():
if re.search(pattern, asset.name):
matched_asset = asset
break
if matched_asset is None:
print(f'[Error] Unable to find asset that match pattern: "{pattern}"')
return None
download_path = common.generate_temp_path()
urllib.request.urlretrieve(matched_asset.browser_download_url, download_path)
return download_path
2020-05-05 21:04:42 +00:00
elif common.GitService(module['git']['service']) == common.GitService.GitLab:
2020-03-15 13:38:33 +00:00
group = module['git']['group']
match = re.search(pattern, release.release['description'])
if match is None:
return None
groups = match.groups()
if len(groups) <= group:
return None
download_path = common.generate_temp_path()
urllib.request.urlretrieve(f'https://gitlab.com/{module["git"]["org_name"]}/{module["git"]["repo_name"]}{groups[group]}', download_path)
2020-05-05 21:04:42 +00:00
return download_path
else:
matched_item = None
for item in release['rss']['channel']['item']:
if re.search(pattern, item['title']):
matched_item = item
break
if matched_item is None:
print(f'[Error] Unable to find asset that match pattern: "{pattern}"')
return None
download_path = common.generate_temp_path()
urllib.request.urlretrieve(matched_item['link'], download_path)
2020-03-15 13:38:33 +00:00
return download_path
def find_asset(release, pattern):
for asset in release.get_assets():
if re.search(pattern, asset.name):
return asset
return None
2020-05-05 21:04:42 +00:00
def get_version(module, release, index):
if common.GitService(module['git']['service']) == common.GitService.GitHub:
return release.tag_name
elif common.GitService(module['git']['service']) == common.GitService.GitLab:
return release.name
else:
matched_item = None
for item in release['rss']['channel']['item']:
if re.search(module['git']['asset_patterns'][index], item['title']):
matched_item = item
break
if matched_item is None:
return "Latest"
match = re.search(module['git']['version_pattern'], matched_item['title'])
if match is None:
return "Latest"
groups = match.groups()
if len(groups) == 0:
return "Latest"
return groups[0]
2020-03-15 13:38:33 +00:00
def download_atmosphere(module, temp_directory, kosmos_version, kosmos_build):
release = get_latest_release(module)
bundle_path = download_asset(module, release, 0)
if bundle_path is None:
return None
with zipfile.ZipFile(bundle_path, 'r') as zip_ref:
zip_ref.extractall(temp_directory)
common.delete_path(bundle_path)
common.delete_path(os.path.join(temp_directory, 'switch', 'reboot_to_payload.nro'))
2020-05-05 21:04:42 +00:00
common.delete_path(os.path.join(temp_directory, 'switch'))
2020-03-15 13:38:33 +00:00
common.delete_path(os.path.join(temp_directory, 'atmosphere', 'reboot_payload.bin'))
payload_path = download_asset(module, release, 1)
if payload_path is None:
return None
common.mkdir(os.path.join(temp_directory, 'bootloader', 'payloads'))
shutil.move(payload_path, os.path.join(temp_directory, 'bootloader', 'payloads', 'fusee-primary.bin'))
2020-04-10 00:30:33 +00:00
2020-03-15 13:38:33 +00:00
common.copy_module_file('atmosphere', 'system_settings.ini', os.path.join(temp_directory, 'atmosphere', 'config', 'system_settings.ini'))
2020-04-10 00:30:33 +00:00
2020-03-15 13:38:33 +00:00
if not kosmos_build:
common.delete_path(os.path.join(temp_directory, 'hbmenu.nro'))
2020-05-05 21:04:42 +00:00
return get_version(module, release, 0)
2020-03-15 13:38:33 +00:00
def download_hekate(module, temp_directory, kosmos_version, kosmos_build):
release = get_latest_release(module)
bundle_path = download_asset(module, release, 0)
if bundle_path is None:
return None
with zipfile.ZipFile(bundle_path, 'r') as zip_ref:
zip_ref.extractall(temp_directory)
common.delete_path(bundle_path)
common.copy_module_file('hekate', 'bootlogo.bmp', os.path.join(temp_directory, 'bootloader', 'bootlogo.bmp'))
common.copy_module_file('hekate', 'hekate_ipl.ini', os.path.join(temp_directory, 'bootloader', 'hekate_ipl.ini'))
common.sed('KOSMOS_VERSION', kosmos_version, os.path.join(temp_directory, 'bootloader', 'hekate_ipl.ini'))
payload = common.find_file(os.path.join(temp_directory, 'hekate_ctcaer_*.bin'))
if len(payload) != 0:
shutil.copyfile(payload[0], os.path.join(temp_directory, 'bootloader', 'update.bin'))
common.mkdir(os.path.join(temp_directory, 'atmosphere'))
shutil.copyfile(payload[0], os.path.join(temp_directory, 'atmosphere', 'reboot_payload.bin'))
2020-05-05 21:04:42 +00:00
common.delete_path(os.path.join(temp_directory, 'nyx_usb_max_rate (run once per windows pc).reg'))
2020-03-15 13:38:33 +00:00
if not kosmos_build:
common.mkdir(os.path.join(temp_directory, '..', 'must_have'))
2020-05-05 21:04:42 +00:00
common.move_contents_of_folder(os.path.join(temp_directory, 'bootloader'), os.path.join(temp_directory, '..', 'must_have', 'bootloader'))
shutil.move(os.path.join(temp_directory, 'atmosphere', 'reboot_payload.bin'), os.path.join(temp_directory, '..', 'must_have', 'atmosphere', 'reboot_payload.bin'))
common.delete_path(os.path.join(temp_directory, 'atmosphere'))
2020-03-15 13:38:33 +00:00
2020-05-05 21:04:42 +00:00
return get_version(module, release, 0)
def download_hekate_icons(module, temp_directory, kosmos_version, kosmos_build):
release = get_latest_release(module)
bundle_path = download_asset(module, release, 0)
if bundle_path is None:
return None
with zipfile.ZipFile(bundle_path, 'r') as zip_ref:
zip_ref.extractall(temp_directory)
common.delete_path(bundle_path)
shutil.move(os.path.join(temp_directory, 'bootloader', 'res', 'icon_payload.bmp'), os.path.join(temp_directory, 'bootloader', 'res', 'icon_payload_hue.bmp'))
2020-05-13 18:45:13 +00:00
#shutil.move(os.path.join(temp_directory, 'bootloader', 'res', 'icon_payload_custom.bmp'), os.path.join(temp_directory, 'bootloader', 'res', 'icon_payload.bmp'))
2020-05-05 21:04:42 +00:00
shutil.move(os.path.join(temp_directory, 'bootloader', 'res', 'icon_switch.bmp'), os.path.join(temp_directory, 'bootloader', 'res', 'icon_switch_hue.bmp'))
2020-05-13 18:45:13 +00:00
#shutil.move(os.path.join(temp_directory, 'bootloader', 'res', 'icon_switch_custom.bmp'), os.path.join(temp_directory, 'bootloader', 'res', 'icon_switch.bmp'))
2020-05-05 21:04:42 +00:00
return get_version(module, release, 0)
2020-03-15 13:38:33 +00:00
def download_appstore(module, temp_directory, kosmos_version, kosmos_build):
release = get_latest_release(module)
bundle_path = download_asset(module, release, 0)
if bundle_path is None:
return None
with zipfile.ZipFile(bundle_path, 'r') as zip_ref:
zip_ref.extractall(temp_directory)
common.delete_path(bundle_path)
common.mkdir(os.path.join(temp_directory, 'switch', 'appstore'))
shutil.move(os.path.join(temp_directory, 'appstore.nro'), os.path.join(temp_directory, 'switch', 'appstore', 'appstore.nro'))
2020-05-05 21:04:42 +00:00
return get_version(module, release, 0)
2020-03-15 13:38:33 +00:00
def download_edizon(module, temp_directory, kosmos_version, kosmos_build):
release = get_latest_release(module)
app_path = download_asset(module, release, 0)
if app_path is None:
return None
common.mkdir(os.path.join(temp_directory, 'switch', 'EdiZon'))
shutil.move(app_path, os.path.join(temp_directory, 'switch', 'EdiZon', 'EdiZon.nro'))
2020-05-05 21:04:42 +00:00
overlay_path = download_asset(module, release, 1)
if overlay_path is None:
return None
common.mkdir(os.path.join(temp_directory, 'switch', '.overlays'))
shutil.move(overlay_path, os.path.join(temp_directory, 'switch', '.overlays', 'ovlEdiZon.ovl'))
return get_version(module, release, 0)
2020-03-15 13:38:33 +00:00
def download_emuiibo(module, temp_directory, kosmos_version, kosmos_build):
release = get_latest_release(module)
bundle_path = download_asset(module, release, 0)
if bundle_path is None:
return None
with zipfile.ZipFile(bundle_path, 'r') as zip_ref:
zip_ref.extractall(temp_directory)
common.delete_path(bundle_path)
common.mkdir(os.path.join(temp_directory, 'atmosphere', 'contents'))
shutil.move(os.path.join(temp_directory, 'SdOut', 'atmosphere', 'contents', '0100000000000352'), os.path.join(temp_directory, 'atmosphere', 'contents', '0100000000000352'))
common.mkdir(os.path.join(temp_directory, 'switch', '.overlays'))
shutil.move(os.path.join(temp_directory, 'SdOut', 'switch', '.overlays', 'emuiibo.ovl'), os.path.join(temp_directory, 'switch', '.overlays', 'emuiibo.ovl'))
common.delete_path(os.path.join(temp_directory, 'SdOut'))
2020-03-15 13:38:33 +00:00
if kosmos_build:
common.delete_path(os.path.join(temp_directory, 'atmosphere', 'contents', '0100000000000352', 'flags', 'boot2.flag'))
common.copy_module_file('emuiibo', 'toolbox.json', os.path.join(temp_directory, 'atmosphere', 'contents', '0100000000000352', 'toolbox.json'))
2020-05-05 21:04:42 +00:00
return get_version(module, release, 0)
2020-03-15 13:38:33 +00:00
def download_goldleaf(module, temp_directory, kosmos_version, kosmos_build):
release = get_latest_release(module)
app_path = download_asset(module, release, 0)
if app_path is None:
return None
common.mkdir(os.path.join(temp_directory, 'switch', 'Goldleaf'))
shutil.move(app_path, os.path.join(temp_directory, 'switch', 'Goldleaf', 'Goldleaf.nro'))
2020-05-05 21:04:42 +00:00
return get_version(module, release, 0)
2020-03-15 13:38:33 +00:00
def download_kosmos_cleaner(module, temp_directory, kosmos_version, kosmos_build):
release = get_latest_release(module)
bundle_path = download_asset(module, release, 0)
if bundle_path is None:
return None
with zipfile.ZipFile(bundle_path, 'r') as zip_ref:
zip_ref.extractall(temp_directory)
2020-05-05 21:04:42 +00:00
return get_version(module, release, 0)
2020-03-15 13:38:33 +00:00
def download_kosmos_toolbox(module, temp_directory, kosmos_version, kosmos_build):
release = get_latest_release(module)
app_path = download_asset(module, release, 0)
if app_path is None:
return None
common.mkdir(os.path.join(temp_directory, 'switch', 'KosmosToolbox'))
shutil.move(app_path, os.path.join(temp_directory, 'switch', 'KosmosToolbox', 'KosmosToolbox.nro'))
common.copy_module_file('kosmos-toolbox', 'config.json', os.path.join(temp_directory, 'switch', 'KosmosToolbox', 'config.json'))
2020-05-05 21:04:42 +00:00
return get_version(module, release, 0)
2020-03-15 13:38:33 +00:00
def download_kosmos_updater(module, temp_directory, kosmos_version, kosmos_build):
release = get_latest_release(module)
app_path = download_asset(module, release, 0)
if app_path is None:
return None
common.mkdir(os.path.join(temp_directory, 'switch', 'KosmosUpdater'))
shutil.move(app_path, os.path.join(temp_directory, 'switch', 'KosmosUpdater', 'KosmosUpdater.nro'))
common.copy_module_file('kosmos-updater', 'internal.db', os.path.join(temp_directory, 'switch', 'KosmosUpdater', 'internal.db'))
common.sed('KOSMOS_VERSION', kosmos_version, os.path.join(temp_directory, 'switch', 'KosmosUpdater', 'internal.db'))
2020-05-05 21:04:42 +00:00
return get_version(module, release, 0)
2020-03-15 13:38:33 +00:00
def download_ldn_mitm(module, temp_directory, kosmos_version, kosmos_build):
release = get_latest_release(module)
bundle_path = download_asset(module, release, 0)
if bundle_path is None:
return None
with zipfile.ZipFile(bundle_path, 'r') as zip_ref:
zip_ref.extractall(temp_directory)
common.delete_path(bundle_path)
if kosmos_build:
common.delete_path(os.path.join(temp_directory, 'atmosphere', 'contents', '4200000000000010', 'flags', 'boot2.flag'))
common.copy_module_file('ldn_mitm', 'toolbox.json', os.path.join(temp_directory, 'atmosphere', 'contents', '4200000000000010', 'toolbox.json'))
2020-05-05 21:04:42 +00:00
return get_version(module, release, 0)
2020-03-15 13:38:33 +00:00
def download_lockpick(module, temp_directory, kosmos_version, kosmos_build):
release = get_latest_release(module)
app_path = download_asset(module, release, 0)
if app_path is None:
return None
common.mkdir(os.path.join(temp_directory, 'switch', 'Lockpick'))
shutil.move(app_path, os.path.join(temp_directory, 'switch', 'Lockpick', 'Lockpick.nro'))
2020-05-05 21:04:42 +00:00
return get_version(module, release, 0)
2020-03-15 13:38:33 +00:00
def download_lockpick_rcm(module, temp_directory, kosmos_version, kosmos_build):
release = get_latest_release(module)
payload_path = download_asset(module, release, 0)
if payload_path is None:
return None
if kosmos_build:
common.mkdir(os.path.join(temp_directory, 'bootloader', 'payloads'))
shutil.move(payload_path, os.path.join(temp_directory, 'bootloader', 'payloads', 'Lockpick_RCM.bin'))
else:
shutil.move(payload_path, os.path.join(temp_directory, 'Lockpick_RCM.bin'))
2020-05-05 21:04:42 +00:00
return get_version(module, release, 0)
2020-03-15 13:38:33 +00:00
def download_nxdumptool(module, temp_directory, kosmos_version, kosmos_build):
release = get_latest_release(module)
app_path = download_asset(module, release, 0)
if app_path is None:
return None
common.mkdir(os.path.join(temp_directory, 'switch', 'NXDumpTool'))
shutil.move(app_path, os.path.join(temp_directory, 'switch', 'NXDumpTool', 'NXDumpTool.nro'))
2020-05-05 21:04:42 +00:00
return get_version(module, release, 0)
2020-03-15 13:38:33 +00:00
def download_nx_ovlloader(module, temp_directory, kosmos_version, kosmos_build):
release = get_latest_release(module)
bundle_path = download_asset(module, release, 0)
if bundle_path is None:
return None
with zipfile.ZipFile(bundle_path, 'r') as zip_ref:
zip_ref.extractall(temp_directory)
common.delete_path(bundle_path)
2020-05-05 21:04:42 +00:00
return get_version(module, release, 0)
2020-03-15 13:38:33 +00:00
def download_ovl_sysmodules(module, temp_directory, kosmos_version, kosmos_build):
release = get_latest_release(module)
app_path = download_asset(module, release, 0)
if app_path is None:
return None
common.mkdir(os.path.join(temp_directory, 'switch', '.overlays'))
shutil.move(app_path, os.path.join(temp_directory, 'switch', '.overlays', 'ovlSysmodules.ovl'))
2020-05-05 21:04:42 +00:00
return get_version(module, release, 0)
2020-03-15 13:38:33 +00:00
def download_status_monitor_overlay(module, temp_directory, kosmos_version, kosmos_build):
release = get_latest_release(module)
app_path = download_asset(module, release, 0)
if app_path is None:
return None
common.mkdir(os.path.join(temp_directory, 'switch', '.overlays'))
shutil.move(app_path, os.path.join(temp_directory, 'switch', '.overlays', 'Status-Monitor-Overlay.ovl'))
2020-05-05 21:04:42 +00:00
return get_version(module, release, 0)
2020-03-15 13:38:33 +00:00
def download_sys_clk(module, temp_directory, kosmos_version, kosmos_build):
release = get_latest_release(module)
bundle_path = download_asset(module, release, 0)
if bundle_path is None:
return None
with zipfile.ZipFile(bundle_path, 'r') as zip_ref:
zip_ref.extractall(temp_directory)
common.delete_path(bundle_path)
if kosmos_build:
common.delete_path(os.path.join(temp_directory, 'atmosphere', 'contents', '00FF0000636C6BFF', 'flags', 'boot2.flag'))
common.delete_path(os.path.join(temp_directory, 'README.md'))
common.copy_module_file('sys-clk', 'toolbox.json', os.path.join(temp_directory, 'atmosphere', 'contents', '00FF0000636C6BFF', 'toolbox.json'))
2020-05-05 21:04:42 +00:00
return get_version(module, release, 0)
2020-03-15 13:38:33 +00:00
def download_sys_con(module, temp_directory, kosmos_version, kosmos_build):
release = get_latest_release(module)
bundle_path = download_asset(module, release, 0)
if bundle_path is None:
return None
with zipfile.ZipFile(bundle_path, 'r') as zip_ref:
zip_ref.extractall(temp_directory)
common.delete_path(bundle_path)
if kosmos_build:
common.delete_path(os.path.join(temp_directory, 'atmosphere', 'contents', '690000000000000D', 'flags', 'boot2.flag'))
2020-05-05 21:04:42 +00:00
return get_version(module, release, 0)
2020-03-15 13:38:33 +00:00
def download_sys_ftpd_light(module, temp_directory, kosmos_version, kosmos_build):
release = get_latest_release(module)
bundle_path = download_asset(module, release, 0)
if bundle_path is None:
return None
with zipfile.ZipFile(bundle_path, 'r') as zip_ref:
zip_ref.extractall(temp_directory)
common.delete_path(bundle_path)
if kosmos_build:
common.delete_path(os.path.join(temp_directory, 'atmosphere', 'contents', '420000000000000E', 'flags', 'boot2.flag'))
2020-05-05 21:04:42 +00:00
return get_version(module, release, 0)
2020-03-15 13:38:33 +00:00
def download_tesla_menu(module, temp_directory, kosmos_version, kosmos_build):
release = get_latest_release(module)
bundle_path = download_asset(module, release, 0)
if bundle_path is None:
return None
with zipfile.ZipFile(bundle_path, 'r') as zip_ref:
zip_ref.extractall(temp_directory)
common.delete_path(bundle_path)
2020-05-05 21:04:42 +00:00
return get_version(module, release, 0)
2020-03-15 13:38:33 +00:00
2020-05-05 21:04:42 +00:00
def build(temp_directory, kosmos_version, command, auto_build):
2020-03-15 13:38:33 +00:00
results = []
2020-05-05 21:04:42 +00:00
modules_filename = 'kosmos.json'
if command == common.Command.KosmosMinimal:
modules_filename = 'kosmos-minimal.json'
elif command == common.Command.SDSetup:
modules_filename = 'sdsetup.json'
2020-03-15 13:38:33 +00:00
# Open up modules.json
2020-05-05 21:04:42 +00:00
with open(modules_filename) as json_file:
2020-03-15 13:38:33 +00:00
# Parse JSON
data = json.load(json_file)
# Loop through modules
for module in data:
# Running a SDSetup Build
2020-05-05 21:04:42 +00:00
if command == common.Command.SDSetup:
2020-03-15 13:38:33 +00:00
# Only show prompts when it's not an auto build.
if not auto_build:
print(f'Downloading {module["name"]}...')
# Make sure module directory is created.
2020-05-05 21:04:42 +00:00
module_directory = os.path.join(temp_directory, module['sdsetup_module_name'])
2020-03-15 13:38:33 +00:00
common.mkdir(module_directory)
# Download the module.
download = globals()[module['download_function_name']]
2020-05-05 21:04:42 +00:00
version = download(module, module_directory, kosmos_version, False)
2020-03-15 13:38:33 +00:00
if version is None:
return None
# Auto builds have a different prompt at the end for parsing.
if auto_build:
2020-05-05 21:04:42 +00:00
results.append(f'{module["sdsetup_module_name"]}:{version}')
2020-03-15 13:38:33 +00:00
else:
results.append(f' {module["name"]} - {version}')
2020-05-05 21:04:42 +00:00
# Running a Kosmos Build
else:
# Download the module.
print(f'Downloading {module["name"]}...')
download = globals()[module['download_function_name']]
version = download(module, temp_directory, kosmos_version, True)
if version is None:
return None
results.append(f' {module["name"]} - {version}')
2020-03-15 13:38:33 +00:00
return results