mirror of
https://github.com/cryptomator/cryptomator.git
synced 2026-06-09 21:52:35 +00:00
326 lines
13 KiB
PowerShell
326 lines
13 KiB
PowerShell
Param(
|
|
[Parameter(Mandatory, HelpMessage="Please provide a name for the app")][string] $AppName,
|
|
[Parameter(Mandatory, HelpMessage="Please provide the glob pattern to identify the main jar")][string] $MainJarGlob,
|
|
[Parameter(Mandatory, HelpMessage="Please provide the module- and main class path to start the app")][string] $ModuleAndMainClass,
|
|
[Parameter(Mandatory, HelpMessage="Please provide the windows upgrade uuid for the installer")][string] $UpgradeUUID,
|
|
[Parameter(Mandatory, HelpMessage="Please provide the name of the vendor")][string] $Vendor,
|
|
[Parameter(Mandatory, HelpMessage="Please provide the starting year for the copyright notice")][int] $CopyrightStartYear,
|
|
[Parameter(Mandatory, HelpMessage="Please provide a help url")][string] $HelpUrl,
|
|
[Parameter(Mandatory, HelpMessage="Please provide an update url")][string] $UpdateUrl,
|
|
[Parameter(Mandatory, HelpMessage="Please provide an about url")][string] $AboutUrl,
|
|
[Parameter(Mandatory, HelpMessage="Please provide an alias for localhost")][string] $LoopbackAlias,
|
|
[bool] $clean = $false # if true, cleans up previous build artifacts
|
|
)
|
|
|
|
# ============================
|
|
# Function Definitions Section
|
|
# ============================
|
|
|
|
function Invoke-CommandWithExitCheck {
|
|
param (
|
|
[string]$Command,
|
|
[string[]]$Arguments
|
|
)
|
|
|
|
& $Command @Arguments
|
|
if ($LASTEXITCODE -ne 0) {
|
|
Write-Error "Command '$Command' failed with exit code $LASTEXITCODE"
|
|
exit $LASTEXITCODE
|
|
}
|
|
}
|
|
|
|
function Main {
|
|
|
|
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
|
|
$ProgressPreference = 'SilentlyContinue' # disables Invoke-WebRequest's progress bar, which slows down downloads to a few bytes/s
|
|
|
|
# check preconditions
|
|
if ((Get-Command "git" -ErrorAction SilentlyContinue) -eq $null)
|
|
{
|
|
Write-Error "Unable to find git.exe in your PATH (try: choco install git)"
|
|
exit 1
|
|
}
|
|
if ((Get-Command "mvn" -ErrorAction SilentlyContinue) -eq $null)
|
|
{
|
|
Write-Error "Unable to find mvn.cmd in your PATH (try: choco install maven)"
|
|
exit 1
|
|
}
|
|
if ((Get-Command 'wix' -ErrorAction SilentlyContinue) -eq $null)
|
|
{
|
|
Write-Error 'Unable to find wix in your PATH (try: dotnet tool install --global wix --version 6.0.2)'
|
|
exit 1
|
|
}
|
|
$wixExtensions = & wix.exe extension list --global | Out-String
|
|
if ($wixExtensions -notmatch 'WixToolset.UI.wixext') {
|
|
Write-Error 'Wix UI extension missing. Please install it with: wix.exe extension add WixToolset.UI.wixext/6.0.2 --global)'
|
|
exit 1
|
|
}
|
|
if ($wixExtensions -notmatch 'WixToolset.Util.wixext') {
|
|
Write-Error 'Wix Util extension missing. Please install it with: wix.exe extension add WixToolset.Util.wixext/6.0.2 --global)'
|
|
exit 1
|
|
}
|
|
if ($wixExtensions -notmatch 'WixToolset.BootstrapperApplications.wixext') {
|
|
Write-Error 'Wix Bootstrapper extension missing. Please install it with: wix.exe extension add WixToolset.BootstrapperApplications.wixext/6.0.2 --global)'
|
|
exit 1
|
|
}
|
|
|
|
$buildDir = Split-Path -Parent $PSCommandPath
|
|
$version = $(mvn -f $buildDir/../../pom.xml help:evaluate -Dexpression="project.version" -q -DforceStdout)
|
|
$semVerNo = $version -replace '(\d+\.\d+\.\d+).*','$1'
|
|
$revisionNo = $(git rev-list --count HEAD)
|
|
|
|
Write-Host "`$version=$version"
|
|
Write-Host "`$semVerNo=$semVerNo"
|
|
Write-Host "`$revisionNo=$revisionNo"
|
|
Write-Host "`$buildDir=$buildDir"
|
|
Write-Host "`$Env:JAVA_HOME=$Env:JAVA_HOME"
|
|
|
|
$copyright = "(C) $CopyrightStartYear - $((Get-Date).Year) $Vendor"
|
|
|
|
# compile
|
|
Invoke-CommandWithExitCheck -Command `
|
|
"mvn" -Arguments @("-B", "-f", "$buildDir/../../pom.xml", "clean", "package", "-DskipTests", "-Pwin")
|
|
Copy-Item "$buildDir\..\..\target\$MainJarGlob.jar" -Destination "$buildDir\..\..\target\mods"
|
|
|
|
# add runtime
|
|
$runtimeImagePath = '.\runtime'
|
|
if ($clean -and (Test-Path -Path $runtimeImagePath)) {
|
|
Remove-Item -Path $runtimeImagePath -Force -Recurse
|
|
}
|
|
|
|
## download jfx jmods for X64, while they are part of the Arm64 JDK
|
|
$archCode = (Get-CimInstance Win32_Processor).Architecture
|
|
$archName = switch ($archCode) {
|
|
9 { "x64" }
|
|
12 { "ARM64" }
|
|
default { "WMI Win32_Processor.Architecture code ($archCode)" }
|
|
}
|
|
|
|
switch ($archName) {
|
|
'ARM64' {
|
|
$javafxBaseJmod = Join-Path $Env:JAVA_HOME "jmods\javafx.base.jmod"
|
|
if (!(Test-Path $javafxBaseJmod)) {
|
|
Write-Error "JavaFX module not found in JDK. Please ensure a JDK with JavaFX (including jmods) is installed."
|
|
exit 1
|
|
}
|
|
|
|
$jmodPaths = "$Env:JAVA_HOME/jmods"
|
|
}
|
|
'x64' {
|
|
$javaFxVersion='25.0.3'
|
|
$javaFxJmodsUrl = "https://download2.gluonhq.com/openjfx/${javaFxVersion}/openjfx-${javaFxVersion}_windows-x64_bin-jmods.zip"
|
|
$javaFxJmodsSHA256 = '0bf9b83260b85607a9ba200124debabd9cdb013cbc0d659e62a20192a7137907'
|
|
$javaFxJmods = '.\resources\jfxJmods.zip'
|
|
|
|
if( !(Test-Path -Path $javaFxJmods) ) {
|
|
Write-Host "Downloading ${javaFxJmodsUrl}..."
|
|
Invoke-WebRequest $javaFxJmodsUrl -OutFile $javaFxJmods # redirects are followed by default
|
|
}
|
|
|
|
$jmodsChecksumActual = $(Get-FileHash -Path $javaFxJmods -Algorithm SHA256).Hash.ToLower()
|
|
if( $jmodsChecksumActual -ne $javaFxJmodsSHA256 ) {
|
|
Write-Error "Checksum mismatch for jfxJmods.zip. Expected: $javaFxJmodsSHA256
|
|
, actual: $jmodsChecksumActual"
|
|
exit 1;
|
|
}
|
|
|
|
Expand-Archive -Path $javaFxJmods -Force -DestinationPath ".\resources\"
|
|
Remove-Item -Recurse -Force -Path ".\resources\javafx-jmods" -ErrorAction Ignore
|
|
Move-Item -Force -Path ".\resources\javafx-jmods-*" -Destination ".\resources\javafx-jmods" -ErrorAction Stop
|
|
|
|
$jmodPaths="$buildDir/resources/javafx-jmods";
|
|
}
|
|
default {
|
|
Write-Error "Unsupported architecture: $arch"
|
|
exit 1
|
|
}
|
|
}
|
|
|
|
## create custom runtime
|
|
### check for JEP 493
|
|
if ((& "$Env:JAVA_HOME\bin\jlink" --help | Select-String -Pattern "Linking from run-time image enabled" -SimpleMatch | Measure-Object).Count -eq 0 ) {
|
|
$jmodPaths="$Env:JAVA_HOME/jmods;" + $jmodPaths;
|
|
}
|
|
|
|
### create runtime
|
|
Invoke-CommandWithExitCheck -Command `
|
|
"$Env:JAVA_HOME\bin\jlink" -Arguments @(
|
|
"--verbose",
|
|
"--output", "runtime",
|
|
"--module-path", $jmodPaths,
|
|
"--add-modules", "java.base,java.desktop,java.instrument,java.logging,java.naming,java.net.http,java.scripting,java.sql,java.xml,jdk.unsupported,jdk.accessibility,jdk.management.jfr,jdk.crypto.cryptoki,jdk.crypto.ec,jdk.crypto.mscapi,java.compiler,javafx.base,javafx.graphics,javafx.controls,javafx.fxml",
|
|
"--strip-native-commands",
|
|
"--no-header-files",
|
|
"--no-man-pages",
|
|
"--strip-debug",
|
|
"--compress", "zip-0" #do not compress and use msi compression
|
|
)
|
|
|
|
$appPath = ".\$AppName"
|
|
if ($clean -and (Test-Path -Path $appPath)) {
|
|
Remove-Item -Path $appPath -Force -Recurse
|
|
}
|
|
|
|
|
|
$javaOptions = @(
|
|
"--java-options", "--enable-native-access=javafx.graphics,org.cryptomator.jfuse.win,org.cryptomator.integrations.win"
|
|
"--java-options", "-Xss5m"
|
|
"--java-options", "-Xmx256m"
|
|
"--java-options", "-Dcryptomator.appVersion=`"$semVerNo`""
|
|
"--java-options", "-Dfile.encoding=`"utf-8`""
|
|
"--java-options", "-Djava.net.useSystemProxies=true"
|
|
"--java-options", "-Dcryptomator.logDir=`"@{localappdata}/$AppName`""
|
|
"--java-options", "-XX:ErrorFile=`"C:/cryptomator/cryptomator_crash.log`""
|
|
"--java-options", "-Dcryptomator.adminConfigPath=`"C:/ProgramData/$AppName/config.properties`""
|
|
"--java-options", "-Dcryptomator.settingsPath=`"@{appdata}/$AppName/settings.json;@{userhome}/AppData/Roaming/$AppName/settings.json`""
|
|
"--java-options", "-Dcryptomator.ipcSocketPath=`"@{localappdata}/$AppName/ipc.socket`""
|
|
"--java-options", "-Dcryptomator.p12Path=`"@{appdata}/$AppName/key.p12;@{userhome}/AppData/Roaming/$AppName/key.p12`""
|
|
"--java-options", "-Dcryptomator.mountPointsDir=`"@{userhome}/$AppName`""
|
|
"--java-options", "-Dcryptomator.loopbackAlias=`"$LoopbackAlias`""
|
|
"--java-options", "-Dcryptomator.integrationsWin.autoStartShellLinkName=`"$AppName`""
|
|
"--java-options", "-Dcryptomator.integrationsWin.keychainPaths=`"@{appdata}/$AppName/keychain.json;@{userhome}/AppData/Roaming/$AppName/keychain.json`""
|
|
"--java-options", "-Dcryptomator.integrationsWin.windowsHelloKeychainPaths=`"@{appdata}/$AppName/windowsHelloKeychain.json`""
|
|
"--java-options", "-Dcryptomator.showTrayIcon=true"
|
|
"--java-options", "-Dcryptomator.buildNumber=`"msi-$revisionNo`""
|
|
"--java-options", "-Dcryptomator.disableUpdateCheck=false"
|
|
"--java-options", "-Dcryptomator.hub.enableTrustOnFirstUse=true"
|
|
)
|
|
|
|
|
|
# create app dir
|
|
& "$Env:JAVA_HOME\bin\jpackage" `
|
|
--verbose `
|
|
--type app-image `
|
|
--runtime-image runtime `
|
|
--input ../../target/libs `
|
|
--module-path ../../target/mods `
|
|
--module $ModuleAndMainClass `
|
|
--dest . `
|
|
--name $AppName `
|
|
--vendor $Vendor `
|
|
--copyright $copyright `
|
|
--app-version "$semVerNo.$revisionNo" `
|
|
--resource-dir resources `
|
|
--icon resources/$AppName.ico `
|
|
--add-launcher "${AppName} (Debug)=$buildDir\debug-launcher.properties" `
|
|
@javaOptions
|
|
|
|
if ($LASTEXITCODE -ne 0) {
|
|
Write-Error "jpackage Appimage failed with exit code $LASTEXITCODE"
|
|
return 1;
|
|
}
|
|
|
|
#Create RTF license for msi
|
|
Invoke-CommandWithExitCheck -Command `
|
|
"mvn" -Arguments @("-B", "-f", "$buildDir/../../pom.xml", "license:add-third-party", `
|
|
"-Dlicense.thirdPartyFilename=license.rtf", `
|
|
"-Dlicense.fileTemplate=$buildDir\resources\licenseTemplate.ftl", `
|
|
"-Dlicense.outputDirectory=$buildDir\resources\", `
|
|
"-Dlicense.includedScopes=compile", `
|
|
"-Dlicense.excludedGroups=^org\.cryptomator", `
|
|
"-Dlicense.failOnMissing=true", `
|
|
"-Dlicense.licenseMergesUrl=file:///$buildDir/../../license/merges")
|
|
|
|
# patch app dir
|
|
Copy-Item "contrib\*" -Destination "$AppName"
|
|
attrib -r "$AppName\$AppName.exe"
|
|
attrib -r "$AppName\${AppName} (Debug).exe"
|
|
|
|
# create .msi
|
|
$Env:JP_WIXWIZARD_RESOURCES = "$buildDir\resources\"
|
|
$Env:JP_WIXWIZARD_RESOURCES_PROPERTIES_FORMAT = "${Env:JP_WIXWIZARD_RESOURCES}".Replace('\', '\\');
|
|
$Env:JP_WIXHELPER_DIR = ""
|
|
|
|
Get-Content .\resources\FAvaultFile.template.properties ` # Similar to envsubst
|
|
| ForEach-Object { $ExecutionContext.InvokeCommand.ExpandString($_) } `
|
|
| Out-File -FilePath .\resources\FAvaultFile.properties
|
|
|
|
Invoke-CommandWithExitCheck -Command `
|
|
"$Env:JAVA_HOME\bin\jpackage" -Arguments @(
|
|
"--verbose",
|
|
"--type", "msi",
|
|
"--win-upgrade-uuid", $UpgradeUUID,
|
|
"--app-image", $AppName,
|
|
"--dest", "installer",
|
|
"--name", $AppName,
|
|
"--vendor", $Vendor,
|
|
"--copyright", $copyright,
|
|
"--app-version", "$semVerNo.$revisionNo",
|
|
"--win-menu",
|
|
"--win-dir-chooser",
|
|
"--win-shortcut-prompt",
|
|
"--win-menu-group", $AppName,
|
|
"--resource-dir", "resources",
|
|
"--license-file", "resources/license.rtf",
|
|
"--win-update-url", $UpdateUrl,
|
|
"--about-url", $AboutUrl,
|
|
"--file-associations", "resources/FAvaultFile.properties"
|
|
)
|
|
|
|
#Create RTF license for bundle
|
|
Invoke-CommandWithExitCheck -Command `
|
|
"mvn" -Arguments @("-B", "-f", "$buildDir/../../pom.xml", "license:add-third-party", `
|
|
"-Dlicense.thirdPartyFilename=license.rtf", `
|
|
"-Dlicense.fileTemplate=$buildDir\bundle\resources\licenseTemplate.ftl", `
|
|
"-Dlicense.outputDirectory=$buildDir\bundle\resources\", `
|
|
"-Dlicense.includedScopes=compile", `
|
|
"-Dlicense.excludedGroups=^org\.cryptomator", `
|
|
"-Dlicense.failOnMissing=true", `
|
|
"-Dlicense.licenseMergesUrl=file:///$buildDir/../../license/merges")
|
|
|
|
# download Winfsp
|
|
$winfspMsiUrl= 'https://github.com/winfsp/winfsp/releases/download/v2.1/winfsp-2.1.25156.msi'
|
|
$winfspMsiHash = '073A70E00F77423E34BED98B86E600DEF93393BA5822204FAC57A29324DB9F7A'
|
|
Write-Host "Downloading ${winfspMsiUrl}..."
|
|
Invoke-WebRequest $winfspMsiUrl -OutFile ".\bundle\resources\winfsp.msi" # redirects are followed by default
|
|
$computedHash = $(Get-FileHash -Path '.\bundle\resources\winfsp.msi' -Algorithm SHA256).Hash
|
|
if (! $computedHash.Equals($winfspMsiHash)) {
|
|
Write-Error -Category InvalidData -CategoryActivity "Data integrity check failed" -Message @"
|
|
Downloaded Winfsp Installer does not match stored SHA256 checksum.
|
|
Expected: $winfspMsiHash
|
|
Actual: $computedHash
|
|
"@
|
|
exit 1
|
|
}
|
|
|
|
# download legacy-winfsp uninstaller
|
|
$winfspUninstaller= 'https://github.com/cryptomator/winfsp-uninstaller/releases/latest/download/winfsp-uninstaller.exe'
|
|
Write-Host "Downloading ${winfspUninstaller}..."
|
|
Invoke-WebRequest $winfspUninstaller -OutFile ".\bundle\resources\winfsp-uninstaller.exe" # redirects are followed by default
|
|
|
|
# copy MSI to bundle resources
|
|
Copy-Item ".\installer\$AppName-*.msi" -Destination ".\bundle\resources\$AppName.msi" -Force
|
|
|
|
# create bundle including winfsp
|
|
Invoke-CommandWithExitCheck -Command `
|
|
"wix" -Arguments @(
|
|
"build",
|
|
"-define", "BundleName=$AppName",
|
|
"-define", "BundleVersion=$semVerNo.$revisionNo",
|
|
"-define", "BundleVendor=$Vendor",
|
|
"-define", "BundleCopyright=$copyright",
|
|
"-define", "AboutUrl=$AboutUrl",
|
|
"-define", "HelpUrl=$HelpUrl",
|
|
"-define", "UpdateUrl=$UpdateUrl",
|
|
"-ext", "WixToolset.Util.wixext",
|
|
"-ext", "WixToolset.BootstrapperApplications.wixext",
|
|
".\bundle\bundleWithWinfsp.wxs",
|
|
"-out", ".\installer\$AppName-Installer.exe"
|
|
)
|
|
|
|
Write-Host "Created EXE installer .\installer\$AppName-Installer.exe"
|
|
return 0;
|
|
}
|
|
|
|
# ============================
|
|
# Script Execution Starts Here
|
|
# ============================
|
|
if ($clean) {
|
|
Write-Host "Cleaning up previous build artifacts..."
|
|
Remove-Item -Path ".\runtime" -Force -Recurse -ErrorAction Ignore -ProgressAction SilentlyContinue
|
|
Remove-Item -Path ".\$AppName" -Force -Recurse -ErrorAction Ignore -ProgressAction SilentlyContinue
|
|
Remove-Item -Path ".\installer" -Force -Recurse -ErrorAction Ignore -ProgressAction SilentlyContinue
|
|
}
|
|
return Main
|
|
|