Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions cmake/macros/rv_stage.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -504,6 +504,12 @@ FUNCTION(rv_stage)
ENDIF()

ADD_DEPENDENCIES(image_formats ${arg_TARGET})
# Track the plugin file so the image formats .gto cache is regenerated when any plugin is relinked
SET_PROPERTY(
TARGET image_formats
APPEND
PROPERTY RV_FORMAT_PLUGIN_FILES "$<TARGET_FILE:${arg_TARGET}>"
)

ADD_SHARED_LIBRARY_LIST(${arg_TARGET})

Expand Down Expand Up @@ -533,6 +539,12 @@ FUNCTION(rv_stage)
ENDIF()

ADD_DEPENDENCIES(movie_formats ${arg_TARGET})
# Track the plugin file so the movie formats .gto cache is regenerated when any plugin is relinked
SET_PROPERTY(
TARGET movie_formats
APPEND
PROPERTY RV_FORMAT_PLUGIN_FILES "$<TARGET_FILE:${arg_TARGET}>"
)

ADD_SHARED_LIBRARY_LIST(${arg_TARGET})

Expand Down
4 changes: 3 additions & 1 deletion packages/rv/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,9 @@ CONFIGURE_FILE(rviorc.mu ${RV_STAGE_SCRIPTS_DIR}/utv/rviorc.mu COPYONLY)
CONFIGURE_FILE(rvrc.py ${RV_STAGE_SCRIPTS_DIR}/utv/rvrc.py COPYONLY)
CONFIGURE_FILE(rvrc.mu ${RV_STAGE_SCRIPTS_DIR}/utv/utvrc.mu COPYONLY)
CONFIGURE_FILE(rvrc.py ${RV_STAGE_SCRIPTS_DIR}/utv/utvrc.py COPYONLY)
IF(NOT RV_USE_SYSTEM_DEPS)
IF(NOT RV_USE_SYSTEM_DEPS
AND NOT RV_TARGET_WINDOWS
)
CONFIGURE_FILE(qt.conf ${RV_STAGE_BIN_DIR}/qt.conf COPYONLY)
ENDIF()

Expand Down
252 changes: 205 additions & 47 deletions scripts/install.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -112,51 +112,55 @@ Write-Host "Target Directory: $InstallDir" -ForegroundColor White
Write-Host "Administrative Privileges: $isAdmin`n" -ForegroundColor White

