Add checksums for ANGLE and a logging system
This commit is contained in:
		
							parent
							
								
									e12afb619f
								
							
						
					
					
						commit
						76e007ee72
					
				| 
						 | 
				
			
			@ -3,7 +3,12 @@ import os
 | 
			
		|||
import platform
 | 
			
		||||
import subprocess
 | 
			
		||||
 | 
			
		||||
from utils import pushd, removeall, shellish
 | 
			
		||||
import checksum
 | 
			
		||||
from log import *
 | 
			
		||||
from utils import pushd, removeall
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
ANGLE_VERSION = "2023-07-05"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def attach_build_runtime(subparsers):
 | 
			
		||||
| 
						 | 
				
			
			@ -13,24 +18,12 @@ def attach_build_runtime(subparsers):
 | 
			
		|||
 | 
			
		||||
 | 
			
		||||
def build_runtime(args):
 | 
			
		||||
    try:
 | 
			
		||||
        subprocess.run(["clang", "-v"], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
 | 
			
		||||
    except FileNotFoundError:
 | 
			
		||||
        print("ERROR: clang was not found on your system.")
 | 
			
		||||
        if platform.system() == "Windows":
 | 
			
		||||
            print("We recommend installing clang via the Visual Studio installer.")
 | 
			
		||||
            # TODO(ben): Link to the Visual Studio download page (I have no internet right now)
 | 
			
		||||
        elif platform.system() == "Darwin":
 | 
			
		||||
            print("Run the following to install it:")
 | 
			
		||||
            print()
 | 
			
		||||
            print("  brew install llvm")
 | 
			
		||||
            print()
 | 
			
		||||
        exit(1)
 | 
			
		||||
 | 
			
		||||
    # TODO(ben): Check for xcode command line tools
 | 
			
		||||
    ensure_programs()
 | 
			
		||||
    ensure_angle()
 | 
			
		||||
 | 
			
		||||
    build_milepost("lib", args.release)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def build_milepost(target, release):
 | 
			
		||||
    print("Building milepost...")
 | 
			
		||||
    with pushd("milepost"):
 | 
			
		||||
| 
						 | 
				
			
			@ -42,7 +35,8 @@ def build_milepost(target, release):
 | 
			
		|||
            if platform.system() == "Darwin":
 | 
			
		||||
                build_milepost_lib_mac(release)
 | 
			
		||||
            else:
 | 
			
		||||
                print(f"ERROR: can't build milepost for unknown platform '{platform.system()}'")
 | 
			
		||||
                log_error(f"can't build milepost for unknown platform '{platform.system()}'")
 | 
			
		||||
                exit(1)
 | 
			
		||||
        elif target == "test":
 | 
			
		||||
            with pushd("examples/test_app"):
 | 
			
		||||
                # TODO?
 | 
			
		||||
| 
						 | 
				
			
			@ -50,9 +44,10 @@ def build_milepost(target, release):
 | 
			
		|||
        elif target == "clean":
 | 
			
		||||
            removeall("bin")
 | 
			
		||||
        else:
 | 
			
		||||
            print(f"ERROR: unrecognized milepost target '{target}'")
 | 
			
		||||
            log_error(f"unrecognized milepost target '{target}'")
 | 
			
		||||
            exit(1)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def build_milepost_lib_mac(release):
 | 
			
		||||
    sdk_dir = "/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk"
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -123,3 +118,59 @@ def build_milepost_lib_mac(release):
 | 
			
		|||
        "-id", "@rpath/libmilepost.dylib",
 | 
			
		||||
        "bin/libmilepost.dylib",
 | 
			
		||||
    ], check=True)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def ensure_programs():
 | 
			
		||||
    try:
 | 
			
		||||
        subprocess.run(["clang", "-v"], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
 | 
			
		||||
    except FileNotFoundError:
 | 
			
		||||
        msg = log_error("clang was not found on your system.")
 | 
			
		||||
        if platform.system() == "Windows":
 | 
			
		||||
            msg.more("We recommend installing clang via the Visual Studio installer.")
 | 
			
		||||
            # TODO(ben): Link to the Visual Studio download page (I have no internet right now)
 | 
			
		||||
        elif platform.system() == "Darwin":
 | 
			
		||||
            msg.more("Run the following to install it:")
 | 
			
		||||
            msg.more()
 | 
			
		||||
            msg.more("  brew install llvm")
 | 
			
		||||
            msg.more()
 | 
			
		||||
        exit(1)
 | 
			
		||||
    # TODO(ben): Check for xcode command line tools
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def ensure_angle():
 | 
			
		||||
    checkfiles = None
 | 
			
		||||
    if platform.system() == "Windows":
 | 
			
		||||
        checkfiles = [
 | 
			
		||||
            ["libEGL-win", "milepost/lib/libEGL.dll"],
 | 
			
		||||
            ["libGLESv2-win", "milepost/lib/libGLESv2.dll"],
 | 
			
		||||
        ]
 | 
			
		||||
    elif platform.system() == "Darwin":
 | 
			
		||||
        # TODO(ben): Do we need specific builds of ANGLE for each macOS version?
 | 
			
		||||
        if platform.machine() == "arm64":
 | 
			
		||||
            checkfiles = [
 | 
			
		||||
                ["libEGL-mac-arm64", "milepost/lib/libEGL.dylib"],
 | 
			
		||||
                ["libGLESv2-mac-arm64", "milepost/lib/libGLESv2.dylib"],
 | 
			
		||||
            ]
 | 
			
		||||
        else:
 | 
			
		||||
            checkfiles = [
 | 
			
		||||
                ["libEGL-mac-x64", "milepost/lib/libEGL.dylib"],
 | 
			
		||||
                ["libGLESv2-mac-x64", "milepost/lib/libGLESv2.dylib"],
 | 
			
		||||
            ]
 | 
			
		||||
 | 
			
		||||
    if checkfiles is None:
 | 
			
		||||
        log_warning("could not verify if the correct version of ANGLE is present; the build will probably fail.")
 | 
			
		||||
        return
 | 
			
		||||
 | 
			
		||||
    angle_exists = True
 | 
			
		||||
    for file in checkfiles:
 | 
			
		||||
        key = file[0]
 | 
			
		||||
        filepath = file[1]
 | 
			
		||||
        if not os.path.isfile(filepath):
 | 
			
		||||
            angle_exists = False
 | 
			
		||||
            break
 | 
			
		||||
        if not checksum.checkfile(key, filepath):
 | 
			
		||||
            log_error("wrong version of ANGLE libraries installed")
 | 
			
		||||
            exit(1)
 | 
			
		||||
 | 
			
		||||
    if not angle_exists:
 | 
			
		||||
        pass
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,30 @@
 | 
			
		|||
import hashlib
 | 
			
		||||
import json
 | 
			
		||||
 | 
			
		||||
from log import *
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def checkfile(key, filepath):
 | 
			
		||||
    newsum = filesum(filepath)
 | 
			
		||||
 | 
			
		||||
    sums = {}
 | 
			
		||||
    with open("scripts/checksums.json", "r") as sumsfile:
 | 
			
		||||
        sums = json.loads(sumsfile.read())
 | 
			
		||||
    if key not in sums:
 | 
			
		||||
        msg = log_warning(f"no checksum saved for {key}")
 | 
			
		||||
        msg.more(f"file had checksum: {newsum}")
 | 
			
		||||
        return False
 | 
			
		||||
    sum = sums[key]
 | 
			
		||||
 | 
			
		||||
    if sum != newsum:
 | 
			
		||||
        msg = log_warning(f"checksums did not match for {filepath}:")
 | 
			
		||||
        msg.more(f"expected: {sum}")
 | 
			
		||||
        msg.more(f"     got: {newsum}")
 | 
			
		||||
        return False
 | 
			
		||||
 | 
			
		||||
    return True
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def filesum(filepath):
 | 
			
		||||
    with open(filepath, "rb") as file:
 | 
			
		||||
        return hashlib.sha256(file.read()).hexdigest()
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,6 @@
 | 
			
		|||
{
 | 
			
		||||
    "libEGL-win": "3c8b22317664650deba704dd40bbd56447c579ee3a3de18a9c114449a883a36d",
 | 
			
		||||
    "libGLESv2-win": "a10e0ce850a981b11d3d0f01a7efbf8ce46ac74e5fa763b5c43a80c4238da389",
 | 
			
		||||
    "libEGL-mac-arm64": "227445d896047207d1dcef91a8182d886692bc470f402033a6f0831eacb82592",
 | 
			
		||||
    "libGLESv2-mac-arm64": "c814948060494796cda4a3febd8652e1bbf0787a69c2f7e9afd41fc666dc91fe"
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,80 @@
 | 
			
		|||
import subprocess
 | 
			
		||||
import sys
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
errors = []
 | 
			
		||||
warnings = []
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Entry:
 | 
			
		||||
    def __init__(self, msg):
 | 
			
		||||
        self.msgs = [msg]
 | 
			
		||||
 | 
			
		||||
    def more(self, *msgs):
 | 
			
		||||
        if len(msgs) == 0:
 | 
			
		||||
            msgs = [""]
 | 
			
		||||
        for msg in msgs:
 | 
			
		||||
            print(msg)
 | 
			
		||||
            self.msgs.append(msg)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def log_error(msg):
 | 
			
		||||
    msg = f"ERROR: {msg}"
 | 
			
		||||
    print(msg)
 | 
			
		||||
    entry = Entry(msg)
 | 
			
		||||
    errors.append(entry)
 | 
			
		||||
    return entry
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def log_warning(msg):
 | 
			
		||||
    msg = f"WARNING: {msg}"
 | 
			
		||||
    print(msg)
 | 
			
		||||
    entry = Entry(msg)
 | 
			
		||||
    warnings.append(entry)
 | 
			
		||||
    return entry
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def log_finish():
 | 
			
		||||
    if len(errors) + len(warnings) == 0:
 | 
			
		||||
        print("Task completed successfully.")
 | 
			
		||||
        return
 | 
			
		||||
 | 
			
		||||
    print()
 | 
			
		||||
 | 
			
		||||
    errors_str = "1 error" if len(errors) == 1 else f"{len(errors)} errors"
 | 
			
		||||
    warnings_str = "1 warning" if len(warnings) == 1 else f"{len(warnings)} warnings"
 | 
			
		||||
 | 
			
		||||
    if len(errors) > 0 and len(warnings) > 0:
 | 
			
		||||
        print(f"Task failed with {errors_str} and {warnings_str}:")
 | 
			
		||||
        for entry in warnings:
 | 
			
		||||
            print("\n".join(entry.msgs))
 | 
			
		||||
        for entry in errors:
 | 
			
		||||
            print("\n".join(entry.msgs))
 | 
			
		||||
    elif len(errors) > 0:
 | 
			
		||||
        print(f"Task failed with {errors_str}:")
 | 
			
		||||
        for entry in errors:
 | 
			
		||||
            print("\n".join(entry.msgs))
 | 
			
		||||
    elif len(warnings) > 0:
 | 
			
		||||
        print(f"Task failed with {warnings_str}:")
 | 
			
		||||
        for entry in warnings:
 | 
			
		||||
            print("\n".join(entry.msgs))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def shellish(func):
 | 
			
		||||
    def shellfunc(*args, **kwargs):
 | 
			
		||||
        exitcode = 0
 | 
			
		||||
        try:
 | 
			
		||||
            func(*args, **kwargs)
 | 
			
		||||
        except subprocess.CalledProcessError as err:
 | 
			
		||||
            msg = log_error(f"The following command failed with code {err.returncode}:")
 | 
			
		||||
            msg.more(" ".join(err.cmd))
 | 
			
		||||
            exitcode = err.returncode
 | 
			
		||||
        except SystemExit as err:
 | 
			
		||||
            exitcode = err.code
 | 
			
		||||
        except:
 | 
			
		||||
            log_error(sys.exception())
 | 
			
		||||
            exitcode = 1
 | 
			
		||||
        finally:
 | 
			
		||||
            log_finish()
 | 
			
		||||
            exit(exitcode)
 | 
			
		||||
    return shellfunc
 | 
			
		||||
| 
						 | 
				
			
			@ -18,15 +18,3 @@ def pushd(new_dir):
 | 
			
		|||
def removeall(dir):
 | 
			
		||||
    [os.remove(f) for f in glob.iglob("{}/*".format(dir), recursive=True)]
 | 
			
		||||
    os.removedirs(dir)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def shellish(func):
 | 
			
		||||
    def shellfunc(*args, **kwargs):
 | 
			
		||||
        try:
 | 
			
		||||
            func(*args, **kwargs)
 | 
			
		||||
        except subprocess.CalledProcessError as err:
 | 
			
		||||
            print()
 | 
			
		||||
            print(f"ERROR (code {err.returncode}): The following command failed:")
 | 
			
		||||
            print(" ".join(err.cmd))
 | 
			
		||||
            exit(err.returncode)
 | 
			
		||||
    return shellfunc
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue