deskflow/scripts/install_deps.py
Nick Bolton 8f13ce8e7a
Combine GitHub workflows to reduce config duplication (#7352)
* First attempt merging CI test

* Remove older versions of Linux

* Blend Docker containers and GitHub runners

* Test older configure/build method for Windows

* Re-add old Windows workflow

* Use legacy CMake method for more distros

* Rename image to container

* Reduce config dupe

* Fixed logic for configure

* Use newer build command for Windows

* Move full container name back to matrix (yuk)

* Move GIT_COMMIT to common env

* Use more specific Windows runner name

* Fine-grained timeouts for Mac

* Fixed unit test path for Windows

* Rename CI workflow

* Beginning of macOS dist action

* Update ChangeLog

* More triggers for CI workflow

* Attempt to fix test path on Windows

* Move dist-macos action

* Add dir command for testing

* Remove `test-` job prefix

* Bump msbuild action and try modern cmake again

* Composite actions don't support defaults... grr

* Remove dir diag command

* Trying to use Choco again for VS dep

* Don't skip ninja

* Flush stdout

* Add cl to PATH

* Trying out ilammy/msvc-dev-cmd@v1

* Use @v3 checkout for older Linux

* Fixed comment typo

* Remove dead scripts

* Improve env var names

* Run strip from build dir

* Split out deps script to lib files

* Remove stub action

* Remove dist step for now
2024-06-19 17:48:18 +01:00

214 lines
5.6 KiB
Python
Executable File

#!/usr/bin/env python3
import os
from lib import windows, cmd_utils
import sys
import argparse
import traceback
config_file = "deps.yml"
class YamlError(Exception):
pass
class PlatformError(Exception):
pass
class PathError(Exception):
pass
try:
import yaml # type: ignore
except ImportError:
# this is fairly common in earlier versions of python3,
# which is normally what you find on mac and windows.
print("Python yaml module missing, please install: pip install pyyaml")
sys.exit(1)
def main():
"""Entry point for the script."""
parser = argparse.ArgumentParser()
parser.add_argument(
"--pause-on-exit", action="store_true", help="Useful on Windows"
)
parser.add_argument(
"--only", type=str, help="Only install the specified dependency"
)
args = parser.parse_args()
try:
deps = Dependencies(args.only)
deps.install()
except Exception:
traceback.print_exc()
if args.pause_on_exit:
input("Press enter to continue...")
def get_os():
"""Detects the operating system."""
if sys.platform == "win32":
return "windows"
elif sys.platform == "darwin":
return "mac"
elif sys.platform.startswith("linux"):
return "linux"
else:
raise PlatformError(f"Unsupported platform: {sys.platform}")
def get_linux_distro():
"""Detects the Linux distro."""
os_file = "/etc/os-release"
if os.path.isfile(os_file):
with open(os_file) as f:
for line in f:
if line.startswith("ID="):
return line.strip().split("=")[1].strip('"')
return None
class Config:
"""Reads the dependencies configuration file."""
def __init__(self):
with open(config_file, "r") as f:
data = yaml.safe_load(f)
os_name = get_os()
try:
root = data["dependencies"]
except KeyError:
raise YamlError(f"Nothing found in {config_file} for: dependencies")
try:
self.os = root[os_name]
except KeyError:
raise YamlError(f"Nothing found in {config_file} for: {os_name}")
def get_qt_config(self):
try:
return self.os["qt"]
except KeyError:
raise YamlError(f"Nothing found in {config_file} for: qt")
def get_packages_file(self):
try:
return self.os["packages"]
except KeyError:
raise YamlError(f"Nothing found in {config_file} for: packages")
def get_linux_package_command(self, distro):
try:
distro_data = self.os[distro]
except KeyError:
raise YamlError(f"Nothing found in {config_file} for: {distro}")
try:
command_base = distro_data["command"]
except KeyError:
raise YamlError(f"No package command found in {config_file} for: {distro}")
try:
package_data = distro_data["packages"]
except KeyError:
raise YamlError(f"No package list found in {config_file} for: {distro}")
packages = " ".join(package_data)
return f"{command_base} {packages}"
class Dependencies:
def __init__(self, only):
self.config = Config()
self.only = only
def install(self):
"""Installs dependencies for the current platform."""
os = get_os()
if os == "windows":
self.windows()
elif os == "mac":
self.mac()
elif os == "linux":
self.linux()
else:
raise PlatformError(f"Unsupported platform: {os}")
def windows(self):
"""Installs dependencies on Windows."""
if not windows.is_admin():
windows.relaunch_as_admin(__file__)
sys.exit()
ci_env = os.environ.get("CI")
if ci_env:
print("CI environment detected")
only_qt = self.only == "qt"
# for ci, skip qt; we install qt separately so we can cache it.
if not ci_env or only_qt:
qt = windows.WindowsQt(self.config.get_qt_config(), config_file)
qt_install_dir = qt.get_install_dir()
if qt_install_dir:
print(f"Skipping Qt, already installed at: {qt_install_dir}")
else:
qt.install()
if only_qt:
return
choco = windows.WindowsChoco()
if ci_env:
choco.config_ci_cache()
try:
ci_skip = self.config.os["ci"]["skip"]
choco_config_file = ci_skip["edit-config"]
remove_packages = ci_skip["packages"]
except KeyError:
raise YamlError(f"Bad mapping in {config_file} on Windows for: ci")
choco.remove_from_config(choco_config_file, remove_packages)
try:
command = self.config.os["command"]
except KeyError:
raise YamlError(f"Nothing found in {config_file} on Windows for: command")
choco.install(command, ci_env)
def mac(self):
"""Installs dependencies on macOS."""
try:
command = self.config.os["command"]
except KeyError:
raise YamlError(f"Nothing found in {config_file} on Mac for: command")
cmd_utils.run(command)
def linux(self):
"""Installs dependencies on Linux."""
distro = get_linux_distro()
if not distro:
raise PlatformError("Unable to detect Linux distro")
command = self.config.get_linux_package_command(distro)
cmd_utils.run(command)
if __name__ == "__main__":
main()