162 lines
6.5 KiB
Python
Executable file
162 lines
6.5 KiB
Python
Executable file
#!/usr/bin/env python3
|
|
import argparse
|
|
import os
|
|
import json
|
|
import sys
|
|
import shutil
|
|
import tarfile
|
|
from .lowbar import lowbar
|
|
from urllib.request import urlretrieve
|
|
|
|
progress_bar = lowbar(100)
|
|
|
|
def fail(reason: str):
|
|
print("\033[91m"+ "A critical error occoured:" + "\033[0m")
|
|
print("=> " + reason)
|
|
sys.exit(1)
|
|
|
|
def report_hook(block_count, block_size, file_size):
|
|
global progress_bar
|
|
if file_size == -1:
|
|
return
|
|
downloaded = block_count * block_size
|
|
percentage = round(downloaded / file_size * 100)
|
|
if percentage > 100:
|
|
percentage = 100
|
|
elif percentage < 0:
|
|
percentage = 0
|
|
downloaded = round(downloaded / 1000000, 1)
|
|
size = round(file_size / 1000000, 1)
|
|
if downloaded > size:
|
|
downloaded = size
|
|
progress_bar.update(percentage)
|
|
progress_bar.desc = f"{downloaded}MB/{size}MB"
|
|
|
|
def build(path: str, output: str | None, should_compress: bool, compile_static: bool):
|
|
global progress_bar
|
|
file_path = os.path.realpath(os.path.join(os.getcwd(), path))
|
|
|
|
if not os.path.exists(file_path):
|
|
fail(f"Path not existing: {file_path}")
|
|
if not os.path.isdir(file_path):
|
|
fail(f"Not a directory: {file_path}")
|
|
if (not os.path.exists(os.path.join(file_path, "rodeo-builder.json"))) or (not os.path.isfile(os.path.join(file_path, "rodeo-builder.json"))):
|
|
fail("Could not find the rodeo-builder.json file")
|
|
|
|
os.chdir(file_path)
|
|
|
|
with open(os.path.join(file_path, "rodeo-builder.json"), "rb") as f:
|
|
information = json.load(f)
|
|
|
|
if not "name" in information:
|
|
fail("The rodeo-builder.json file does not contain the 'name' field")
|
|
if not "version" in information:
|
|
fail("The rodeo-builder.json file does not contain the 'version' field")
|
|
if not "build" in information:
|
|
fail("The rodeo-builder.json file does not contain the 'build' field")
|
|
|
|
if compile_static and "build_static" not in information:
|
|
fail("The package does not support static builds")
|
|
|
|
cache_directory = os.getenv("XDG_CACHE_HOME", os.path.expanduser("~/.cache"))
|
|
|
|
build_directory = os.path.join(cache_directory, "rodeo-builder-build")
|
|
|
|
src_directory = os.path.join(build_directory, "package-source")
|
|
|
|
if os.path.exists(build_directory):
|
|
shutil.rmtree(build_directory)
|
|
os.makedirs(build_directory)
|
|
|
|
shutil.copytree(file_path, src_directory)
|
|
|
|
os.chdir(src_directory)
|
|
|
|
package_dependencies = {}
|
|
|
|
if "dependencies" in information:
|
|
if "build" in information["dependencies"]:
|
|
if "packages" in information["dependencies"]["build"]:
|
|
for package in information["dependencies"]["build"]["packages"]:
|
|
if not package in []:
|
|
fail(f"The rodeo package {package} could not be found or is not loaded.")
|
|
if "commands" in information["dependencies"]["build"]:
|
|
for command in information["dependencies"]["build"]["commands"]:
|
|
if shutil.which(command) is None:
|
|
fail(f"The command {command} could not be found and is a build dependency")
|
|
if "runtime" in information["dependencies"]:
|
|
package_dependencies = information["dependencies"]["runtime"]
|
|
|
|
if "web_sources" in information and isinstance(information["web_sources"], dict) and len(information["web_sources"]) > 0:
|
|
for org_url, org_path in information["web_sources"].items():
|
|
url = org_url.replace("$PKG_VERSION", information["version"])
|
|
path = org_path.replace("$PKG_VERSION", information["version"])
|
|
print(f"Downloading source {path} from {url}")
|
|
progress_bar.new()
|
|
urlretrieve(url, path, report_hook)
|
|
print("")
|
|
if not os.path.exists(path):
|
|
fail(f"Download of {path} failed")
|
|
|
|
if "git_sources" in information and isinstance(information["git_sources"], dict) and len(information["git_sources"]) > 0:
|
|
for org_url, org_path in information["git_sources"].items():
|
|
url = org_url.replace("$PKG_VERSION", information["version"])
|
|
path = org_path.replace("$PKG_VERSION", information["version"])
|
|
print(f"Cloning {path} from {url}")
|
|
os.system(f"git clone {url} {path}")
|
|
if not os.path.exists(path):
|
|
fail(f"Cloning of {path} failed")
|
|
|
|
print(f"Building {information['name']}")
|
|
if compile_static:
|
|
build_command = information['build_static']
|
|
else:
|
|
build_command = information['build']
|
|
build_result = os.system(f"PKG_NAME={information['name']} PKG_VERSION={information['version']} OUT_DIR={build_directory} PKG_SRC={src_directory} {build_command}")
|
|
if build_result != 0:
|
|
fail("Build failed")
|
|
|
|
print("Creating rodeo package")
|
|
os.chdir(os.path.join(file_path, build_directory))
|
|
if "extra_package_info" in information:
|
|
json_file = information["extra_package_info"]
|
|
else:
|
|
json_file = {}
|
|
|
|
json_file["name"] = information["name"]
|
|
json_file["version"] = information["version"]
|
|
|
|
json_file["dependencies"] = package_dependencies
|
|
|
|
with open("rodeo-package.json", "wt") as f:
|
|
json.dump(json_file, f)
|
|
|
|
os.chdir(file_path)
|
|
|
|
if output and not should_compress:
|
|
if os.path.exists(os.path.join(file_path, output)):
|
|
shutil.rmtree(os.path.join(file_path, output))
|
|
shutil.move(os.path.join(file_path, build_directory), os.path.join(file_path, output))
|
|
elif output and should_compress:
|
|
print("Compressing package")
|
|
with tarfile.open(output, "w:gz") as tar:
|
|
tar.add(build_directory)
|
|
shutil.rmtree(build_directory)
|
|
elif should_compress:
|
|
print("Compressing package")
|
|
with tarfile.open("package.tar.gz", "w:gz") as tar:
|
|
tar.add(build_directory)
|
|
shutil.rmtree(build_directory)
|
|
|
|
print("\033[92m" + "Done! Package built" + "\033[0m")
|
|
|
|
def main():
|
|
parser = argparse.ArgumentParser(prog="rodeo-builder", description="The rodeo package builder")
|
|
parser.add_argument("--output", "-o", help="The path of the folder/archive to be created", default=None)
|
|
parser.add_argument("--archive", "-a", help="Compress the output into a .tar.gz archive", action="store_true")
|
|
parser.add_argument("--static", "-s", help="Try to build the package statically", action="store_true")
|
|
parser.add_argument("path", help="The path to the archive or folder to build")
|
|
|
|
args = parser.parse_args()
|
|
|
|
build(path=args.path, output=args.output, should_compress=args.archive, compile_static=args.static)
|