Compare commits
2 Commits
ee62045416
...
3c4dc329d0
| Author | SHA1 | Date | |
|---|---|---|---|
| 3c4dc329d0 | |||
| cfd0849cba |
10
package.json
10
package.json
@ -92,6 +92,7 @@
|
||||
"build:cloudflare": "cross-env VITE_DEPLOY_TARGET=cloudflare vite build",
|
||||
"deploy": "npm run build:cloudflare && wrangler pages deploy --branch main",
|
||||
"postinstall": "bun scripts/patch-electrobun-src.mjs && bun scripts/build-macos-effects.mjs",
|
||||
"generate-app-icons": "bun scripts/generate-app-icons.mjs",
|
||||
"build:macos-effects": "bun scripts/build-macos-effects.mjs",
|
||||
"clean": "bun scripts/clean-build.mjs"
|
||||
},
|
||||
@ -225,8 +226,7 @@
|
||||
},
|
||||
"win": {
|
||||
"target": [
|
||||
"nsis",
|
||||
"msiWrapped"
|
||||
"nsis"
|
||||
],
|
||||
"protocols": [
|
||||
{
|
||||
@ -245,12 +245,6 @@
|
||||
"allowToChangeInstallationDirectory": true,
|
||||
"include": "scripts/installer.nsh",
|
||||
"perMachine": false
|
||||
},
|
||||
"msiWrapped": {
|
||||
"upgradeCode": "{735812DB-E33B-57A0-8FBC-5FC3155925AA}",
|
||||
"perMachine": false,
|
||||
"impersonate": true,
|
||||
"wrappedInstallerArgs": "/S"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,159 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
|
||||
<!--
|
||||
Dual-purpose wrapper around the NSIS setup.exe.
|
||||
ALLUSERS=2 + MSIINSTALLPERUSER=1 defaults to per-user (matching NSIS
|
||||
RequestExecutionLevel user / $LOCALAPPDATA install) and is not blocked by
|
||||
DisableMsi=1 / error 1625 the way a pure InstallScope=perUser package is.
|
||||
-->
|
||||
<Product
|
||||
Id="*"
|
||||
Name="Farm Control"
|
||||
Language="1033"
|
||||
Version="__VERSION__"
|
||||
Manufacturer="Tom Butcher"
|
||||
UpgradeCode="__UPGRADE_CODE__">
|
||||
<Package
|
||||
InstallerVersion="500"
|
||||
Compressed="yes"
|
||||
InstallPrivileges="limited"
|
||||
Platform="x64" />
|
||||
|
||||
<Condition Message="Windows 7 and above is required"><![CDATA[Installed OR VersionNT >= 601]]></Condition>
|
||||
|
||||
<MajorUpgrade
|
||||
AllowSameVersionUpgrades="yes"
|
||||
DowngradeErrorMessage="A newer version of [ProductName] is already installed." />
|
||||
<MediaTemplate EmbedCab="yes" CompressionLevel="high" />
|
||||
|
||||
<Icon Id="InstallerIcon" SourceFile="__INSTALLER_ICON__" />
|
||||
<Property Id="ARPPRODUCTICON" Value="InstallerIcon" />
|
||||
|
||||
<Property Id="DISABLEADVTSHORTCUTS" Value="1" />
|
||||
<Property Id="ALLUSERS" Secure="yes" Value="2" />
|
||||
<Property Id="MSIINSTALLPERUSER" Secure="yes" Value="1" />
|
||||
<Property Id="REBOOT" Value="ReallySuppress" />
|
||||
|
||||
<!-- Prefer current per-user NSIS install; fall back to legacy per-machine. -->
|
||||
<Property Id="PREVIOUS_UNINSTALL_CMD">
|
||||
<RegistrySearch
|
||||
Id="PreviousUninstallCmdHkcuSearch"
|
||||
Root="HKCU"
|
||||
Key="Software\Microsoft\Windows\CurrentVersion\Uninstall\Farm Control"
|
||||
Name="UninstallString"
|
||||
Type="raw" />
|
||||
</Property>
|
||||
<Property Id="PREVIOUS_UNINSTALL_CMD_LEGACY">
|
||||
<RegistrySearch
|
||||
Id="PreviousUninstallCmdHklmSearch"
|
||||
Root="HKLM"
|
||||
Key="Software\Microsoft\Windows\CurrentVersion\Uninstall\Farm Control"
|
||||
Name="UninstallString"
|
||||
Type="raw"
|
||||
Win64="yes" />
|
||||
</Property>
|
||||
|
||||
<Property Id="PREVIOUS_INSTALL_DIR">
|
||||
<RegistrySearch
|
||||
Id="PreviousInstallDirHkcuSearch"
|
||||
Root="HKCU"
|
||||
Key="Software\Tom Butcher\Farm Control"
|
||||
Name="InstallDir"
|
||||
Type="directory" />
|
||||
</Property>
|
||||
<Property Id="PREVIOUS_INSTALL_DIR_LEGACY">
|
||||
<RegistrySearch
|
||||
Id="PreviousInstallDirHklmSearch"
|
||||
Root="HKLM"
|
||||
Key="Software\Tom Butcher\Farm Control"
|
||||
Name="InstallDir"
|
||||
Type="directory"
|
||||
Win64="yes" />
|
||||
</Property>
|
||||
|
||||
<Binary Id="WrappedExe" SourceFile="__SETUP_EXE__" />
|
||||
|
||||
<CustomAction
|
||||
Id="KillFarmControl"
|
||||
BinaryKey="WixCA"
|
||||
DllEntry="WixQuietExec"
|
||||
Execute="immediate"
|
||||
Impersonate="yes"
|
||||
Return="ignore" />
|
||||
|
||||
<CustomAction
|
||||
Id="UninstallPrevious"
|
||||
BinaryKey="WixCA"
|
||||
DllEntry="WixQuietExec"
|
||||
Execute="immediate"
|
||||
Impersonate="yes"
|
||||
Return="ignore" />
|
||||
|
||||
<CustomAction
|
||||
Id="RunInstaller"
|
||||
BinaryKey="WrappedExe"
|
||||
ExeCommand="/S"
|
||||
Execute="immediate"
|
||||
Impersonate="yes"
|
||||
Return="check" />
|
||||
|
||||
<Directory Id="TARGETDIR" Name="SourceDir">
|
||||
<Component Id="PerUserMarker" Guid="8A3F2E1D-9C4B-4A7E-B6D5-1F0E3C2B4A59">
|
||||
<RegistryValue
|
||||
Root="HKCU"
|
||||
Key="Software\Tom Butcher\Farm Control"
|
||||
Name="MsiWrapper"
|
||||
Type="integer"
|
||||
Value="1"
|
||||
KeyPath="yes" />
|
||||
</Component>
|
||||
</Directory>
|
||||
|
||||
<Feature Id="MainFeature" Title="Farm Control" Level="1">
|
||||
<ComponentRef Id="PerUserMarker" />
|
||||
</Feature>
|
||||
|
||||
<CustomAction
|
||||
Id="SetKillFarmControl"
|
||||
Property="QtExecCmdLine"
|
||||
Value="taskkill.exe /F /IM launcher.exe /T"
|
||||
Execute="immediate" />
|
||||
|
||||
<CustomAction
|
||||
Id="SetUninstallPreviousFromRegistry"
|
||||
Property="QtExecCmdLine"
|
||||
Value=""[PREVIOUS_UNINSTALL_CMD]" /S"
|
||||
Execute="immediate" />
|
||||
|
||||
<CustomAction
|
||||
Id="SetUninstallPreviousFromRegistryLegacy"
|
||||
Property="QtExecCmdLine"
|
||||
Value=""[PREVIOUS_UNINSTALL_CMD_LEGACY]" /S"
|
||||
Execute="immediate" />
|
||||
|
||||
<CustomAction
|
||||
Id="SetUninstallPreviousFromInstallDir"
|
||||
Property="QtExecCmdLine"
|
||||
Value=""[PREVIOUS_INSTALL_DIR]Uninstall.exe" /S"
|
||||
Execute="immediate" />
|
||||
|
||||
<CustomAction
|
||||
Id="SetUninstallPreviousFromInstallDirLegacy"
|
||||
Property="QtExecCmdLine"
|
||||
Value=""[PREVIOUS_INSTALL_DIR_LEGACY]Uninstall.exe" /S"
|
||||
Execute="immediate" />
|
||||
|
||||
<InstallExecuteSequence>
|
||||
<Custom Action="SetKillFarmControl" Before="KillFarmControl">NOT Installed</Custom>
|
||||
<Custom Action="KillFarmControl" After="InstallInitialize">NOT Installed</Custom>
|
||||
|
||||
<Custom Action="SetUninstallPreviousFromRegistry" Before="UninstallPrevious">NOT Installed AND PREVIOUS_UNINSTALL_CMD</Custom>
|
||||
<Custom Action="SetUninstallPreviousFromRegistryLegacy" Before="UninstallPrevious">NOT Installed AND NOT PREVIOUS_UNINSTALL_CMD AND PREVIOUS_UNINSTALL_CMD_LEGACY</Custom>
|
||||
<Custom Action="SetUninstallPreviousFromInstallDir" Before="UninstallPrevious">NOT Installed AND NOT PREVIOUS_UNINSTALL_CMD AND NOT PREVIOUS_UNINSTALL_CMD_LEGACY AND PREVIOUS_INSTALL_DIR</Custom>
|
||||
<Custom Action="SetUninstallPreviousFromInstallDirLegacy" Before="UninstallPrevious">NOT Installed AND NOT PREVIOUS_UNINSTALL_CMD AND NOT PREVIOUS_UNINSTALL_CMD_LEGACY AND NOT PREVIOUS_INSTALL_DIR AND PREVIOUS_INSTALL_DIR_LEGACY</Custom>
|
||||
|
||||
<Custom Action="UninstallPrevious" Before="RunInstaller">NOT Installed AND (PREVIOUS_UNINSTALL_CMD OR PREVIOUS_UNINSTALL_CMD_LEGACY OR PREVIOUS_INSTALL_DIR OR PREVIOUS_INSTALL_DIR_LEGACY)</Custom>
|
||||
<Custom Action="RunInstaller" After="KillFarmControl">NOT Installed</Custom>
|
||||
</InstallExecuteSequence>
|
||||
</Product>
|
||||
</Wix>
|
||||
@ -1,130 +0,0 @@
|
||||
param(
|
||||
[Parameter(Mandatory = $true)]
|
||||
[string]$SetupExe,
|
||||
|
||||
[Parameter(Mandatory = $true)]
|
||||
[string]$OutputMsi,
|
||||
|
||||
[Parameter(Mandatory = $true)]
|
||||
[string]$Version,
|
||||
|
||||
[string]$UpgradeCode = "735812DB-E33B-57A0-8FBC-5FC3155925AA"
|
||||
)
|
||||
|
||||
$ErrorActionPreference = "Stop"
|
||||
|
||||
function Get-MsiVersion {
|
||||
param([string]$InputVersion)
|
||||
|
||||
$parts = $InputVersion.Split(".")
|
||||
while ($parts.Count -lt 4) {
|
||||
$parts += "0"
|
||||
}
|
||||
|
||||
return ($parts[0..3] -join ".")
|
||||
}
|
||||
|
||||
function Find-WixToolset {
|
||||
$searchRoots = @(
|
||||
$env:WIX,
|
||||
$env:WIX_TOOLSET_PATH,
|
||||
"${env:ProgramFiles(x86)}\WiX Toolset v3.14\bin",
|
||||
"${env:ProgramFiles}\WiX Toolset v3.14\bin",
|
||||
"${env:ProgramFiles(x86)}\WiX Toolset v3.11\bin",
|
||||
"${env:ProgramFiles}\WiX Toolset v3.11\bin"
|
||||
)
|
||||
|
||||
foreach ($root in $searchRoots) {
|
||||
if (-not $root) {
|
||||
continue
|
||||
}
|
||||
|
||||
$candle = Join-Path $root "candle.exe"
|
||||
$light = Join-Path $root "light.exe"
|
||||
if ((Test-Path $candle) -and (Test-Path $light)) {
|
||||
return @{
|
||||
Candle = $candle
|
||||
Light = $light
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$candleCommand = Get-Command candle.exe -ErrorAction SilentlyContinue
|
||||
$lightCommand = Get-Command light.exe -ErrorAction SilentlyContinue
|
||||
if ($candleCommand -and $lightCommand) {
|
||||
return @{
|
||||
Candle = $candleCommand.Source
|
||||
Light = $lightCommand.Source
|
||||
}
|
||||
}
|
||||
|
||||
throw @"
|
||||
WiX Toolset not found. Install WiX Toolset 3.11+ on the Windows build agent and ensure candle.exe and light.exe are on PATH.
|
||||
Example: choco install wixtoolset --version=3.14.0.4118
|
||||
"@
|
||||
}
|
||||
|
||||
function Escape-WixSourcePath {
|
||||
param([string]$Path)
|
||||
|
||||
return $Path.Replace("\", "\\")
|
||||
}
|
||||
|
||||
$rootDir = Split-Path -Parent $PSScriptRoot
|
||||
$templatePath = Join-Path $rootDir "packaging/windows/msi-wrapped.wxs"
|
||||
$workDir = Join-Path $env:TEMP "farmcontrol-wix"
|
||||
$wix = Find-WixToolset
|
||||
|
||||
if (Test-Path $workDir) {
|
||||
Remove-Item $workDir -Recurse -Force
|
||||
}
|
||||
New-Item -ItemType Directory -Path $workDir | Out-Null
|
||||
|
||||
$setupExePath = (Resolve-Path -LiteralPath $SetupExe).Path
|
||||
$outputMsiPath = $ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($OutputMsi)
|
||||
$outputDir = Split-Path $outputMsiPath -Parent
|
||||
if ($outputDir -and -not (Test-Path $outputDir)) {
|
||||
New-Item -ItemType Directory -Path $outputDir -Force | Out-Null
|
||||
}
|
||||
|
||||
$installerIconPath = Join-Path $rootDir "assets\installer.ico"
|
||||
if (-not (Test-Path $installerIconPath)) {
|
||||
throw "Installer icon not found at $installerIconPath. Run scripts/prepare-installer-icons.mjs first."
|
||||
}
|
||||
|
||||
$installerIconWorkPath = Join-Path $workDir "installer.ico"
|
||||
Copy-Item -LiteralPath $installerIconPath -Destination $installerIconWorkPath -Force
|
||||
|
||||
$msiVersion = Get-MsiVersion $Version
|
||||
$wxsContent = Get-Content -LiteralPath $templatePath -Raw
|
||||
$wxsContent = $wxsContent.Replace("__UPGRADE_CODE__", $UpgradeCode)
|
||||
$wxsContent = $wxsContent.Replace("__VERSION__", $msiVersion)
|
||||
$wxsContent = $wxsContent.Replace("__SETUP_EXE__", (Escape-WixSourcePath $setupExePath))
|
||||
$wxsContent = $wxsContent.Replace("__INSTALLER_ICON__", (Escape-WixSourcePath $installerIconWorkPath))
|
||||
|
||||
$projectWxs = Join-Path $workDir "project.wxs"
|
||||
Set-Content -LiteralPath $projectWxs -Value $wxsContent -Encoding UTF8
|
||||
|
||||
$wixObj = Join-Path $workDir "project.wixobj"
|
||||
|
||||
Push-Location $workDir
|
||||
try {
|
||||
& $wix.Candle "-arch" "x64" "-ext" "WixUtilExtension" $projectWxs
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
throw "candle.exe failed with exit code $LASTEXITCODE"
|
||||
}
|
||||
|
||||
& $wix.Light "-out" $outputMsiPath "-spdb" "-sw1076" "-ext" "WixUtilExtension" $wixObj
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
throw "light.exe failed with exit code $LASTEXITCODE"
|
||||
}
|
||||
} finally {
|
||||
Pop-Location
|
||||
Remove-Item $workDir -Recurse -Force
|
||||
}
|
||||
|
||||
if (-not (Test-Path $outputMsiPath)) {
|
||||
throw "MSI installer was not created at $outputMsiPath"
|
||||
}
|
||||
|
||||
Write-Host "Created MSI installer at $outputMsiPath"
|
||||
@ -20,6 +20,7 @@ import {
|
||||
expandWindowsAppFromArchive
|
||||
} from './expand-windows-installer.mjs'
|
||||
import { stageWindowsDeeplink } from './build-windows-deeplink.mjs'
|
||||
import { patchWindowsBinaries } from './patch-windows-binaries.mjs'
|
||||
import { codesignMacAppBundle } from './codesign-macos-app.mjs'
|
||||
|
||||
const rootDir = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..')
|
||||
@ -211,7 +212,7 @@ function findCommand(command) {
|
||||
function buildInstallerIcns(destinationPath) {
|
||||
if (!existsSync(MAC_INSTALLER_ICONSET_PATH)) {
|
||||
throw new Error(
|
||||
`Installer iconset not found at ${MAC_INSTALLER_ICONSET_PATH}. Run scripts/prepare-installer-icons.mjs first.`
|
||||
`Installer iconset not found at ${MAC_INSTALLER_ICONSET_PATH}. Run \`bun run generate-app-icons\` first.`
|
||||
)
|
||||
}
|
||||
|
||||
@ -572,50 +573,6 @@ function buildWindowsNsis(appDir, arch) {
|
||||
return exePath
|
||||
}
|
||||
|
||||
function buildWindowsMsi(setupExePath, arch) {
|
||||
const scriptPath = path.join(rootDir, 'scripts/build-windows-msi.ps1')
|
||||
const msiPath = path.join(
|
||||
artifactDir,
|
||||
getReleaseArtifactName(version, arch, 'msi')
|
||||
)
|
||||
const powershell = process.env.SystemRoot
|
||||
? path.join(
|
||||
process.env.SystemRoot,
|
||||
'System32',
|
||||
'WindowsPowerShell',
|
||||
'v1.0',
|
||||
'powershell.exe'
|
||||
)
|
||||
: 'powershell.exe'
|
||||
|
||||
const result = spawnSync(
|
||||
powershell,
|
||||
[
|
||||
'-NoProfile',
|
||||
'-ExecutionPolicy',
|
||||
'Bypass',
|
||||
'-File',
|
||||
scriptPath,
|
||||
'-SetupExe',
|
||||
setupExePath,
|
||||
'-OutputMsi',
|
||||
msiPath,
|
||||
'-Version',
|
||||
version
|
||||
],
|
||||
{ stdio: 'inherit' }
|
||||
)
|
||||
|
||||
if (result.status !== 0) {
|
||||
throw new Error(
|
||||
`build-windows-msi.ps1 failed with exit code ${result.status ?? 1}`
|
||||
)
|
||||
}
|
||||
|
||||
console.log(`Published ${msiPath}`)
|
||||
return msiPath
|
||||
}
|
||||
|
||||
if (buildEnv === 'dev') {
|
||||
console.log('finalize-desktop-artifacts: skipping dev build')
|
||||
process.exit(0)
|
||||
@ -662,11 +619,12 @@ async function main() {
|
||||
platformDir
|
||||
)
|
||||
stageWindowsDeeplinkScript(appDir)
|
||||
await patchWindowsBinaries(appDir)
|
||||
|
||||
let published
|
||||
try {
|
||||
const setupExe = buildWindowsNsis(appDir, arch)
|
||||
published = [setupExe, buildWindowsMsi(setupExe, arch)]
|
||||
published = [setupExe]
|
||||
|
||||
if (installerFiles.setupZip) {
|
||||
published.push(publishArtifact(installerFiles.setupZip, arch, 'zip'))
|
||||
|
||||
27
scripts/generate-app-icons.mjs
Normal file
27
scripts/generate-app-icons.mjs
Normal file
@ -0,0 +1,27 @@
|
||||
import path from 'node:path'
|
||||
import { spawnSync } from 'node:child_process'
|
||||
import { fileURLToPath } from 'node:url'
|
||||
|
||||
const rootDir = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..')
|
||||
|
||||
const steps = [
|
||||
[
|
||||
path.join(rootDir, 'scripts/prepare-app-icons.mjs'),
|
||||
'assets/logos/farmcontrolicon.png'
|
||||
],
|
||||
[path.join(rootDir, 'scripts/prepare-installer-icons.mjs')]
|
||||
]
|
||||
|
||||
for (const args of steps) {
|
||||
const result = spawnSync('bun', args, {
|
||||
cwd: rootDir,
|
||||
stdio: 'inherit',
|
||||
env: process.env
|
||||
})
|
||||
|
||||
if (result.status !== 0) {
|
||||
process.exit(result.status ?? 1)
|
||||
}
|
||||
}
|
||||
|
||||
console.log('generate-app-icons: done')
|
||||
@ -61,33 +61,31 @@ if (process.platform === "darwin") {
|
||||
}
|
||||
}
|
||||
|
||||
const prepareIcons = spawnSync(
|
||||
"bun",
|
||||
[
|
||||
path.join(rootDir, "scripts/prepare-app-icons.mjs"),
|
||||
"assets/logos/farmcontrolicon.png",
|
||||
],
|
||||
{ cwd: rootDir, stdio: "inherit", env: process.env },
|
||||
);
|
||||
const requiredIconPaths = [
|
||||
path.join(rootDir, "assets/icon.ico"),
|
||||
path.join(rootDir, "assets/icon.png"),
|
||||
path.join(rootDir, "assets/icon.iconset/icon_256x256.png"),
|
||||
path.join(rootDir, "assets/installer.ico"),
|
||||
];
|
||||
|
||||
if (prepareIcons.status !== 0) {
|
||||
if (buildEnv === "stable") {
|
||||
const prepareIcons = spawnSync(
|
||||
"bun",
|
||||
[path.join(rootDir, "scripts/generate-app-icons.mjs")],
|
||||
{ cwd: rootDir, stdio: "inherit", env: process.env },
|
||||
);
|
||||
|
||||
if (prepareIcons.status !== 0) {
|
||||
process.exit(prepareIcons.status ?? 1);
|
||||
}
|
||||
}
|
||||
|
||||
const prepareInstallerIcons = spawnSync(
|
||||
"bun",
|
||||
[path.join(rootDir, "scripts/prepare-installer-icons.mjs")],
|
||||
{ cwd: rootDir, stdio: "inherit", env: process.env },
|
||||
);
|
||||
|
||||
if (prepareInstallerIcons.status !== 0) {
|
||||
process.exit(prepareInstallerIcons.status ?? 1);
|
||||
}
|
||||
|
||||
const windowsIconPath = path.join(rootDir, "assets/icon.ico");
|
||||
if (!existsSync(windowsIconPath)) {
|
||||
const missingIcons = requiredIconPaths.filter((filePath) => !existsSync(filePath));
|
||||
if (missingIcons.length > 0) {
|
||||
console.error(
|
||||
"pre-build: assets/icon.ico not found after prepare-app-icons (required for build.win.icon)",
|
||||
`pre-build: missing generated icons:\n${missingIcons
|
||||
.map((filePath) => ` - ${path.relative(rootDir, filePath)}`)
|
||||
.join("\n")}\nRun \`bun run generate-app-icons\` to create them.`,
|
||||
);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user