# Step 1: Check and Install OpenUTVDeps
if (-not $SkipDeps) {
Write-Host "--- Checking OpenUTV Dependencies (v$DepsVersion) ---" -ForegroundColor Cyan
$depsFound = $false
$detectedDepsPath = ""

if ($env:OPENUTV_DEPS_ROOT -and (Test-Path "$env:OPENUTV_DEPS_ROOT\bin\OpenImageIO.dll")) {
$depsFound = $true
$detectedDepsPath = $env:OPENUTV_DEPS_ROOT
} elseif (Test-Path "C:\Program Files\OpenUTVDeps $DepsVersion\bin\OpenImageIO.dll") {
$depsFound = $true
$detectedDepsPath = "C:\Program Files\OpenUTVDeps $DepsVersion"
} elseif (Test-Path "C:\Program Files\OpenUTVDeps*\bin\OpenImageIO.dll") {
$found = Get-Item "C:\Program Files\OpenUTVDeps*\bin\OpenImageIO.dll" | Select-Object -First 1
Write-Host "--- Checking OpenUTV Dependencies (v$DepsVersion) ---" -ForegroundColor Cyan
$depsFound = $false
$detectedDepsPath = ""

if (Test-Path "C:\Program Files\OpenUTVDeps $DepsVersion\bin\OpenImageIO.dll") {
$depsFound = $true
$detectedDepsPath = "C:\Program Files\OpenUTVDeps $DepsVersion"
} elseif ($env:UTV_DEPS_ROOT -and (Test-Path "$env:UTV_DEPS_ROOT\bin\OpenImageIO.dll")) {
$depsFound = $true
$detectedDepsPath = $env:UTV_DEPS_ROOT
} elseif ($env:OPENUTV_DEPS_ROOT -and (Test-Path "$env:OPENUTV_DEPS_ROOT\bin\OpenImageIO.dll")) {
$depsFound = $true
$detectedDepsPath = $env:OPENUTV_DEPS_ROOT
} elseif (Test-Path "C:\Program Files\OpenUTVDeps*\bin\OpenImageIO.dll") {
$found = Get-Item "C:\Program Files\OpenUTVDeps*\bin\OpenImageIO.dll" | Select-Object -First 1
$depsFound = $true
$detectedDepsPath = $found.Directory.Parent.FullName
} else {
$uninst = Get-ItemProperty "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*" -ErrorAction SilentlyContinue |
Where-Object { $_.DisplayName -like "OpenUTVDeps $DepsVersion*" -or $_.DisplayName -like "OpenUTV Dependencies $DepsVersion*" } |
Select-Object -First 1
if ($uninst -and $uninst.InstallLocation -and (Test-Path "$($uninst.InstallLocation)\bin\OpenImageIO.dll")) {
$depsFound = $true
$detectedDepsPath = $found.Directory.Parent.FullName
} else {
$uninst = Get-ItemProperty "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*" -ErrorAction SilentlyContinue |
Where-Object { $_.DisplayName -like "OpenUTVDeps $DepsVersion*" -or $_.DisplayName -like "OpenUTV Dependencies $DepsVersion*" } |
Select-Object -First 1
if ($uninst -and $uninst.InstallLocation -and (Test-Path "$($uninst.InstallLocation)\bin\OpenImageIO.dll")) {
$depsFound = $true
$detectedDepsPath = $uninst.InstallLocation.TrimEnd('\')
}
$detectedDepsPath = $uninst.InstallLocation.TrimEnd('\')
}
}

if ($depsFound) {
Write-Host "OpenUTV dependencies detected at: $detectedDepsPath" -ForegroundColor Green
} else {
Write-Host "OpenUTV dependencies not found. Downloading OpenUTVDeps MSI installer..." -ForegroundColor Yellow
$msiUrl = "https://github.com/$RepoOwner/$DepsRepoName/releases/download/v$DepsVersion/OpenUTVDeps-$DepsVersion-win64.msi"
$tempMsi = Join-Path $env:TEMP "OpenUTVDeps-$DepsVersion-win64.msi"
if ($depsFound) {
Write-Host "OpenUTV dependencies detected at: $detectedDepsPath" -ForegroundColor Green
} elseif (-not $SkipDeps) {
Write-Host "OpenUTV dependencies not found. Downloading OpenUTVDeps MSI installer..." -ForegroundColor Yellow
$msiUrl = "https://github.com/$RepoOwner/$DepsRepoName/releases/download/v$DepsVersion/OpenUTVDeps-$DepsVersion-win64.msi"
$tempMsi = Join-Path $env:TEMP "OpenUTVDeps-$DepsVersion-win64.msi"

Write-Host "Downloading $msiUrl..." -ForegroundColor White
Invoke-WebRequest -Uri $msiUrl -OutFile $tempMsi -UseBasicParsing
Write-Host "Downloading $msiUrl..." -ForegroundColor White
Invoke-WebRequest -Uri $msiUrl -OutFile $tempMsi -UseBasicParsing

Write-Host "Installing OpenUTVDeps (silent MSI install)..." -ForegroundColor Yellow
$msiProc = Start-Process msiexec.exe -ArgumentList "/i `"$tempMsi`" /qn /norestart MSIFASTINSTALL=7" -Wait -PassThru
Remove-Item -Force $tempMsi -ErrorAction SilentlyContinue
Write-Host "Installing OpenUTVDeps (silent MSI install)..." -ForegroundColor Yellow
$msiProc = Start-Process msiexec.exe -ArgumentList "/i `"$tempMsi`" /qn /norestart MSIFASTINSTALL=7" -Wait -PassThru
Remove-Item -Force $tempMsi -ErrorAction SilentlyContinue

if ($msiProc.ExitCode -ne 0 -and $msiProc.ExitCode -ne 3010) {
Write-Error "Failed to install OpenUTVDeps MSI. Exit code: $($msiProc.ExitCode)"
return
}
Write-Host "OpenUTVDeps installed successfully!" -ForegroundColor Green
if ($msiProc.ExitCode -ne 0 -and $msiProc.ExitCode -ne 3010) {
Write-Error "Failed to install OpenUTVDeps MSI. Exit code: $($msiProc.ExitCode)"
return
}
Write-Host "OpenUTVDeps installed successfully!" -ForegroundColor Green
$detectedDepsPath = "C:\Program Files\OpenUTVDeps $DepsVersion"
} else {
Write-Host "Skipping OpenUTVDeps download/install (-SkipDeps)." -ForegroundColor Gray
}

# Step 2: Resolve UTV Release Asset
Expand Down Expand Up @@ -208,20 +212,174 @@ if (-not (Test-Path $utvExe)) {
return
}

# Step 4: Configure PATH
Write-Host "`n--- Configuring Environment ---" -ForegroundColor Cyan
# Step 4: Configure PATH, Isolated CLI Shims, and Environment
Write-Host "`n--- Configuring Environment & Isolated CLI Tools ---" -ForegroundColor Cyan
$binDir = Join-Path $InstallDir "bin"
$pathScope = if ($isAdmin) { "Machine" } else { "User" }

# Remove orphaned legacy qt.conf if present without plugins\Qt (prevents blocking PySide6 Qt plugin loading)
$legacyQtConf = Join-Path $binDir "qt.conf"
$qtPluginDir = Join-Path $InstallDir "plugins\Qt"
if ((Test-Path $legacyQtConf) -and -not (Test-Path $qtPluginDir)) {
Remove-Item -Force $legacyQtConf -ErrorAction SilentlyContinue
Write-Host "Removed legacy qt.conf." -ForegroundColor Gray
}

# Ensure dedicated CLI tools (utvio, utvpkg, py-interp, utvls) have -bin copies and launcher shims
$utvExe = Join-Path $binDir "utv.exe"
$cliTools = @("utvio", "utvpkg", "py-interp", "utvls")
foreach ($tool in $cliTools) {
$toolExe = Join-Path $binDir "$tool.exe"
$toolBin = Join-Path $binDir "$tool-bin.exe"
if ((Test-Path $toolExe) -and -not (Test-Path $toolBin) -and (Test-Path $utvExe)) {
Move-Item -Force -Path $toolExe -Destination $toolBin
Copy-Item -Force -Path $utvExe -Destination $toolExe
Write-Host "Configured hermetic launcher for $tool.exe" -ForegroundColor Gray
}
}

# Deploy companion .cmd scripts for seamless CLI usage without PATH pollution
$cmdShimTemplate = @'
@echo off
setlocal

:: Discover OpenUTVDeps runtime root directory
set "DEPS_ROOT="
if defined UTV_DEPS_ROOT if exist "%UTV_DEPS_ROOT%\bin\OpenImageIO.dll" set "DEPS_ROOT=%UTV_DEPS_ROOT%"
if not defined DEPS_ROOT if defined OPENUTV_DEPS_ROOT if exist "%OPENUTV_DEPS_ROOT%\bin\OpenImageIO.dll" set "DEPS_ROOT=%OPENUTV_DEPS_ROOT%"

if not defined DEPS_ROOT (
for /f "tokens=2*" %%a in ('reg query "HKCU\Environment" /v "UTV_DEPS_ROOT" 2^>nul') do if exist "%%b\bin\OpenImageIO.dll" set "DEPS_ROOT=%%b"
)
if not defined DEPS_ROOT (
for /f "tokens=2*" %%a in ('reg query "HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\Environment" /v "UTV_DEPS_ROOT" 2^>nul') do if exist "%%b\bin\OpenImageIO.dll" set "DEPS_ROOT=%%b"
)
if not defined DEPS_ROOT (
for /f "tokens=2*" %%a in ('reg query "HKCU\Environment" /v "OPENUTV_DEPS_ROOT" 2^>nul') do if exist "%%b\bin\OpenImageIO.dll" set "DEPS_ROOT=%%b"
)
if not defined DEPS_ROOT (
for /f "tokens=2*" %%a in ('reg query "HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\Environment" /v "OPENUTV_DEPS_ROOT" 2^>nul') do if exist "%%b\bin\OpenImageIO.dll" set "DEPS_ROOT=%%b"
)
if not defined DEPS_ROOT (
for /f "tokens=2*" %%a in ('reg query "HKCU\Software\OpenUTV" /v "DepsPath" 2^>nul') do if exist "%%b\bin\OpenImageIO.dll" set "DEPS_ROOT=%%b"
)
if not defined DEPS_ROOT (
for /f "tokens=2*" %%a in ('reg query "HKLM\Software\OpenUTV" /v "DepsPath" 2^>nul') do if exist "%%b\bin\OpenImageIO.dll" set "DEPS_ROOT=%%b"
)
if not defined DEPS_ROOT (
for /d %%d in ("%ProgramFiles%\OpenUTVDeps*") do if exist "%%d\bin\OpenImageIO.dll" set "DEPS_ROOT=%%d"
)
if not defined DEPS_ROOT (
for /d %%d in ("%LOCALAPPDATA%\Programs\OpenUTVDeps*") do if exist "%%d\bin\OpenImageIO.dll" set "DEPS_ROOT=%%d"
)

if not defined DEPS_ROOT (
echo OpenUTV: Could not locate OpenUTVDeps runtime dependencies. >&2
exit /b 1
)

set "APP_DIR=%~dp0"
if "%APP_DIR:~-1%"=="\" set "APP_DIR=%APP_DIR:~0,-1%"

set "PATH=%APP_DIR%;%DEPS_ROOT%\bin;%DEPS_ROOT%\tools\python3\Lib\site-packages\PySide6;%DEPS_ROOT%\tools\python3;%DEPS_ROOT%\tools\python3\Scripts;%PATH%"
set "PYTHONHOME=%DEPS_ROOT%\tools\python3"
set "QT_PLUGIN_PATH=%DEPS_ROOT%\tools\python3\Lib\site-packages\PySide6\plugins"
set "QT_QPA_PLATFORM_PLUGIN_PATH=%DEPS_ROOT%\tools\python3\Lib\site-packages\PySide6\plugins\platforms"
set "UTV_DEPS_ROOT=%DEPS_ROOT%"
set "OPENUTV_DEPS_ROOT=%DEPS_ROOT%"
set "UTV_HOME=%APP_DIR%"
set "OPENUTV_HOME=%APP_DIR%"
'@

# Write openutv-run.cmd
$openutvRunContent = $cmdShimTemplate + "`r`n`r`n%*`r`nexit /b %ERRORLEVEL%`r`n"
Set-Content -Path (Join-Path $binDir "openutv-run.cmd") -Value $openutvRunContent -Encoding ASCII

# Write utvio.cmd, utvpkg.cmd, py-interp.cmd, utvls.cmd
foreach ($tool in $cliTools) {
$dispatch = @"

if exist "%APP_DIR%\$tool-bin.exe" (
"%APP_DIR%\$tool-bin.exe" %*
) else if exist "%APP_DIR%\$tool.exe" (
"%APP_DIR%\$tool.exe" %*
) else (
echo OpenUTV: Could not locate $tool executable. >&2
exit /b 1
)
exit /b %ERRORLEVEL%
"@
Set-Content -Path (Join-Path $binDir "$tool.cmd") -Value ($cmdShimTemplate + $dispatch) -Encoding ASCII
}

# Write openutv-diagnostics.cmd and openutv-check-updates.cmd
$diagDispatch = @"

if exist "%APP_DIR%\py-interp-bin.exe" (
"%APP_DIR%\py-interp-bin.exe" "%APP_DIR%\openutv-diagnostics.py" %*
) else if exist "%APP_DIR%\py-interp.exe" (
"%APP_DIR%\py-interp.exe" "%APP_DIR%\openutv-diagnostics.py" %*
) else if exist "%DEPS_ROOT%\tools\python3\python.exe" (
"%DEPS_ROOT%\tools\python3\python.exe" "%APP_DIR%\openutv-diagnostics.py" %*
) else (
python "%APP_DIR%\openutv-diagnostics.py" %*
)
exit /b %ERRORLEVEL%
"@
Set-Content -Path (Join-Path $binDir "openutv-diagnostics.cmd") -Value ($cmdShimTemplate + $diagDispatch) -Encoding ASCII

$updateDispatch = @"

if exist "%APP_DIR%\py-interp-bin.exe" (
"%APP_DIR%\py-interp-bin.exe" "%APP_DIR%\openutv-check-updates.py" %*
) else if exist "%APP_DIR%\py-interp.exe" (
"%APP_DIR%\py-interp.exe" "%APP_DIR%\openutv-check-updates.py" %*
) else if exist "%DEPS_ROOT%\tools\python3\python.exe" (
"%DEPS_ROOT%\tools\python3\python.exe" "%APP_DIR%\openutv-check-updates.py" %*
) else (
python "%APP_DIR%\openutv-check-updates.py" %*
)
exit /b %ERRORLEVEL%
"@
Set-Content -Path (Join-Path $binDir "openutv-check-updates.cmd") -Value ($cmdShimTemplate + $updateDispatch) -Encoding ASCII

# Configure persistent environment variables
if ($detectedDepsPath -and (Test-Path $detectedDepsPath)) {
[Environment]::SetEnvironmentVariable("UTV_DEPS_ROOT", $detectedDepsPath, $pathScope)
[Environment]::SetEnvironmentVariable("OPENUTV_DEPS_ROOT", $detectedDepsPath, $pathScope)
$env:UTV_DEPS_ROOT = $detectedDepsPath
$env:OPENUTV_DEPS_ROOT = $detectedDepsPath
}
[Environment]::SetEnvironmentVariable("UTV_HOME", $InstallDir, $pathScope)
[Environment]::SetEnvironmentVariable("OPENUTV_HOME", $InstallDir, $pathScope)
$env:UTV_HOME = $InstallDir
$env:OPENUTV_HOME = $InstallDir

# Clean global pollution: remove PYTHONHOME, QT_PLUGIN_PATH, QT_QPA_PLATFORM_PLUGIN_PATH
[Environment]::SetEnvironmentVariable("PYTHONHOME", $null, $pathScope)
[Environment]::SetEnvironmentVariable("QT_PLUGIN_PATH", $null, $pathScope)
[Environment]::SetEnvironmentVariable("QT_QPA_PLATFORM_PLUGIN_PATH", $null, $pathScope)
$env:PYTHONHOME = $null
$env:QT_PLUGIN_PATH = $null
$env:QT_QPA_PLATFORM_PLUGIN_PATH = $null

# Configure PATH: ONLY $binDir, zero pollution from OpenUTVDeps/Scoop/Choco
$currentEnvPath = [Environment]::GetEnvironmentVariable("Path", $pathScope)
if ($currentEnvPath -notlike "*$binDir*") {
$newEnvPath = "$binDir;$currentEnvPath"
[Environment]::SetEnvironmentVariable("Path", $newEnvPath, $pathScope)
$env:Path = "$binDir;$env:Path"
Write-Host "Added $binDir to $pathScope PATH." -ForegroundColor Green
} else {
Write-Host "$binDir is already present in $pathScope PATH." -ForegroundColor Gray
$cleanList = ($currentEnvPath -split ";") | Where-Object {
$_ -ne "" -and
$_ -notlike "*OpenUTVDeps*" -and
$_ -notlike "*openutv-dependencies*" -and
$_ -ne $binDir
}

$newEnvPath = (@($binDir) + $cleanList) -join ";"
[Environment]::SetEnvironmentVariable("Path", $newEnvPath, $pathScope)
$env:Path = (@($binDir) + (($env:Path -split ";") | Where-Object { $_ -notlike "*OpenUTVDeps*" -and $_ -notlike "*openutv-dependencies*" -and $_ -ne $binDir })) -join ";"

Write-Host "Environment configured hermetically (Zero `$PATH pollution)." -ForegroundColor Green
Write-Host " + Added to $pathScope PATH: $binDir" -ForegroundColor Gray
Write-Host " - Cleaned dependency folders and global PYTHONHOME/QT_PLUGIN_PATH from environment." -ForegroundColor Gray

# Step 5: Create Start Menu and Desktop Shortcuts
if (-not $NoShortcuts) {
Write-Host "`n--- Creating Shortcuts ---" -ForegroundColor Cyan
Expand Down
5 changes: 5 additions & 0 deletions src/bin/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,11 @@ CONFIGURE_FILE(${_HELPER_SRC_DIR}/openutv-check-updates.py ${RV_STAGE_BIN_DIR}/o
IF(WIN32)
CONFIGURE_FILE(${_HELPER_SRC_DIR}/openutv-diagnostics.cmd ${RV_STAGE_BIN_DIR}/openutv-diagnostics.cmd COPYONLY)
CONFIGURE_FILE(${_HELPER_SRC_DIR}/openutv-check-updates.cmd ${RV_STAGE_BIN_DIR}/openutv-check-updates.cmd COPYONLY)
CONFIGURE_FILE(${_HELPER_SRC_DIR}/openutv-run.cmd ${RV_STAGE_BIN_DIR}/openutv-run.cmd COPYONLY)
CONFIGURE_FILE(${_HELPER_SRC_DIR}/utvio.cmd ${RV_STAGE_BIN_DIR}/utvio.cmd COPYONLY)
CONFIGURE_FILE(${_HELPER_SRC_DIR}/utvpkg.cmd ${RV_STAGE_BIN_DIR}/utvpkg.cmd COPYONLY)
CONFIGURE_FILE(${_HELPER_SRC_DIR}/py-interp.cmd ${RV_STAGE_BIN_DIR}/py-interp.cmd COPYONLY)
CONFIGURE_FILE(${_HELPER_SRC_DIR}/utvls.cmd ${RV_STAGE_BIN_DIR}/utvls.cmd COPYONLY)
ELSE()
CONFIGURE_FILE(${_HELPER_SRC_DIR}/openutv-diagnostics.py ${RV_STAGE_BIN_DIR}/openutv-diagnostics COPYONLY)
CONFIGURE_FILE(${_HELPER_SRC_DIR}/openutv-check-updates.py ${RV_STAGE_BIN_DIR}/openutv-check-updates COPYONLY)
Expand Down
Loading
Loading