diff --git a/.github/actions/build-plugin/action.yaml b/.github/actions/build-plugin/action.yaml new file mode 100644 index 0000000..e5839ea --- /dev/null +++ b/.github/actions/build-plugin/action.yaml @@ -0,0 +1,113 @@ +name: Set up and build plugin +description: Builds the plugin for specified architecture and build config +inputs: + target: + description: Target architecture for dependencies + required: true + config: + description: Build configuration + required: false + default: RelWithDebInfo + codesign: + description: Enable codesigning (macOS only) + required: false + default: 'false' + codesignIdent: + description: Developer ID for application codesigning (macOS only) + required: false + default: '-' + codesignTeam: + description: Team ID for application codesigning (macOS only) + required: false + default: '' + workingDirectory: + description: Working directory for packaging + required: false + default: ${{ github.workspace }} +runs: + using: composite + steps: + - name: Run macOS Build + if: runner.os == 'macOS' + shell: zsh --no-rcs --errexit --pipefail {0} + working-directory: ${{ inputs.workingDirectory }} + env: + CCACHE_DIR: ${{ inputs.workingDirectory }}/.ccache + CODESIGN_IDENT: ${{ inputs.codesignIdent }} + CODESIGN_TEAM: ${{ inputs.codesignTeam }} + run: | + : Run macOS Build + + local -a build_args=(--config ${{ inputs.config }}) + if (( ${+RUNNER_DEBUG} )) build_args+=(--debug) + + if [[ '${{ inputs.codesign }}' == 'true' ]] build_args+=(--codesign) + + .github/scripts/build-macos ${build_args} + + - name: Install Dependencies 🛍️ + if: runner.os == 'Linux' + shell: bash + run: | + : Install Dependencies 🛍️ + echo ::group::Install Dependencies + eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)" + echo "/home/linuxbrew/.linuxbrew/bin:/home/linuxbrew/.linuxbrew/sbin" >> $GITHUB_PATH + brew install --quiet zsh + echo ::endgroup:: + + - name: Run Ubuntu Build + if: runner.os == 'Linux' + shell: zsh --no-rcs --errexit --pipefail {0} + working-directory: ${{ inputs.workingDirectory }} + env: + CCACHE_DIR: ${{ inputs.workingDirectory }}/.ccache + run: | + : Run Ubuntu Build + + local -a build_args=( + --target ubuntu-${{ inputs.target }} + --config ${{ inputs.config }} + ) + if (( ${+RUNNER_DEBUG} )) build_args+=(--debug) + + .github/scripts/build-ubuntu ${build_args} + + - name: Run Windows Build + if: runner.os == 'Windows' + shell: pwsh + run: | + # Run Windows Build + if ( $Env:RUNNER_DEBUG -ne $null ) { + Set-PSDebug -Trace 1 + } + + $BuildArgs = @{ + Target = '${{ inputs.target }}' + Configuration = '${{ inputs.config }}' + } + + .github/scripts/Build-Windows.ps1 @BuildArgs + + - name: Create Summary 📊 + if: contains(fromJSON('["Linux", "macOS"]'),runner.os) + shell: zsh --no-rcs --errexit --pipefail {0} + env: + CCACHE_DIR: ${{ inputs.workingDirectory }}/.ccache + run: | + : Create Summary 📊 + + local -a ccache_data + if (( ${+RUNNER_DEBUG} )) { + setopt XTRACE + ccache_data=("${(fA)$(ccache -s -vv)}") + } else { + ccache_data=("${(fA)$(ccache -s)}") + } + + print '### ${{ runner.os }} Ccache Stats (${{ inputs.target }})' >> $GITHUB_STEP_SUMMARY + print '```' >> $GITHUB_STEP_SUMMARY + for line (${ccache_data}) { + print ${line} >> $GITHUB_STEP_SUMMARY + } + print '```' >> $GITHUB_STEP_SUMMARY diff --git a/.github/actions/package-plugin/action.yaml b/.github/actions/package-plugin/action.yaml new file mode 100644 index 0000000..11fdccf --- /dev/null +++ b/.github/actions/package-plugin/action.yaml @@ -0,0 +1,113 @@ +name: Package plugin +description: Packages the plugin for specified architecture and build config. +inputs: + target: + description: Build target for dependencies + required: true + config: + description: Build configuration + required: false + default: RelWithDebInfo + codesign: + description: Enable codesigning (macOS only) + required: false + default: 'false' + notarize: + description: Enable notarization (macOS only) + required: false + default: 'false' + codesignIdent: + description: Developer ID for application codesigning (macOS only) + required: false + default: '-' + installerIdent: + description: Developer ID for installer package codesigning (macOS only) + required: false + default: '' + codesignTeam: + description: Developer team for codesigning (macOS only) + required: false + default: '' + codesignUser: + description: Apple ID username for notarization (macOS only) + required: false + default: '' + codesignPass: + description: Apple ID password for notarization (macOS only) + required: false + default: '' + package: + description: Create Windows or macOS installation package + required: false + default: 'false' + workingDirectory: + description: Working directory for packaging + required: false + default: ${{ github.workspace }} +runs: + using: composite + steps: + - name: Run macOS Packaging + if: runner.os == 'macOS' + shell: zsh --no-rcs --errexit --pipefail {0} + working-directory: ${{ inputs.workingDirectory }} + env: + CODESIGN_IDENT: ${{ inputs.codesignIdent }} + CODESIGN_IDENT_INSTALLER: ${{ inputs.installerIdent }} + CODESIGN_TEAM: ${{ inputs.codesignTeam }} + CODESIGN_IDENT_USER: ${{ inputs.codesignUser }} + CODESIGN_IDENT_PASS: ${{ inputs.codesignPass }} + run: | + : Run macOS Packaging + + local -a package_args=(--config ${{ inputs.config }}) + if (( ${+RUNNER_DEBUG} )) package_args+=(--debug) + + if [[ '${{ inputs.codesign }}' == 'true' ]] package_args+=(--codesign) + if [[ '${{ inputs.notarize }}' == 'true' ]] package_args+=(--notarize) + if [[ '${{ inputs.package }}' == 'true' ]] package_args+=(--package) + + .github/scripts/package-macos ${package_args} + + - name: Install Dependencies 🛍️ + if: runner.os == 'Linux' + shell: bash + run: | + : Install Dependencies 🛍️ + echo ::group::Install Dependencies + eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)" + echo "/home/linuxbrew/.linuxbrew/bin:/home/linuxbrew/.linuxbrew/sbin" >> $GITHUB_PATH + brew install --quiet zsh + echo ::endgroup:: + + - name: Run Ubuntu Packaging + if: runner.os == 'Linux' + shell: zsh --no-rcs --errexit --pipefail {0} + working-directory: ${{ inputs.workingDirectory }} + run: | + : Run Ubuntu Packaging + package_args=( + --target ubuntu-${{ inputs.target }} + --config ${{ inputs.config }} + ) + if (( ${+RUNNER_DEBUG} )) build_args+=(--debug) + + if [[ '${{ inputs.package }}' == 'true' ]] package_args+=(--package) + + .github/scripts/package-ubuntu ${package_args} + + - name: Run Windows Packaging + if: runner.os == 'Windows' + shell: pwsh + run: | + # Run Windows Packaging + if ( $Env:RUNNER_DEBUG -ne $null ) { + Set-PSDebug -Trace 1 + } + + $PackageArgs = @{ + Target = '${{ inputs.target }}' + Configuration = '${{ inputs.config }}' + } + + .github/scripts/Package-Windows.ps1 @PackageArgs diff --git a/.github/scripts/Build-Windows.ps1 b/.github/scripts/Build-Windows.ps1 new file mode 100644 index 0000000..d56e61d --- /dev/null +++ b/.github/scripts/Build-Windows.ps1 @@ -0,0 +1,86 @@ +[CmdletBinding()] +param( + [ValidateSet('x64')] + [string] $Target = 'x64', + [ValidateSet('Debug', 'RelWithDebInfo', 'Release', 'MinSizeRel')] + [string] $Configuration = 'RelWithDebInfo' +) + +$ErrorActionPreference = 'Stop' + +if ( $DebugPreference -eq 'Continue' ) { + $VerbosePreference = 'Continue' + $InformationPreference = 'Continue' +} + +if ( $env:CI -eq $null ) { + throw "Build-Windows.ps1 requires CI environment" +} + +if ( ! ( [System.Environment]::Is64BitOperatingSystem ) ) { + throw "A 64-bit system is required to build the project." +} + +if ( $PSVersionTable.PSVersion -lt '7.2.0' ) { + Write-Warning 'The obs-studio PowerShell build script requires PowerShell Core 7. Install or upgrade your PowerShell version: https://aka.ms/pscore6' + exit 2 +} + +function Build { + trap { + Pop-Location -Stack BuildTemp -ErrorAction 'SilentlyContinue' + Write-Error $_ + Log-Group + exit 2 + } + + $ScriptHome = $PSScriptRoot + $ProjectRoot = Resolve-Path -Path "$PSScriptRoot/../.." + + $UtilityFunctions = Get-ChildItem -Path $PSScriptRoot/utils.pwsh/*.ps1 -Recurse + + foreach($Utility in $UtilityFunctions) { + Write-Debug "Loading $($Utility.FullName)" + . $Utility.FullName + } + + Push-Location -Stack BuildTemp + Ensure-Location $ProjectRoot + + $CmakeArgs = @('--preset', "windows-ci-${Target}") + $CmakeBuildArgs = @('--build') + $CmakeInstallArgs = @() + + if ( $DebugPreference -eq 'Continue' ) { + $CmakeArgs += ('--debug-output') + $CmakeBuildArgs += ('--verbose') + $CmakeInstallArgs += ('--verbose') + } + + $CmakeBuildArgs += @( + '--preset', "windows-${Target}" + '--config', $Configuration + '--parallel' + '--', '/consoleLoggerParameters:Summary', '/noLogo' + ) + + $CmakeInstallArgs += @( + '--install', "build_${Target}" + '--prefix', "${ProjectRoot}/release/${Configuration}" + '--config', $Configuration + ) + + Log-Group "Configuring ${ProductName}..." + Invoke-External cmake @CmakeArgs + + Log-Group "Building ${ProductName}..." + Invoke-External cmake @CmakeBuildArgs + + Log-Group "Installing ${ProductName}..." + Invoke-External cmake @CmakeInstallArgs + + Pop-Location -Stack BuildTemp + Log-Group +} + +Build diff --git a/.github/scripts/build-macos b/.github/scripts/build-macos new file mode 100644 index 0000000..fece23b --- /dev/null +++ b/.github/scripts/build-macos @@ -0,0 +1,153 @@ +#!/usr/bin/env zsh + +builtin emulate -L zsh +setopt EXTENDED_GLOB +setopt PUSHD_SILENT +setopt ERR_EXIT +setopt ERR_RETURN +setopt NO_UNSET +setopt PIPE_FAIL +setopt NO_AUTO_PUSHD +setopt NO_PUSHD_IGNORE_DUPS +setopt FUNCTION_ARGZERO + +## Enable for script debugging +# setopt WARN_CREATE_GLOBAL +# setopt WARN_NESTED_VAR +# setopt XTRACE + +if (( ! ${+CI} )) { + print -u2 -PR "%F{1} ✖︎ ${ZSH_ARGZERO:t:r} requires CI environment.%f" + exit 1 +} + +autoload -Uz is-at-least && if ! is-at-least 5.9; then + print -u2 -PR "${CI:+::error::}%F{1}${funcstack[1]##*/}:%f Running on Zsh version %B${ZSH_VERSION}%b, but Zsh %B5.2%b is the minimum supported version. Upgrade Zsh to fix this issue." + exit 1 +fi + +TRAPZERR() { + print -u2 -PR "::error::%F{1} ✖︎ script execution error%f" + print -PR -e " + Callstack: + ${(j:\n :)funcfiletrace} + " + + exit 2 +} + +build() { + if (( ! ${+SCRIPT_HOME} )) typeset -g SCRIPT_HOME=${ZSH_ARGZERO:A:h} + local host_os='macos' + local project_root=${SCRIPT_HOME:A:h:h} + local buildspec_file=${project_root}/buildspec.json + + fpath=("${SCRIPT_HOME}/utils.zsh" ${fpath}) + autoload -Uz log_group log_info log_error log_output check_macos setup_ccache + + if [[ ! -r ${buildspec_file} ]] { + log_error \ + 'No buildspec.json found. Please create a build specification for your project.' + return 2 + } + + local -i debug=0 + + local config='RelWithDebInfo' + local -r -a _valid_configs=(Debug RelWithDebInfo Release MinSizeRel) + local -i codesign=0 + + local -a args + while (( # )) { + case ${1} { + -c|--config) + if (( # == 1 )) || [[ ${2:0:1} == '-' ]] { + log_error "Missing value for option %B${1}%b" + log_output ${_usage} + exit 2 + } + ;; + } + case ${1} { + --) shift; args+=($@); break ;; + -c|--config) + if (( ! ${_valid_configs[(Ie)${2}]} )) { + log_error "Invalid value %B${2}%b for option %B${1}%b" + exit 2 + } + config=${2} + shift 2 + ;; + -s|--codesign) codesign=1; shift ;; + --debug) debug=1; shift ;; + *) log_error "Unknown option: %B${1}%b"; exit 2 ;; + } + } + + set -- ${(@)args} + + check_macos + + local product_name + local product_version + read -r product_name product_version <<< \ + "$(jq -r '. | {name, version} | join(" ")' ${buildspec_file})" + + pushd ${project_root} + + local -a cmake_args=() + local -a cmake_build_args=(--build) + local -a cmake_install_args=(--install) + + if (( debug )) cmake_args+=(--debug-output) + + cmake_args+=(--preset 'macos-ci') + + typeset -gx NSUnbufferedIO=YES + + typeset -gx CODESIGN_IDENT="${CODESIGN_IDENT:--}" + if (( codesign )) && [[ -z ${CODESIGN_TEAM} ]] { + typeset -gx CODESIGN_TEAM="$(print "${CODESIGN_IDENT}" | /usr/bin/sed -En 's/.+\((.+)\)/\1/p')" + } + + log_group "Configuring ${product_name}..." + cmake -S ${project_root} ${cmake_args} + + log_group "Building ${product_name}..." + run_xcodebuild() { + if (( debug )) { + xcodebuild ${@} + } else { + if [[ ${GITHUB_EVENT_NAME} == push ]] { + xcodebuild ${@} 2>&1 | xcbeautify --renderer terminal + } else { + xcodebuild ${@} 2>&1 | xcbeautify --renderer github-actions + } + } + } + + local -a build_args=( + ONLY_ACTIVE_ARCH=NO + -arch arm64 + -arch x86_64 + -project ${product_name}.xcodeproj + -target ${product_name} + -destination "generic/platform=macOS,name=Any Mac" + -configuration ${config} + -parallelizeTargets + -hideShellScriptEnvironment + build + ) + + pushd build_macos + run_xcodebuild ${build_args} + popd + + log_group "Installing ${product_name}..." + cmake --install build_macos --config ${config} --prefix "${project_root}/release/${config}" + + popd + log_group +} + +build ${@} diff --git a/.github/scripts/build-ubuntu b/.github/scripts/build-ubuntu new file mode 100644 index 0000000..895148d --- /dev/null +++ b/.github/scripts/build-ubuntu @@ -0,0 +1,232 @@ +#!/usr/bin/env zsh + +builtin emulate -L zsh +setopt EXTENDED_GLOB +setopt PUSHD_SILENT +setopt ERR_EXIT +setopt ERR_RETURN +setopt NO_UNSET +setopt PIPE_FAIL +setopt NO_AUTO_PUSHD +setopt NO_PUSHD_IGNORE_DUPS +setopt FUNCTION_ARGZERO + +## Enable for script debugging +# setopt WARN_CREATE_GLOBAL +# setopt WARN_NESTED_VAR +# setopt XTRACE + +autoload -Uz is-at-least && if ! is-at-least 5.2; then + print -u2 -PR "${CI:+::error::}%F{1}${funcstack[1]##*/}:%f Running on Zsh version %B${ZSH_VERSION}%b, but Zsh %B5.2%b is the minimum supported version. Upgrade Zsh to fix this issue." + exit 1 +fi + +TRAPZERR() { + if (( ${_loglevel:-3} > 2 )) { + print -u2 -PR "${CI:+::error::}%F{1} ✖︎ script execution error%f" + print -PR -e " + Callstack: + ${(j:\n :)funcfiletrace} + " + } + + exit 2 +} + +build() { + if (( ! ${+SCRIPT_HOME} )) typeset -g SCRIPT_HOME=${ZSH_ARGZERO:A:h} + local host_os='ubuntu' + local project_root=${SCRIPT_HOME:A:h:h} + local buildspec_file=${project_root}/buildspec.json + + fpath=("${SCRIPT_HOME}/utils.zsh" ${fpath}) + autoload -Uz log_group log_info log_error log_output set_loglevel check_ubuntu setup_ccache + + if [[ ! -r ${buildspec_file} ]] { + log_error \ + 'No buildspec.json found. Please create a build specification for your project.' + return 2 + } + + local -i debug=0 + typeset -g -a skips=() + local -i verbosity=1 + local -r _version='2.0.0' + local -r -a _valid_targets=( + ubuntu-x86_64 + ) + local target + local config='RelWithDebInfo' + local -r -a _valid_configs=(Debug RelWithDebInfo Release MinSizeRel) + local -i codesign=0 + + local -r -a _valid_generators=(Ninja 'Unix Makefiles') + local generator='Ninja' + local -r _usage_host=" +%F{yellow} Additional options for Linux builds%f + ----------------------------------------------------------------------------- + %B--generator%b Specify build system to generate + Available generators: + - Ninja + - Unix Makefiles" + + local -i print_config=0 + local -r _usage=" +Usage: %B${functrace[1]%:*}%b