diff --git a/pom.xml b/pom.xml index 14abc6f..c254920 100644 --- a/pom.xml +++ b/pom.xml @@ -262,7 +262,7 @@ windows-package - Windows + windows.package diff --git a/scripts/build_release.bat b/scripts/build_release.bat index f85edf1..70e3655 100644 --- a/scripts/build_release.bat +++ b/scripts/build_release.bat @@ -1,249 +1,119 @@ @echo off chcp 65001 >nul -setlocal enabledelayedexpansion +setlocal EnableExtensions EnableDelayedExpansion -:: ============================================ -:: WorkUtils 生产打包脚本(免安装版) -:: 输出:target\dist\workutils-v{version}.zip -:: (含 exe + 内嵌JRE + jar + 启动脚本) -:: ============================================ - -:: 切换到项目根目录 cd /d "%~dp0.." set "PROJECT_DIR=%CD%" set "TARGET=%PROJECT_DIR%\target" set "DIST=%TARGET%\dist" +set "RELEASE_DIR=%DIST%\workutils" +set "BUILD_JDK=" + +echo. +echo ========== WorkUtils Windows portable release ========== +echo Project: %PROJECT_DIR% + +call :try_jdk "%JDK17_HOME%" +call :try_jdk "%JAVA_HOME%" +call :try_jdk "C:\Program Files\Java\jdk-17" +call :try_jdk "C:\Program Files\Eclipse Adoptium\jdk-17" + +if not defined BUILD_JDK ( + echo [ERROR] A JDK 17 or newer with jlink.exe is required to build the release. + echo Set JAVA_HOME or JDK17_HOME to a valid JDK directory. + pause + exit /b 1 +) + +set "JAVA_HOME=%BUILD_JDK%" +set "PATH=%JAVA_HOME%\bin;%PATH%" +echo Build JDK: %JAVA_HOME% + +echo. +echo [1/5] Build and test executable JAR... +call "%PROJECT_DIR%\mvnw.cmd" clean package +if errorlevel 1 goto :build_failed + +echo. +echo [2/5] Read project version... set "VERSION=" - -echo. -echo ========== WorkUtils 生产构建 ========== -echo 项目目录: %PROJECT_DIR% -echo. - -:: ============================================================ -:: 步骤 1:清理残留进程 & 解锁删除旧产物 -:: ============================================================ -echo [1/5] Clean stale processes and files... -taskkill /f /im java.exe 2>nul -taskkill /f /im workutils.exe 2>nul -:: 等进程完全退出,文件锁释放 -echo 等待进程退出... -ping 127.0.0.1 -n 4 >nul - -:: --- 清理 target/dist --- -if exist "%TARGET%" ( - :: 策略1:直接 rd(文件锁已释放时应成功) - rd /s /q "%TARGET%" 2>nul - :: 策略2:如果 rd 失败,改名后重建 - if exist "%TARGET%" ( - echo [WARN] 直接删除失败,尝试改名清理... - :: 先删 dist/ 子目录的文件(规避 JRE 文件锁) - if exist "%DIST%" ( - del /f /s /q "%DIST%\*" 2>nul - rd /s /q "%DIST%" 2>nul - ) - :: 再删 jre/ - if exist "%TARGET%\jre" ( - del /f /s /q "%TARGET%\jre\*" 2>nul - rd /s /q "%TARGET%\jre" 2>nul - ) - :: 删 target/ 下其余文件 - del /f /s /q "%TARGET%\*" 2>nul - for /d %%d in ("%TARGET%\*") do rd /s /q "%%d" 2>nul - rd /s /q "%TARGET%" 2>nul - ) - :: 策略3:改名旧目录,让后续步骤创建新的 - if exist "%TARGET%" ( - for /f "tokens=2 delims==" %%I in ('wmic os get localdatetime /value') do set "TS=%%I" - set "OLD_TARGET=%PROJECT_DIR%\target_old_!TS:~0,14!" - echo [WARN] 无法删除,重命名为 !OLD_TARGET! ... - move "%TARGET%" "!OLD_TARGET!" >nul 2>&1 - if exist "!OLD_TARGET!" ( - echo [INFO] 旧产物已移至 !OLD_TARGET!,稍后请手动删除 - ) - ) -) - -:: ============================================================ -:: 步骤 2:Maven 打包 -:: ============================================================ -echo. -echo [2/5] Maven build... -call "%PROJECT_DIR%\mvnw.cmd" package -DskipTests -q -if %errorlevel% neq 0 ( - echo [ERROR] Maven build failed! - pause - exit /b 1 -) - -:: ============================================================ -:: 步骤 3:提取版本号 -:: ============================================================ -echo. -echo [3/5] Read version from pom.xml... for /f "usebackq delims=" %%a in (`powershell -NoProfile -NonInteractive -Command "([xml](Get-Content -Encoding UTF8 '%PROJECT_DIR%\pom.xml')).project.version"`) do set "VERSION=%%a" -if "%VERSION%"=="" set "VERSION=0.0.1-SNAPSHOT" -echo 版本: %VERSION% - -:: ============================================================ -:: 步骤 4:生成精简 JRE(jlink 内嵌 Java 17 + JavaFX) -:: ============================================================ -echo. -echo [4/5] Generate bundled JRE... - -:: 4.1 查找 JDK 17 -if not defined JDK17_HOME ( - for %%d in ( - "C:\Program Files\Java\jdk-17" - "C:\Program Files\Eclipse Adoptium\jdk-17.0.0.35-hotspot" - "C:\Program Files\Java\jdk-17.0.14" - "%JAVA_HOME%" - ) do ( - if exist "%%~d\bin\jlink.exe" ( - set "JDK17_HOME=%%~d" - goto :jdk17_found - ) - ) - echo [ERROR] Cannot find JDK 17 with jlink.exe - echo Please set JDK17_HOME environment variable - pause & exit /b 1 -) -:jdk17_found - -:: 4.2 查找 JavaFX SDK -if not defined JFX_SDK_HOME ( - for %%d in ( - "C:\Program Files\Java\javafx-sdk-17.0.15" - "C:\Program Files\Java\javafx-sdk-17.0.14" - "C:\Program Files\Java\javafx-sdk-17" - ) do ( - if exist "%%~d\lib\javafx.base.jar" ( - set "JFX_SDK_HOME=%%~d" - goto :jfx_found - ) - ) - echo [ERROR] Cannot find JavaFX SDK - echo Please set JFX_SDK_HOME environment variable - pause & exit /b 1 -) -:jfx_found - -echo JDK : %JDK17_HOME% -echo JavaFX: %JFX_SDK_HOME% - -:: 4.3 清理旧 JRE -if exist "%TARGET%\jre" rd /s /q "%TARGET%\jre" 2>nul - -:: 4.4 执行 jlink -echo Running jlink, please wait... -"%JDK17_HOME%\bin\jlink.exe" ^ - --module-path "%JFX_SDK_HOME%\lib;%JDK17_HOME%\jmods" ^ - --add-modules java.base,java.desktop,java.logging,java.management,java.naming,java.sql,java.xml,java.xml.crypto,java.instrument,java.security.jgss,java.security.sasl,jdk.unsupported,jdk.management,java.scripting,jdk.crypto.ec,java.net.http,javafx.base,javafx.controls,javafx.fxml,javafx.graphics,javafx.web,javafx.swing ^ - --output "%TARGET%\jre" ^ - --strip-debug --no-header-files --no-man-pages --compress=2 - -if %errorlevel% neq 0 ( - echo [ERROR] jlink failed! +if not defined VERSION ( + echo [ERROR] Unable to read the project version from pom.xml. pause exit /b 1 ) - -:: 4.5 补充 JavaFX 原生 DLL -echo Copy JavaFX native DLLs... -if exist "%JFX_SDK_HOME%\bin\glass.dll" ( - xcopy /y /q "%JFX_SDK_HOME%\bin\*.dll" "%TARGET%\jre\bin\" >nul - echo [OK] JavaFX DLLs copied -) else ( - echo [WARN] No JavaFX DLLs found in %JFX_SDK_HOME%\bin +set "JAR_NAME=workutils-%VERSION%.jar" +set "JAR_PATH=%TARGET%\%JAR_NAME%" +if not exist "%JAR_PATH%" ( + echo [ERROR] Executable JAR not found: %JAR_PATH% + pause + exit /b 1 ) +echo Version: %VERSION% -echo [OK] JRE generated : %TARGET%\jre - -:: ============================================================ -:: 步骤 5:组装发布目录 & 打包 ZIP -:: ============================================================ echo. -echo [5/5] Assemble distribution... +echo [3/5] Assemble release directory... +if exist "%DIST%" rd /s /q "%DIST%" +mkdir "%RELEASE_DIR%" || goto :build_failed +copy /y "%JAR_PATH%" "%RELEASE_DIR%\%JAR_NAME%" >nul || goto :build_failed +powershell -NoProfile -NonInteractive -Command ^ + "$text = Get-Content -Raw -Encoding UTF8 '%PROJECT_DIR%\scripts\start-release.bat';" ^ + "$text = $text.Replace('@APP_JAR@', '%JAR_NAME%');" ^ + "[IO.File]::WriteAllText('%RELEASE_DIR%\start.bat', $text, [Text.UTF8Encoding]::new($false))" +if errorlevel 1 goto :build_failed -:: 清理旧发布目录 -if exist "%DIST%" ( - del /f /s /q "%DIST%\*" 2>nul - for /d %%d in ("%DIST%\*") do rd /s /q "%%d" 2>nul - rd /s /q "%DIST%" 2>nul -) -mkdir "%DIST%\workutils" 2>nul +echo. +echo [4/5] Generate bundled Java runtime... +"%JAVA_HOME%\bin\jlink.exe" ^ + --module-path "%JAVA_HOME%\jmods" ^ + --add-modules ALL-MODULE-PATH ^ + --bind-services ^ + --strip-debug ^ + --no-header-files ^ + --no-man-pages ^ + --compress=2 ^ + --output "%RELEASE_DIR%\runtime" +if errorlevel 1 goto :build_failed -:: 复制 EXE -if exist "%TARGET%\workutils.exe" ( - copy /y "%TARGET%\workutils.exe" "%DIST%\workutils\" >nul - echo [OK] workutils.exe -) else ( - echo [WARN] workutils.exe not found! -) +"%RELEASE_DIR%\runtime\bin\java.exe" -version +if errorlevel 1 goto :build_failed -:: 复制 JAR -for %%j in ("%TARGET%\workutils-*.jar") do ( - copy /y "%%j" "%DIST%\workutils\" >nul - echo [OK] %%~nxj -) +echo. +echo [5/5] Create portable ZIP... +set "ZIP_PATH=%DIST%\workutils-v%VERSION%-windows.zip" +powershell -NoProfile -NonInteractive -Command ^ + "Compress-Archive -Path '%RELEASE_DIR%' -DestinationPath '%ZIP_PATH%' -Force" +if errorlevel 1 goto :build_failed -:: 复制内嵌 JRE -if exist "%TARGET%\jre\bin\java.exe" ( - echo 复制内嵌 JRE... - xcopy /e /i /q "%TARGET%\jre" "%DIST%\workutils\jre\" >nul - echo [OK] jre/ ^(bundled Java 17 + JavaFX^) -) else ( - echo [WARN] jre not found in target! -) - -:: ============================================================ -:: 生成 start.bat -:: ============================================================ -( - echo @echo off - echo chcp 65001 ^>nul - echo title WorkUtils - echo. - echo :: 优先用内嵌 JRE,否则查系统 Java 17+ - echo set "JAVA_BIN=%%~dp0jre\bin\java.exe" - echo if exist "%%JAVA_BIN%%" goto :run - echo. - echo set "JAVA_BIN=java" - echo for /f "tokens=3" %%%%v in ^('"%%JAVA_BIN%%" -version 2^>^&1 ^| findstr /i "version"'^) do set "JAVA_VER=%%%%~v" - echo for /f "tokens=1 delims=." %%%%m in ^("%%JAVA_VER%%"^) do set "MAJOR=%%%%m" - echo if "%%MAJOR%%"=="1" for /f "tokens=2 delims=." %%%%m in ^("%%JAVA_VER%%"^) do set "MAJOR=%%%%m" - echo if %%MAJOR%% LSS 17 ^( - echo echo [ERROR] Java %%JAVA_VER%% found. WorkUtils requires Java 17+. - echo echo Download JDK 17+ from https://adoptium.net/ - echo pause ^& exit /b 1 - echo ^) - echo. - echo :run - echo "%%JAVA_BIN%%" -jar "%%~dp0workutils-%VERSION%.jar" %%* - echo if %%errorlevel%% neq 0 pause -) > "%DIST%\workutils\start.bat" -echo [OK] start.bat - -:: ============================================================ -:: 打包 ZIP -:: ============================================================ -set "ZIPNAME=workutils-v%VERSION%" -echo 正在压缩 %ZIPNAME%.zip ... -powershell -Command ^ - "Compress-Archive -Path '%DIST%\workutils' -DestinationPath '%DIST%\%ZIPNAME%.zip' -Force" -echo [OK] %ZIPNAME%.zip - -:: ============================================================ -:: 完成 -:: ============================================================ echo. echo ============================================ -echo Build Complete ^! v%VERSION% +echo Build complete. The recipient needs no Java installation. +echo Directory: %RELEASE_DIR% +echo ZIP: %ZIP_PATH% echo ============================================ -echo Output: -echo %DIST%\workutils\ -echo %DIST%\%ZIPNAME%.zip -echo ============================================ -echo. -pause exit /b 0 + +:try_jdk +if defined BUILD_JDK exit /b 0 +set "CANDIDATE=%~1" +if not defined CANDIDATE exit /b 0 +if not exist "!CANDIDATE!\bin\java.exe" exit /b 0 +if not exist "!CANDIDATE!\bin\jlink.exe" exit /b 0 +set "CANDIDATE_VERSION=" +set "VERSION_FILE=%TEMP%\workutils-java-version-!RANDOM!.txt" +"!CANDIDATE!\bin\java.exe" -version > "!VERSION_FILE!" 2>&1 +for /f "tokens=3" %%v in ('findstr /i "version" "!VERSION_FILE!"') do set "CANDIDATE_VERSION=%%~v" +del /q "!VERSION_FILE!" >nul 2>&1 +set "CANDIDATE_MAJOR=" +for /f "tokens=1 delims=." %%m in ("!CANDIDATE_VERSION!") do set "CANDIDATE_MAJOR=%%m" +if "!CANDIDATE_MAJOR!"=="1" for /f "tokens=2 delims=." %%m in ("!CANDIDATE_VERSION!") do set "CANDIDATE_MAJOR=%%m" +if not defined CANDIDATE_MAJOR exit /b 0 +if !CANDIDATE_MAJOR! GEQ 17 set "BUILD_JDK=!CANDIDATE!" +exit /b 0 + +:build_failed +echo. +echo [ERROR] Windows portable release build failed. +pause +exit /b 1 diff --git a/scripts/start-release.bat b/scripts/start-release.bat new file mode 100644 index 0000000..f02d3cf --- /dev/null +++ b/scripts/start-release.bat @@ -0,0 +1,21 @@ +@echo off +chcp 65001 >nul +setlocal +cd /d "%~dp0" + +set "JAVA_BIN=%~dp0runtime\bin\java.exe" +set "APP_JAR=%~dp0@APP_JAR@" + +if not exist "%JAVA_BIN%" ( + echo [ERROR] Bundled Java runtime is missing: %JAVA_BIN% + pause + exit /b 1 +) +if not exist "%APP_JAR%" ( + echo [ERROR] WorkUtils JAR is missing: %APP_JAR% + pause + exit /b 1 +) + +"%JAVA_BIN%" -Dfile.encoding=UTF-8 "-Dworkutils.home=%~dp0" -jar "%APP_JAR%" %* +if errorlevel 1 pause diff --git a/src/test/java/com/example/workutils/system/support/BuildPortabilityTest.java b/src/test/java/com/example/workutils/system/support/BuildPortabilityTest.java index 1443860..10f6d73 100644 --- a/src/test/java/com/example/workutils/system/support/BuildPortabilityTest.java +++ b/src/test/java/com/example/workutils/system/support/BuildPortabilityTest.java @@ -30,13 +30,14 @@ class BuildPortabilityTest { } @Test - void launch4jOnlyBelongsToTheWindowsProfile() throws Exception { + void launch4jRequiresAnExplicitWindowsPackageProfile() throws Exception { Document pom = parsePom(); Element project = element(pom, "project"); assertFalse(hasPlugin(directChild(project, "build"), "launch4j-maven-plugin")); Element windowsProfile = profile(project, "windows-package"); - assertEquals("Windows", childText(directChild(directChild(windowsProfile, "activation"), "os"), "family")); + Element property = directChild(directChild(windowsProfile, "activation"), "property"); + assertEquals("windows.package", childText(property, "name")); assertTrue(hasPlugin(directChild(windowsProfile, "build"), "launch4j-maven-plugin")); }