From 6aacb568fc42e4bd8c7120f57176b3526c256735 Mon Sep 17 00:00:00 2001 From: line0 Date: Fri, 24 Jul 2026 14:36:42 +0200 Subject: [PATCH 1/6] Stop bundling modules DependencyControl now manages Yutils, luajson and the ffi-experiments libraries were shipped alongside DependencyControl because nothing else could install them. That is no longer the case: Yutils has its own feed, and DependencyControl ships equivalents of json, BadMutex, PreciseTimer and DownloadManager that it offers under those module names, so it pulls each of them in on demand. Dropping ffi-experiments also removes meson and MoonScript from the installer build, which only existed to compile those three libraries. DependencyControl itself is still bundled, as the bootstrap, and moves from v0.6.3-alpha to v0.8.0. It now comes from its release bundle instead of a clone: the repository arranges its sources for its own tooling, and since v0.7.0 no longer in the layout the installer copied out of it, while the bundle already carries Aegisub's automation directory layout. That also drops the stale DepUnit directory entries, which named a path DependencyControl hasn't used in years and the bundle now creates, along with the DepSqlite and DepLifecycle ones for features that never shipped. Copies installed by earlier versions are left in place. Lua resolves them before DependencyControl's own module search, so they keep shadowing the managed copies, but removing them would break scripts that use these modules directly without DependencyControl. The removal is available behind the CLEANUP_UNBUNDLED_MODULES define, pending a decision on whether such scripts still exist. Co-Authored-By: Claude Opus 4.8 (1M context) --- .../win_installer/fragment_automation.iss | 43 ++++++++++--------- .../win_installer/fragment_mainprogram.iss | 2 - .../portable/create-portable.ps1 | 18 +++----- tools/win-installer-setup.ps1 | 38 ++++++---------- 4 files changed, 41 insertions(+), 60 deletions(-) diff --git a/packages/win_installer/fragment_automation.iss b/packages/win_installer/fragment_automation.iss index e5dee92054..660473d92f 100644 --- a/packages/win_installer/fragment_automation.iss +++ b/packages/win_installer/fragment_automation.iss @@ -32,27 +32,12 @@ DestDir: {app}\automation\include; Source: {#SOURCE_ROOT}\automation\include\uti DestDir: {app}\automation\include; Source: {#SOURCE_ROOT}\automation\include\utils-auto4.lua; Flags: ignoreversion overwritereadonly uninsremovereadonly; Attribs: readonly; Components: main #ifdef DEPCTRL -; DepCtrl -DestDir: {userappdata}\Aegisub\automation\include\l0; Source: {#DEPS_DIR}\DependencyControl\modules\*; Flags: ignoreversion recursesubdirs createallsubdirs; Components: macros\modules\depctrl -DestDir: {userappdata}\Aegisub\automation\autoload; Source: {#DEPS_DIR}\DependencyControl\macros\*; Flags: ignoreversion recursesubdirs createallsubdirs; Components: macros\modules\depctrl -DestDir: {userappdata}\Aegisub\automation\include; Source: {#DEPS_DIR}\Yutils\src\Yutils.lua; Flags: ignoreversion; Components: macros\modules\yutils -DestDir: {userappdata}\Aegisub\automation\include; Source: {#DEPS_DIR}\luajson\lua\*; Flags: ignoreversion recursesubdirs createallsubdirs; Components: macros\modules\luajson - -DestDir: {userappdata}\Aegisub\automation\include\requireffi; Source: {#DEPS_DIR}\ffi-experiments\build\requireffi\requireffi.lua; Flags: ignoreversion recursesubdirs createallsubdirs; Components: macros\modules\depctrl -DestDir: {userappdata}\Aegisub\automation\include\BM\BadMutex; Source: {#DEPS_DIR}\ffi-experiments\build\bad-mutex\BadMutex.dll; Flags: ignoreversion recursesubdirs createallsubdirs; Components: macros\modules\depctrl -DestDir: {userappdata}\Aegisub\automation\include\BM; Source: {#DEPS_DIR}\ffi-experiments\build\bad-mutex\BadMutex.lua; Flags: ignoreversion recursesubdirs createallsubdirs; Components: macros\modules\depctrl -DestDir: {userappdata}\Aegisub\automation\include\PT\PreciseTimer; Source: {#DEPS_DIR}\ffi-experiments\build\precise-timer\PreciseTimer.dll; Flags: ignoreversion recursesubdirs createallsubdirs; Components: macros\modules\depctrl -DestDir: {userappdata}\Aegisub\automation\include\PT; Source: {#DEPS_DIR}\ffi-experiments\build\precise-timer\PreciseTimer.lua; Flags: ignoreversion recursesubdirs createallsubdirs; Components: macros\modules\depctrl -DestDir: {userappdata}\Aegisub\automation\include\DM\DownloadManager; Source: {#DEPS_DIR}\ffi-experiments\build\download-manager\DownloadManager.dll; Flags: ignoreversion recursesubdirs createallsubdirs; Components: macros\modules\depctrl -DestDir: {userappdata}\Aegisub\automation\include\DM; Source: {#DEPS_DIR}\ffi-experiments\build\download-manager\DownloadManager.lua; Flags: ignoreversion recursesubdirs createallsubdirs; Components: macros\modules\depctrl - -[Dirs] -Name: {userappdata}\Aegisub\automation\test\DepUnit\automation; Components: macros\modules\depctrl; -Name: {userappdata}\Aegisub\automation\test\DepUnit\modules; Components: macros\modules\depctrl; -Name: {userappdata}\Aegisub\automation\schema\DepSqlite\automation; Components: macros\modules\depctrl; -Name: {userappdata}\Aegisub\automation\schema\DepSqlite\modules; Components: macros\modules\depctrl; -Name: {userappdata}\Aegisub\automation\lifecycle\DepLifecycle\automation; Components: macros\modules\depctrl; -Name: {userappdata}\Aegisub\automation\lifecycle\DepLifecycle\modules; Components: macros\modules\depctrl; +; DepCtrl's release bundle already has the files arranged for Aegisub's automation directory layout. +; +; Yutils, luajson and the ffi-experiments libraries are no longer bundled. DependencyControl +; installs Yutils from its own feed and ships internal replacements for json, BadMutex, PreciseTimer and +; DownloadManager. +DestDir: {userappdata}\Aegisub\automation; Source: {#DEPS_DIR}\DependencyControl\automation\*; Flags: ignoreversion recursesubdirs createallsubdirs; Components: macros\modules\depctrl #endif [InstallDelete] @@ -64,3 +49,19 @@ Type: files; Name: "{userappdata}\Aegisub\ASSWipe.json" Type: files; Name: "{userappdata}\Aegisub\automation\include\DM\DownloadManager.dll" Type: files; Name: "{userappdata}\Aegisub\automation\include\BM\BadMutex.dll" Type: files; Name: "{userappdata}\Aegisub\automation\include\PT\PreciseTimer.dll" + +#ifdef CLEANUP_UNBUNDLED_MODULES +; Remove the module copies earlier versions bundled, so the DependencyControl-managed ones take +; over. Lua resolves these paths before DependencyControl's own module search, so left in place +; they keep shadowing the managed copies and never migrate. +; +; Opt-in, because it also removes them from scripts that use these modules directly without +; DependencyControl and thus cannot reach the replacements. +Type: files; Name: "{userappdata}\Aegisub\automation\include\Yutils.lua" +Type: files; Name: "{userappdata}\Aegisub\automation\include\json.lua" +Type: filesandordirs; Name: "{userappdata}\Aegisub\automation\include\json" +Type: filesandordirs; Name: "{userappdata}\Aegisub\automation\include\requireffi" +Type: filesandordirs; Name: "{userappdata}\Aegisub\automation\include\BM" +Type: filesandordirs; Name: "{userappdata}\Aegisub\automation\include\PT" +Type: filesandordirs; Name: "{userappdata}\Aegisub\automation\include\DM" +#endif diff --git a/packages/win_installer/fragment_mainprogram.iss b/packages/win_installer/fragment_mainprogram.iss index e01ee4a20a..07afffba4e 100644 --- a/packages/win_installer/fragment_mainprogram.iss +++ b/packages/win_installer/fragment_mainprogram.iss @@ -12,8 +12,6 @@ Name: "macros\demos"; Description: "Example macros/Demos"; Types: full basic #ifdef DEPCTRL Name: "macros\modules"; Description: "Modules"; Types: full Name: "macros\modules\depctrl"; Description: "DependencyControl"; Types: full -Name: "macros\modules\yutils"; Description: "YUtils"; Types: full -Name: "macros\modules\luajson"; Description: "LuaJSON"; Types: full #endif Name: "dictionaries"; Description: "Spellcheck Dictionaries"; Types: full basic Name: "dictionaries\en_US"; Description: "English (US)"; Types: full basic diff --git a/packages/win_installer/portable/create-portable.ps1 b/packages/win_installer/portable/create-portable.ps1 index 387fb1aa57..a5a131c5b0 100644 --- a/packages/win_installer/portable/create-portable.ps1 +++ b/packages/win_installer/portable/create-portable.ps1 @@ -67,18 +67,12 @@ Copy-New-Item $InstallerDepsDir\VC_redist\VC_redist.x64.exe $PortableOutputDir\M Write-Output 'Copying - automation' Copy-New-Items "$InstallerDir\share\aegisub\automation\*" "$PortableOutputDir\automation\" -Recurse Write-Output 'Copying - automation\DEPCTRL' -Copy-New-Items "$InstallerDepsDir\DependencyControl\modules\*" "$PortableOutputDir\automation\include\l0\" -Recurse -Copy-New-Items "$InstallerDepsDir\DependencyControl\macros\*" "$PortableOutputDir\automation\autoload\" -Recurse -Copy-New-Item $InstallerDepsDir\Yutils\src\Yutils.lua $PortableOutputDir\automation\include -Copy-New-Items "$InstallerDepsDir\luajson\lua\*" "$PortableOutputDir\automation\include\" -Recurse - -Copy-New-Item $InstallerDepsDir\ffi-experiments\build\requireffi\requireffi.lua $PortableOutputDir\automation\include\requireffi -Copy-New-Item $InstallerDepsDir\ffi-experiments\build\bad-mutex\BadMutex.dll $PortableOutputDir\automation\include\BM\BadMutex -Copy-New-Item $InstallerDepsDir\ffi-experiments\build\bad-mutex\BadMutex.lua $PortableOutputDir\automation\include\BM -Copy-New-Item $InstallerDepsDir\ffi-experiments\build\precise-timer\PreciseTimer.dll $PortableOutputDir\automation\include\PT\PreciseTimer -Copy-New-Item $InstallerDepsDir\ffi-experiments\build\precise-timer\PreciseTimer.lua $PortableOutputDir\automation\include\PT -Copy-New-Item $InstallerDepsDir\ffi-experiments\build\download-manager\DownloadManager.dll $PortableOutputDir\automation\include\DM\DownloadManager -Copy-New-Item $InstallerDepsDir\ffi-experiments\build\download-manager\DownloadManager.lua $PortableOutputDir\automation\include\DM + +# DepCtrl's release bundle already has the files arranged for Aegisub's automation directory layout. +# Yutils, luajson and the ffi-experiments libraries are no longer bundled. DependencyControl +# installs Yutils from its own feed and ships internal replacements for json, BadMutex, PreciseTimer and +# DownloadManager. +Copy-New-Items "$InstallerDepsDir\DependencyControl\automation\*" "$PortableOutputDir\automation\" -Recurse Write-Output 'Copying - portable-config' Copy-New-Item $SourceRoot\packages\win_installer\portable\config.json $PortableOutputDir diff --git a/tools/win-installer-setup.ps1 b/tools/win-installer-setup.ps1 index 85b1f6cd8f..4461face20 100644 --- a/tools/win-installer-setup.ps1 +++ b/tools/win-installer-setup.ps1 @@ -23,24 +23,24 @@ if (Test-Path 'Env:GITHUB_TOKEN') { $GitHeaders = @{ 'Authorization' = 'Bearer ' + $Env:GITHUB_TOKEN } } +# Yutils, luajson and the ffi-experiments libraries are no longer fetched: DependencyControl +# installs Yutils from its own feed and ships equivalents of json, BadMutex, PreciseTimer and +# DownloadManager, so it pulls each of them in on demand. + # DepCtrl +# Taken from the release bundle rather than a clone: the repository arranges its sources for its own +# tooling, while the bundle already carries Aegisub's automation directory layout. +$DepCtrlVersion = "v0.8.0" if (!(Test-Path DependencyControl)) { - git clone https://github.com/TypesettingTools/DependencyControl.git - Set-Location DependencyControl - git checkout v0.6.3-alpha + $depCtrlDir = New-Item -ItemType Directory DependencyControl + Set-Location $depCtrlDir + $depCtrlUrl = "https://github.com/TypesettingTools/DependencyControl/releases/download/$DepCtrlVersion/DependencyControl-$DepCtrlVersion.zip" + Invoke-WebRequest $depCtrlUrl -OutFile DependencyControl.zip -UseBasicParsing + 7z x DependencyControl.zip + Remove-Item DependencyControl.zip Set-Location $DepsDir } -# YUtils -if (!(Test-Path YUtils)) { - git clone https://github.com/TypesettingTools/YUtils.git -} - -# luajson -if (!(Test-Path luajson)) { - git clone https://github.com/harningt/luajson.git -} - # Avisynth # if (!(Test-Path AviSynthPlus64)) { # $avsReleases = Invoke-WebRequest "https://api.github.com/repos/AviSynth/AviSynthPlus/releases/latest" -Headers $GitHeaders -UseBasicParsing | ConvertFrom-Json @@ -63,18 +63,6 @@ if (!(Test-Path VSFilter)) { Set-Location $DepsDir } -# ffi-experiments -if (!(Test-Path ffi-experiments)) { - Get-Command "moonc" # check to ensure Moonscript is present - git clone https://github.com/TypesettingTools/ffi-experiments.git - Set-Location ffi-experiments - meson build -Ddefault_library=static - if(!$?) { Exit $LASTEXITCODE } - meson compile -C build - if(!$?) { Exit $LASTEXITCODE } - Set-Location $DepsDir -} - # VC++ redistributable if (!(Test-Path VC_redist)) { $redistDir = New-Item -ItemType Directory VC_redist From fa49aa1ede81c50828d165af2acd1ea1e2c8d7be Mon Sep 17 00:00:00 2001 From: line0 Date: Fri, 24 Jul 2026 20:54:06 +0200 Subject: [PATCH 2/6] Harden and clean up the Windows portable packaging script - Make the BuildRoot/SourceRoot args mandatory and fail fast (stop on error, check meson install) - Build the zip via System.IO.Compression instead of requiring 7z in path - Use absolute paths instead switching CWD without reliably restoring it - Merge the copy helpers into one function with an approved verb name - Fix the automation copy collision - prettify progress logging --- .../portable/create-portable.ps1 | 134 ++++++++++-------- 1 file changed, 76 insertions(+), 58 deletions(-) diff --git a/packages/win_installer/portable/create-portable.ps1 b/packages/win_installer/portable/create-portable.ps1 index a5a131c5b0..c92b1c6f55 100644 --- a/packages/win_installer/portable/create-portable.ps1 +++ b/packages/win_installer/portable/create-portable.ps1 @@ -1,83 +1,101 @@ #!/usr/bin/env powershell param ( - [Parameter(Position = 0)] + [Parameter(Position = 0, Mandatory = $true)] + [ValidateNotNullOrEmpty()] [string]$BuildRoot, - [Parameter(Position = 1)] + [Parameter(Position = 1, Mandatory = $true)] + [ValidateNotNullOrEmpty()] [string]$SourceRoot ) -function Copy-New-Item { - $SourceFilePath = $args[0] - $DestinationFilePath = $args[1] - - If (-not (Test-Path $DestinationFilePath)) { - New-Item -ItemType Directory -Path $DestinationFilePath -Force - } - Copy-Item -Path $SourceFilePath -Destination $DestinationFilePath -} +$ErrorActionPreference = 'Stop' -function Copy-New-Items { - $SourceFilePath = $args[0] - $DestinationFilePath = $args[1] - - If (-not (Test-Path $DestinationFilePath)) { - New-Item -ItemType Directory -Path $DestinationFilePath -Force - } - Copy-Item -Path $SourceFilePath -Destination $DestinationFilePath -Recurse +function Copy-ToDirectory { + param( + [Parameter(Mandatory)][string]$Path, + [Parameter(Mandatory)][string]$Destination, + [switch]$Recurse + ) + New-Item -ItemType Directory -Path $Destination -Force | Out-Null + Copy-Item -Path $Path -Destination $Destination -Recurse:$Recurse -Force } +# Keep in sync with the number of Write-Step calls below. +$script:stepNum = 0 +$script:stepTotal = 11 + +# Report progress both via an interactive bar and a textual trail for CI logs. +function Write-Step { + param([Parameter(Mandatory)][string]$Status) + $script:stepNum++ + Write-Progress -Activity 'Creating portable Aegisub' -Status $Status -PercentComplete (100 * $script:stepNum / $script:stepTotal) + Write-Host "[$script:stepNum/$script:stepTotal] $Status" +} -Write-Output BUILD_ROOT=$BuildRoot -Write-Output SOURCE_ROOT=$SourceRoot +Write-Host "BUILD_ROOT=$BuildRoot" +Write-Host "SOURCE_ROOT=$SourceRoot" $InstallerDir = Join-Path $BuildRoot "install" $InstallerDepsDir = Join-Path $BuildRoot "installer-deps" $PortableOutputDir = Join-Path $BuildRoot "aegisub-portable" +$PortableZipPath = Join-Path $BuildRoot "aegisub-portable-64.zip" +Write-Step 'Removing previous output' +Remove-Item -LiteralPath $PortableOutputDir -Force -Recurse -ErrorAction SilentlyContinue +Remove-Item -LiteralPath $InstallerDir -Force -Recurse -ErrorAction SilentlyContinue -Write-Output Goto building dir -Set-Location $BuildRoot - +Write-Step 'Installing build output' +meson install -C $BuildRoot --no-rebuild --destdir $InstallerDir +if ($LASTEXITCODE -ne 0) { throw "meson install failed (exit $LASTEXITCODE)" } -Write-Output 'Removing old temp dir' -Remove-Item -LiteralPath "$PortableOutputDir" -Force -Recurse -Remove-Item -LiteralPath "install" -Force -Recurse +Write-Step 'Copying executable' +Copy-ToDirectory $InstallerDir\bin\aegisub.exe $PortableOutputDir +Write-Step 'Copying translations' +Copy-ToDirectory "$InstallerDir\share\locale\*" "$PortableOutputDir\locale" -Recurse -Write-Output 'Make install' -meson install --no-rebuild --destdir $InstallerDir -Write-Output 'Gathering files' -Copy-New-Item $InstallerDir\bin\aegisub.exe $PortableOutputDir +Write-Step 'Copying dictionaries' +Copy-ToDirectory $InstallerDepsDir\dictionaries\en_US.aff $PortableOutputDir\dictionaries +Copy-ToDirectory $InstallerDepsDir\dictionaries\en_US.dic $PortableOutputDir\dictionaries -Write-Output 'Copying - translations' -Copy-New-Items "$InstallerDir\share\locale\*" "$PortableOutputDir\locale" -Recurse -Write-Output 'Copying - dictionaries' -Copy-New-Item $InstallerDepsDir\dictionaries\en_US.aff $PortableOutputDir\dictionaries -Copy-New-Item $InstallerDepsDir\dictionaries\en_US.dic $PortableOutputDir\dictionaries -Write-Output 'Copying - codecs' -# Write-Output 'Copying - codecs\Avisynth' -# Copy-New-Item $InstallerDepsDir\AvisynthPlus64\x64\Output\system\DevIL.dll $PortableOutputDir -# Copy-New-Item $InstallerDepsDir\AvisynthPlus64\x64\Output\AviSynth.dll $PortableOutputDir -# Copy-New-Item $InstallerDepsDir\AvisynthPlus64\x64\Output\plugins\DirectShowSource.dll $PortableOutputDir -Write-Output 'Copying - codecs\VSFilter' -Copy-New-Item $InstallerDepsDir\VSFilter\x64\VSFilter.dll $PortableOutputDir\csri -Write-Output 'Copying - runtimes\MS-CRT' -Copy-New-Item $InstallerDepsDir\VC_redist\VC_redist.x64.exe $PortableOutputDir\Microsoft.CRT +# Write-Step 'AviSynth' +# Copy-ToDirectory $InstallerDepsDir\AvisynthPlus64\x64\Output\system\DevIL.dll $PortableOutputDir +# Copy-ToDirectory $InstallerDepsDir\AvisynthPlus64\x64\Output\AviSynth.dll $PortableOutputDir +# Copy-ToDirectory $InstallerDepsDir\AvisynthPlus64\x64\Output\plugins\DirectShowSource.dll $PortableOutputDir -Write-Output 'Copying - automation' -Copy-New-Items "$InstallerDir\share\aegisub\automation\*" "$PortableOutputDir\automation\" -Recurse -Write-Output 'Copying - automation\DEPCTRL' +Write-Step 'Copying VSFilter' +Copy-ToDirectory $InstallerDepsDir\VSFilter\x64\VSFilter.dll $PortableOutputDir\csri -# DepCtrl's release bundle already has the files arranged for Aegisub's automation directory layout. -# Yutils, luajson and the ffi-experiments libraries are no longer bundled. DependencyControl -# installs Yutils from its own feed and ships internal replacements for json, BadMutex, PreciseTimer and -# DownloadManager. -Copy-New-Items "$InstallerDepsDir\DependencyControl\automation\*" "$PortableOutputDir\automation\" -Recurse +Write-Step 'Copying VC++ runtime' +Copy-ToDirectory $InstallerDepsDir\VC_redist\VC_redist.x64.exe $PortableOutputDir\Microsoft.CRT -Write-Output 'Copying - portable-config' -Copy-New-Item $SourceRoot\packages\win_installer\portable\config.json $PortableOutputDir +Write-Step 'Copying automation' +Copy-ToDirectory "$InstallerDir\share\aegisub\automation\*" "$PortableOutputDir\automation\" -Recurse +Write-Step 'Copying DependencyControl' +# DepCtrl's release bundle already has the files arranged for Aegisub's automation directory layout. +Copy-ToDirectory "$InstallerDepsDir\DependencyControl\automation\*" "$PortableOutputDir\automation\" -Recurse + +Write-Step 'Copying portable config' +Copy-ToDirectory $SourceRoot\packages\win_installer\portable\config.json $PortableOutputDir + +Write-Step 'Creating portable zip' +Remove-Item -LiteralPath $PortableZipPath -Force -ErrorAction SilentlyContinue + +# Build the zip in a way that avoids some PowerShell versions emitting backslashes in the entry names. +Add-Type -AssemblyName System.IO.Compression.FileSystem +$zipRoot = Split-Path $PortableOutputDir -Leaf +$baseLen = $PortableOutputDir.Length + 1 +$zip = [System.IO.Compression.ZipFile]::Open($PortableZipPath, 'Create') +try { + foreach ($file in Get-ChildItem -LiteralPath $PortableOutputDir -Recurse -File) { + $entryName = "$zipRoot/" + $file.FullName.Substring($baseLen).Replace('\', '/') + [void][System.IO.Compression.ZipFileExtensions]::CreateEntryFromFile($zip, $file.FullName, $entryName, [System.IO.Compression.CompressionLevel]::Optimal) + } +} +finally { + $zip.Dispose() +} -Write-Output 'Creating portable zip' -Remove-Item aegisub-portable-64.zip -7z a aegisub-portable-64.zip aegisub-portable\ +Write-Progress -Activity 'Creating portable Aegisub' -Completed +Write-Host "Done: $PortableZipPath" From cfbfde1bcd08a9fc1cd165692a87341559a07400 Mon Sep 17 00:00:00 2001 From: line0 Date: Sun, 26 Jul 2026 22:46:06 +0200 Subject: [PATCH 3/6] Harden and clean up the Windows installer setup script - Make BuildRoot/SourceRoot mandatory - Drop Set-Location; use absolute paths throughout (7z -o, meson -C) - Collapse the InnoSetup language downloads into a loop - Bump bundled DependencyControl to v0.8.1 --- tools/win-installer-setup.ps1 | 97 ++++++++++++++++++----------------- 1 file changed, 50 insertions(+), 47 deletions(-) diff --git a/tools/win-installer-setup.ps1 b/tools/win-installer-setup.ps1 index 4461face20..63c1caa023 100644 --- a/tools/win-installer-setup.ps1 +++ b/tools/win-installer-setup.ps1 @@ -1,23 +1,23 @@ #!/usr/bin/env powershell param ( - [Parameter(Position = 0)] + [Parameter(Position = 0, Mandatory = $true)] + [ValidateNotNullOrEmpty()] [string]$BuildRoot, - [Parameter(Position = 1)] + [Parameter(Position = 1, Mandatory = $true)] + [ValidateNotNullOrEmpty()] [string]$SourceRoot ) $InstallerDir = Join-Path $SourceRoot "packages\win_installer" | Resolve-Path $DepsDir = Join-Path $BuildRoot "installer-deps" if (!(Test-Path $DepsDir)) { - New-Item -ItemType Directory -Path $DepsDir + New-Item -ItemType Directory -Path $DepsDir | Out-Null } $Env:BUILD_ROOT = $BuildRoot $Env:SOURCE_ROOT = $SourceRoot -Set-Location $DepsDir - $GitHeaders = @{} if (Test-Path 'Env:GITHUB_TOKEN') { $GitHeaders = @{ 'Authorization' = 'Bearer ' + $Env:GITHUB_TOKEN } @@ -27,71 +27,74 @@ if (Test-Path 'Env:GITHUB_TOKEN') { # installs Yutils from its own feed and ships equivalents of json, BadMutex, PreciseTimer and # DownloadManager, so it pulls each of them in on demand. -# DepCtrl -# Taken from the release bundle rather than a clone: the repository arranges its sources for its own -# tooling, while the bundle already carries Aegisub's automation directory layout. -$DepCtrlVersion = "v0.8.0" -if (!(Test-Path DependencyControl)) { - $depCtrlDir = New-Item -ItemType Directory DependencyControl - Set-Location $depCtrlDir +# DependencyControl +# Unlike a git clone, DepCtrl's release bundle already has the files arranged for Aegisub's automation directory layout. +$DepCtrlVersion = "v0.8.1" +$DepCtrlDir = Join-Path $DepsDir "DependencyControl" +if (!(Test-Path $DepCtrlDir)) { + New-Item -ItemType Directory -Path $DepCtrlDir | Out-Null $depCtrlUrl = "https://github.com/TypesettingTools/DependencyControl/releases/download/$DepCtrlVersion/DependencyControl-$DepCtrlVersion.zip" - Invoke-WebRequest $depCtrlUrl -OutFile DependencyControl.zip -UseBasicParsing - 7z x DependencyControl.zip - Remove-Item DependencyControl.zip - Set-Location $DepsDir + $depCtrlZip = Join-Path $DepCtrlDir "DependencyControl.zip" + Invoke-WebRequest $depCtrlUrl -OutFile $depCtrlZip -UseBasicParsing + 7z x $depCtrlZip "-o$DepCtrlDir" + Remove-Item $depCtrlZip } # Avisynth -# if (!(Test-Path AviSynthPlus64)) { +# $AviSynthDir = Join-Path $DepsDir "AviSynthPlus64" +# if (!(Test-Path $AviSynthDir)) { # $avsReleases = Invoke-WebRequest "https://api.github.com/repos/AviSynth/AviSynthPlus/releases/latest" -Headers $GitHeaders -UseBasicParsing | ConvertFrom-Json # $avsUrl = $avsReleases.assets[0].browser_download_url -# Invoke-WebRequest $avsUrl -OutFile AviSynthPlus.7z -UseBasicParsing -# 7z x AviSynthPlus.7z -# Rename-Item (Get-ChildItem -Filter "AviSynthPlus_*" -Directory) AviSynthPlus64 -# Remove-Item AviSynthPlus.7z +# $avsArchive = Join-Path $DepsDir "AviSynthPlus.7z" +# Invoke-WebRequest $avsUrl -OutFile $avsArchive -UseBasicParsing +# 7z x $avsArchive "-o$DepsDir" +# Rename-Item (Join-Path $DepsDir (Get-ChildItem -Path $DepsDir -Filter "AviSynthPlus_*" -Directory).Name) $AviSynthDir +# Remove-Item $avsArchive # } # VSFilter -if (!(Test-Path VSFilter)) { - $vsFilterDir = New-Item -ItemType Directory VSFilter - Set-Location $vsFilterDir +$VSFilterDir = Join-Path $DepsDir "VSFilter" +if (!(Test-Path $VSFilterDir)) { + New-Item -ItemType Directory -Path $VSFilterDir | Out-Null $vsFilterReleases = Invoke-WebRequest "https://api.github.com/repos/pinterf/xy-VSFilter/releases/latest" -Headers $GitHeaders -UseBasicParsing | ConvertFrom-Json $vsFilterUrl = $vsFilterReleases.assets[0].browser_download_url - Invoke-WebRequest $vsFilterUrl -OutFile VSFilter.7z -UseBasicParsing - 7z x VSFilter.7z - Remove-Item VSFilter.7z - Set-Location $DepsDir + $vsFilterArchive = Join-Path $VSFilterDir "VSFilter.7z" + Invoke-WebRequest $vsFilterUrl -OutFile $vsFilterArchive -UseBasicParsing + 7z x $vsFilterArchive "-o$VSFilterDir" + Remove-Item $vsFilterArchive } # VC++ redistributable -if (!(Test-Path VC_redist)) { - $redistDir = New-Item -ItemType Directory VC_redist - Invoke-WebRequest https://aka.ms/vs/17/release/VC_redist.x64.exe -OutFile "$redistDir\VC_redist.x64.exe" -UseBasicParsing +$RedistDir = Join-Path $DepsDir "VC_redist" +if (!(Test-Path $RedistDir)) { + New-Item -ItemType Directory -Path $RedistDir | Out-Null + Invoke-WebRequest https://aka.ms/vs/17/release/VC_redist.x64.exe -OutFile (Join-Path $RedistDir "VC_redist.x64.exe") -UseBasicParsing } # Dictionaries -if (!(Test-Path dictionaries)) { - New-Item -ItemType Directory dictionaries - Invoke-WebRequest https://raw.githubusercontent.com/TypesettingTools/Aegisub-dictionaries/master/dicts/en_US.aff -OutFile dictionaries/en_US.aff -UseBasicParsing - Invoke-WebRequest https://raw.githubusercontent.com/TypesettingTools/Aegisub-dictionaries/master/dicts/en_US.dic -OutFile dictionaries/en_US.dic -UseBasicParsing +$DictionariesDir = Join-Path $DepsDir "dictionaries" +if (!(Test-Path $DictionariesDir)) { + New-Item -ItemType Directory -Path $DictionariesDir | Out-Null + Invoke-WebRequest https://raw.githubusercontent.com/TypesettingTools/Aegisub-dictionaries/master/dicts/en_US.aff -OutFile (Join-Path $DictionariesDir "en_US.aff") -UseBasicParsing + Invoke-WebRequest https://raw.githubusercontent.com/TypesettingTools/Aegisub-dictionaries/master/dicts/en_US.dic -OutFile (Join-Path $DictionariesDir "en_US.dic") -UseBasicParsing } # Installer localization -if (!(Test-Path innosetup-langs)) { - New-Item -ItemType Directory innosetup-langs - Invoke-WebRequest https://raw.github.com/jrsoftware/issrc/is-6_7_3/Files/Languages/Unofficial/Greek.isl -OutFile innosetup-langs/Greek.isl -UseBasicParsing - Invoke-WebRequest https://raw.github.com/jrsoftware/issrc/is-6_7_3/Files/Languages/Unofficial/Basque.isl -OutFile innosetup-langs/Basque.isl -UseBasicParsing - Invoke-WebRequest https://raw.github.com/jrsoftware/issrc/is-6_7_3/Files/Languages/Unofficial/Galician.isl -OutFile innosetup-langs/Galician.isl -UseBasicParsing - Invoke-WebRequest https://raw.github.com/jrsoftware/issrc/is-6_7_3/Files/Languages/Unofficial/Indonesian.isl -OutFile innosetup-langs/Indonesian.isl -UseBasicParsing - Invoke-WebRequest https://raw.github.com/jrsoftware/issrc/is-6_7_3/Files/Languages/Unofficial/SerbianCyrillic.isl -OutFile innosetup-langs/SerbianCyrillic.isl -UseBasicParsing - Invoke-WebRequest https://raw.github.com/jrsoftware/issrc/is-6_7_3/Files/Languages/Unofficial/SerbianLatin.isl -OutFile innosetup-langs/SerbianLatin.isl -UseBasicParsing - Invoke-WebRequest https://raw.github.com/jrsoftware/issrc/is-6_7_3/Files/Languages/Unofficial/ChineseSimplified.isl -OutFile innosetup-langs/ChineseSimplified.isl -UseBasicParsing - Invoke-WebRequest https://raw.github.com/jrsoftware/issrc/is-6_7_3/Files/Languages/Unofficial/ChineseTraditional.isl -OutFile innosetup-langs/ChineseTraditional.isl -UseBasicParsing +$LangsDir = Join-Path $DepsDir "innosetup-langs" +if (!(Test-Path $LangsDir)) { + New-Item -ItemType Directory -Path $LangsDir | Out-Null + $LangBaseUrl = "https://raw.github.com/jrsoftware/issrc/is-6_7_3/Files/Languages/Unofficial" + $Languages = @( + 'Greek', 'Basque', 'Galician', 'Indonesian', + 'SerbianCyrillic', 'SerbianLatin', 'ChineseSimplified', 'ChineseTraditional' + ) + foreach ($lang in $Languages) { + Invoke-WebRequest "$LangBaseUrl/$lang.isl" -OutFile (Join-Path $LangsDir "$lang.isl") -UseBasicParsing + } } # Aegisub localization -Set-Location $BuildRoot -meson compile aegisub-gmo +meson compile -C $BuildRoot aegisub-gmo if(!$?) { Exit $LASTEXITCODE } # Invoke InnoSetup From 7e113ae77acbd029f680443d770cdc8039ec3daf Mon Sep 17 00:00:00 2001 From: Ryan Lucia Date: Wed, 12 Aug 2026 21:29:32 -0700 Subject: [PATCH 4/6] Avoid caching incomplete DependencyControl downloads --- tools/win-installer-setup.ps1 | 28 +++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/tools/win-installer-setup.ps1 b/tools/win-installer-setup.ps1 index 63c1caa023..c8d930692f 100644 --- a/tools/win-installer-setup.ps1 +++ b/tools/win-installer-setup.ps1 @@ -32,12 +32,30 @@ if (Test-Path 'Env:GITHUB_TOKEN') { $DepCtrlVersion = "v0.8.1" $DepCtrlDir = Join-Path $DepsDir "DependencyControl" if (!(Test-Path $DepCtrlDir)) { - New-Item -ItemType Directory -Path $DepCtrlDir | Out-Null $depCtrlUrl = "https://github.com/TypesettingTools/DependencyControl/releases/download/$DepCtrlVersion/DependencyControl-$DepCtrlVersion.zip" - $depCtrlZip = Join-Path $DepCtrlDir "DependencyControl.zip" - Invoke-WebRequest $depCtrlUrl -OutFile $depCtrlZip -UseBasicParsing - 7z x $depCtrlZip "-o$DepCtrlDir" - Remove-Item $depCtrlZip + $depCtrlStagingDir = Join-Path $DepsDir ("DependencyControl-{0}" -f [guid]::NewGuid().ToString("N")) + $depCtrlZip = Join-Path $depCtrlStagingDir "DependencyControl.zip" + + try { + New-Item -ItemType Directory -Path $depCtrlStagingDir | Out-Null + Invoke-WebRequest $depCtrlUrl -OutFile $depCtrlZip -UseBasicParsing + 7z x $depCtrlZip "-o$depCtrlStagingDir" + if ($LASTEXITCODE -ne 0) { + throw "Failed to extract DependencyControl (7z exited with code $LASTEXITCODE)" + } + + $depCtrlModule = Join-Path $depCtrlStagingDir "automation\include\l0\DependencyControl.moon" + if (!(Test-Path -LiteralPath $depCtrlModule -PathType Leaf)) { + throw "DependencyControl archive did not contain $depCtrlModule" + } + + Remove-Item -LiteralPath $depCtrlZip + Rename-Item -LiteralPath $depCtrlStagingDir -NewName (Split-Path $DepCtrlDir -Leaf) + } finally { + if (Test-Path -LiteralPath $depCtrlStagingDir) { + Remove-Item -LiteralPath $depCtrlStagingDir -Recurse -Force + } + } } # Avisynth From d57b85543b4ca20c37fc4f71376b7e12b371fa77 Mon Sep 17 00:00:00 2001 From: Ryan Lucia Date: Wed, 12 Aug 2026 21:35:13 -0700 Subject: [PATCH 5/6] Remove redundant DependencyControl comments --- packages/win_installer/fragment_automation.iss | 5 ----- packages/win_installer/portable/create-portable.ps1 | 1 - tools/win-installer-setup.ps1 | 5 ----- 3 files changed, 11 deletions(-) diff --git a/packages/win_installer/fragment_automation.iss b/packages/win_installer/fragment_automation.iss index 660473d92f..028cfc4f9e 100644 --- a/packages/win_installer/fragment_automation.iss +++ b/packages/win_installer/fragment_automation.iss @@ -32,11 +32,6 @@ DestDir: {app}\automation\include; Source: {#SOURCE_ROOT}\automation\include\uti DestDir: {app}\automation\include; Source: {#SOURCE_ROOT}\automation\include\utils-auto4.lua; Flags: ignoreversion overwritereadonly uninsremovereadonly; Attribs: readonly; Components: main #ifdef DEPCTRL -; DepCtrl's release bundle already has the files arranged for Aegisub's automation directory layout. -; -; Yutils, luajson and the ffi-experiments libraries are no longer bundled. DependencyControl -; installs Yutils from its own feed and ships internal replacements for json, BadMutex, PreciseTimer and -; DownloadManager. DestDir: {userappdata}\Aegisub\automation; Source: {#DEPS_DIR}\DependencyControl\automation\*; Flags: ignoreversion recursesubdirs createallsubdirs; Components: macros\modules\depctrl #endif diff --git a/packages/win_installer/portable/create-portable.ps1 b/packages/win_installer/portable/create-portable.ps1 index c92b1c6f55..84123cc178 100644 --- a/packages/win_installer/portable/create-portable.ps1 +++ b/packages/win_installer/portable/create-portable.ps1 @@ -73,7 +73,6 @@ Write-Step 'Copying automation' Copy-ToDirectory "$InstallerDir\share\aegisub\automation\*" "$PortableOutputDir\automation\" -Recurse Write-Step 'Copying DependencyControl' -# DepCtrl's release bundle already has the files arranged for Aegisub's automation directory layout. Copy-ToDirectory "$InstallerDepsDir\DependencyControl\automation\*" "$PortableOutputDir\automation\" -Recurse Write-Step 'Copying portable config' diff --git a/tools/win-installer-setup.ps1 b/tools/win-installer-setup.ps1 index c8d930692f..bf0a5895be 100644 --- a/tools/win-installer-setup.ps1 +++ b/tools/win-installer-setup.ps1 @@ -23,12 +23,7 @@ if (Test-Path 'Env:GITHUB_TOKEN') { $GitHeaders = @{ 'Authorization' = 'Bearer ' + $Env:GITHUB_TOKEN } } -# Yutils, luajson and the ffi-experiments libraries are no longer fetched: DependencyControl -# installs Yutils from its own feed and ships equivalents of json, BadMutex, PreciseTimer and -# DownloadManager, so it pulls each of them in on demand. - # DependencyControl -# Unlike a git clone, DepCtrl's release bundle already has the files arranged for Aegisub's automation directory layout. $DepCtrlVersion = "v0.8.1" $DepCtrlDir = Join-Path $DepsDir "DependencyControl" if (!(Test-Path $DepCtrlDir)) { From 6eb8311bda440396e9d960f04a4584ced25dc9dc Mon Sep 17 00:00:00 2001 From: line0 Date: Thu, 13 Aug 2026 23:46:16 +0200 Subject: [PATCH 6/6] Fix Windows installer script not bailing on errors and not cleaning up stale DepCtrl builds --- tools/win-installer-setup.ps1 | 43 ++++++++++++++++++++++++++++------- 1 file changed, 35 insertions(+), 8 deletions(-) diff --git a/tools/win-installer-setup.ps1 b/tools/win-installer-setup.ps1 index bf0a5895be..857a3bcd61 100644 --- a/tools/win-installer-setup.ps1 +++ b/tools/win-installer-setup.ps1 @@ -6,9 +6,13 @@ param ( [string]$BuildRoot, [Parameter(Position = 1, Mandatory = $true)] [ValidateNotNullOrEmpty()] - [string]$SourceRoot + [string]$SourceRoot, + [ValidateNotNullOrEmpty()] + [string]$DepCtrlVersion = "0.8.1" ) +$ErrorActionPreference = 'Stop' + $InstallerDir = Join-Path $SourceRoot "packages\win_installer" | Resolve-Path $DepsDir = Join-Path $BuildRoot "installer-deps" if (!(Test-Path $DepsDir)) { @@ -24,10 +28,24 @@ if (Test-Path 'Env:GITHUB_TOKEN') { } # DependencyControl -$DepCtrlVersion = "v0.8.1" $DepCtrlDir = Join-Path $DepsDir "DependencyControl" -if (!(Test-Path $DepCtrlDir)) { - $depCtrlUrl = "https://github.com/TypesettingTools/DependencyControl/releases/download/$DepCtrlVersion/DependencyControl-$DepCtrlVersion.zip" + +function Get-CachedDepCtrlVersion { + param([Parameter(Mandatory = $true)][string]$Root) + $module = Join-Path $Root "automation\include\l0\DependencyControl.moon" + if (!(Test-Path -LiteralPath $module -PathType Leaf)) { + return $null + } + $marker = Select-String -LiteralPath $module -Pattern 'version:\s*"([^"]+)".*--\s*@\{l0\.DependencyControl:version\}' | + Select-Object -First 1 + if (!$marker) { + return $null + } + $marker.Matches[0].Groups[1].Value +} + +if ((Get-CachedDepCtrlVersion $DepCtrlDir) -ne $DepCtrlVersion) { + $depCtrlUrl = "https://github.com/TypesettingTools/DependencyControl/releases/download/v$DepCtrlVersion/DependencyControl-v$DepCtrlVersion.zip" $depCtrlStagingDir = Join-Path $DepsDir ("DependencyControl-{0}" -f [guid]::NewGuid().ToString("N")) $depCtrlZip = Join-Path $depCtrlStagingDir "DependencyControl.zip" @@ -39,18 +57,27 @@ if (!(Test-Path $DepCtrlDir)) { throw "Failed to extract DependencyControl (7z exited with code $LASTEXITCODE)" } - $depCtrlModule = Join-Path $depCtrlStagingDir "automation\include\l0\DependencyControl.moon" - if (!(Test-Path -LiteralPath $depCtrlModule -PathType Leaf)) { - throw "DependencyControl archive did not contain $depCtrlModule" + $stagedVersion = Get-CachedDepCtrlVersion $depCtrlStagingDir + if (!$stagedVersion) { + throw "DependencyControl archive did not contain a versioned automation\include\l0\DependencyControl.moon" + } + if ($stagedVersion -ne $DepCtrlVersion) { + throw "DependencyControl archive contains version $stagedVersion, expected $DepCtrlVersion" } Remove-Item -LiteralPath $depCtrlZip + if (Test-Path -LiteralPath $DepCtrlDir) { + Remove-Item -LiteralPath $DepCtrlDir -Recurse -Force + } Rename-Item -LiteralPath $depCtrlStagingDir -NewName (Split-Path $DepCtrlDir -Leaf) + Write-Host "DependencyControl v$DepCtrlVersion has been downloaded to $DepCtrlDir" } finally { if (Test-Path -LiteralPath $depCtrlStagingDir) { - Remove-Item -LiteralPath $depCtrlStagingDir -Recurse -Force + Remove-Item -LiteralPath $depCtrlStagingDir -Recurse -Force -ErrorAction SilentlyContinue } } +} else { + Write-Host "DependencyControl v$DepCtrlVersion already cached at $DepCtrlDir" } # Avisynth