You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

315 lines
11 KiB

@echo off
setlocal EnableExtensions EnableDelayedExpansion
rem Build and export only the linux/amd64 inspect-nvr application image.
rem The BAT file intentionally contains ASCII only so cmd.exe cannot corrupt
rem UTF-8 comments or messages into executable command fragments.
rem
rem Usage:
rem export-inspect-nvr-amd64.bat
rem export-inspect-nvr-amd64.bat --no-cache
rem export-inspect-nvr-amd64.bat D:\backup\inspect-nvr-app-amd64.tar --no-cache
rem export-inspect-nvr-amd64.bat --preflight
rem export-inspect-nvr-amd64.bat --help
cd /d "%~dp0"
if not exist "%~dp0deploy-package" mkdir "%~dp0deploy-package"
set "IMAGE=inspect-nvr:local"
set "FFMPEG_IMAGE="
set "FFMPEG_DIGEST=sha256:3d1966c91f65f7e7a4ea09203852c8563ef9e48c3ca2cd5e79c8bc80bde02569"
set "OUTPUT=%~dp0deploy-package\inspect-nvr-app-amd64-latest.tar"
set "NO_CACHE=0"
set "PREFLIGHT=0"
set "OLD_CONTAINER_ID="
set "OLD_IMAGE_ID="
set "NEW_IMAGE_ID="
if /I "%~1"=="--help" goto :usage
if /I "%~1"=="--preflight" set "PREFLIGHT=1"
if /I "%~1"=="--no-cache" set "NO_CACHE=1"
if not "%~1"=="" if /I not "%~1"=="--preflight" if /I not "%~1"=="--no-cache" set "OUTPUT=%~1"
if /I "%~2"=="--no-cache" set "NO_CACHE=1"
echo [1/10] Checking Docker...
where docker >nul 2>&1
if errorlevel 1 (
echo [ERROR] Docker was not found. Start Docker Desktop first.
goto :fail
)
docker info >nul 2>&1
if errorlevel 1 (
echo [ERROR] The Docker engine is not running.
goto :fail
)
docker compose version >nul 2>&1
if errorlevel 1 (
echo [ERROR] The docker compose plugin is not available.
goto :fail
)
docker buildx version >nul 2>&1
if errorlevel 1 (
echo [ERROR] Docker Buildx is not available.
goto :fail
)
if not exist "%~dp0docker-compose.yml" (
echo [ERROR] docker-compose.yml was not found in %~dp0
goto :fail
)
rem Compose only needs placeholder ZLM URLs while resolving the build model.
rem Real remote ZLM URLs are still mandatory before the local container starts.
findstr /R /B /C:"ZLM_RTMP_BASE_URL=" "%~dp0.env" >nul 2>&1
if errorlevel 1 (
set "ZLM_RTMP_BASE_URL=rtmp://build-only.invalid:1935"
echo [INFO] ZLM_RTMP_BASE_URL is missing. Using a build-only placeholder.
)
findstr /R /B /C:"ZLM_HTTP_BASE_URL=" "%~dp0.env" >nul 2>&1
if errorlevel 1 (
set "ZLM_HTTP_BASE_URL=http://build-only.invalid:18081"
echo [INFO] ZLM_HTTP_BASE_URL is missing. Using a build-only placeholder.
)
echo [2/10] Checking the FFmpeg base image...
rem Try verified mirrors first. The digest check prevents a mirror from
rem returning content that differs from the official 6.1 manifest.
call :try_ffmpeg_image "docker.1ms.run/mwader/static-ffmpeg:6.1"
call :try_ffmpeg_image "dockerproxy.net/mwader/static-ffmpeg:6.1"
call :try_ffmpeg_image "hub.rat.dev/mwader/static-ffmpeg:6.1"
call :try_ffmpeg_image "registry-1.docker.io/mwader/static-ffmpeg:6.1"
if not defined FFMPEG_IMAGE (
echo [ERROR] No verified FFmpeg registry is reachable.
echo [ERROR] Check Docker Desktop proxy, DNS, or registry connectivity.
goto :fail
)
echo Selected: !FFMPEG_IMAGE!
echo Verified digest: %FFMPEG_DIGEST%
if "!PREFLIGHT!"=="1" (
echo.
echo Preflight passed. No image was removed or built.
endlocal
exit /b 0
)
echo [3/10] Removing the old %IMAGE% image...
rem Read the image from the existing Compose container first. This also finds
rem an untagged image left behind when an earlier build stopped with an error.
for /f "delims=" %%C in ('docker compose ps --all -q inspect-nvr 2^>nul') do set "OLD_CONTAINER_ID=%%C"
if defined OLD_CONTAINER_ID (
for /f "delims=" %%I in ('docker inspect --format "{{.Image}}" "!OLD_CONTAINER_ID!" 2^>nul') do set "OLD_IMAGE_ID=%%I"
)
docker image inspect "%IMAGE%" >nul 2>&1
if errorlevel 1 (
if defined OLD_IMAGE_ID (
echo The running container uses an already untagged old image.
) else (
echo No old image with this name exists.
)
) else (
rem Remember the exact old image so its untagged data can be deleted after
rem Compose replaces the running application container.
if not defined OLD_IMAGE_ID (
for /f "delims=" %%I in ('docker image inspect --format "{{.Id}}" "%IMAGE%" 2^>nul') do set "OLD_IMAGE_ID=%%I"
)
if not defined OLD_IMAGE_ID (
echo [ERROR] Failed to read the old %IMAGE% image ID.
goto :fail
)
rem Force only removes the image tag when a running container still uses
rem the old image ID, so the current container can keep running during build.
docker image rm --force "%IMAGE%"
if errorlevel 1 (
echo [ERROR] Failed to remove the old %IMAGE% image.
goto :fail
)
)
echo [4/10] Building %IMAGE%...
if "!NO_CACHE!"=="1" (
echo Building with --no-cache. The first build can take a while.
docker compose build --no-cache inspect-nvr
) else (
echo Using the build cache. Source or pom.xml changes rebuild the JAR.
docker compose build inspect-nvr
)
if errorlevel 1 (
echo [ERROR] Docker image build failed. Review the Maven or Docker log above.
echo [INFO] An existing running container was not stopped by this script.
goto :fail
)
echo [5/10] Checking the image platform...
docker image inspect "%IMAGE%" >nul 2>&1
if errorlevel 1 (
echo [ERROR] The build finished without creating %IMAGE%.
goto :fail
)
for /f "delims=" %%I in ('docker image inspect --format "{{.Id}}" "%IMAGE%" 2^>nul') do set "NEW_IMAGE_ID=%%I"
if not defined NEW_IMAGE_ID (
echo [ERROR] Failed to read the new %IMAGE% image ID.
goto :fail
)
set "PLATFORM_FILE=%TEMP%\inspect-nvr-platform-%RANDOM%.txt"
docker image inspect --format "{{.Os}}/{{.Architecture}}" "%IMAGE%" > "%PLATFORM_FILE%"
if errorlevel 1 (
echo [ERROR] Failed to read the image platform.
del /f /q "%PLATFORM_FILE%" >nul 2>&1
goto :fail
)
set "PLATFORM="
set /p PLATFORM=<"%PLATFORM_FILE%"
del /f /q "%PLATFORM_FILE%" >nul 2>&1
if /I not "!PLATFORM!"=="linux/amd64" (
echo [ERROR] Image platform is !PLATFORM!, expected linux/amd64.
goto :fail
)
echo Platform confirmed: !PLATFORM!
if exist "%OUTPUT%" (
echo [INFO] Output file already exists: %OUTPUT%
choice /C YN /N /M "Overwrite it? [Y/N]"
if errorlevel 2 (
echo Cancelled.
goto :fail
)
del /f /q "%OUTPUT%" >nul 2>&1
)
if exist "%OUTPUT%.sha256" del /f /q "%OUTPUT%.sha256" >nul 2>&1
echo [6/10] Exporting the application image...
docker save -o "%OUTPUT%" "%IMAGE%"
if errorlevel 1 (
echo [ERROR] docker save failed. The output file may be in use.
goto :fail
)
echo [7/10] Checking the tar contents...
where tar >nul 2>&1
if not errorlevel 1 (
tar -xOf "%OUTPUT%" manifest.json | findstr /I /C:"zlmediakit" >nul
if not errorlevel 1 (
echo [ERROR] ZLMediaKit was found in the application tar.
goto :fail
)
echo ZLMediaKit is not present in the tar.
) else (
echo [INFO] tar was not found. docker save only exported %IMAGE%.
)
echo [8/10] Generating the SHA256 file...
where powershell >nul 2>&1
if errorlevel 1 (
echo [ERROR] PowerShell was not found.
goto :fail
)
set "HASH_FILE=%OUTPUT%.sha256"
rem Use .NET directly because Windows PowerShell launched through cmd.exe can
rem inherit PowerShell 7 module paths and then fail to autoload Get-FileHash.
powershell -NoProfile -ExecutionPolicy Bypass -Command "$ErrorActionPreference='Stop'; try { $stream=[IO.File]::OpenRead($env:OUTPUT); try { $sha=[Security.Cryptography.SHA256]::Create(); try { $hash=([BitConverter]::ToString($sha.ComputeHash($stream))).Replace('-','').ToLowerInvariant() } finally { if ($null -ne $sha) { $sha.Dispose() } } } finally { if ($null -ne $stream) { $stream.Dispose() } }; if ($hash.Length -ne 64) { throw 'Unexpected SHA256 length.' }; $name=[IO.Path]::GetFileName($env:OUTPUT); [IO.File]::WriteAllText($env:HASH_FILE, ($hash + ' ' + $name + [char]10), [Text.Encoding]::ASCII) } catch { [Console]::Error.WriteLine($_.Exception.Message); exit 1 }"
if errorlevel 1 (
echo [ERROR] SHA256 generation failed.
goto :fail
)
set "HASH="
set /p HASH=<"%HASH_FILE%"
echo [9/10] Recreating the local application container...
rem Build placeholders must never be used when the application starts.
findstr /R /B /C:"ZLM_RTMP_BASE_URL=" "%~dp0.env" >nul 2>&1
if errorlevel 1 (
echo [ERROR] The image was built and exported, but the container was not recreated.
echo [ERROR] Set a real ZLM_RTMP_BASE_URL in .env and run Compose again.
goto :fail
)
findstr /R /B /C:"ZLM_HTTP_BASE_URL=" "%~dp0.env" >nul 2>&1
if errorlevel 1 (
echo [ERROR] The image was built and exported, but the container was not recreated.
echo [ERROR] Set a real ZLM_HTTP_BASE_URL in .env and run Compose again.
goto :fail
)
docker compose up -d --force-recreate --no-build inspect-nvr
if errorlevel 1 (
echo [ERROR] The image was exported, but the local container recreate failed.
goto :fail
)
echo [10/10] Releasing the previous application image...
if not defined OLD_IMAGE_ID (
echo No previous image data needs cleanup.
) else if /I "!OLD_IMAGE_ID!"=="!NEW_IMAGE_ID!" (
rem An unchanged cached build can reproduce the same image ID. That ID now
rem belongs to the new tag and container, so there is no duplicate to delete.
echo The rebuilt image reused the same image ID. No duplicate remains.
) else (
rem The old Compose container is gone, so deleting its exact image ID frees
rem only obsolete inspect-nvr layers and leaves other project images intact.
docker image rm "!OLD_IMAGE_ID!"
if errorlevel 1 (
echo [WARN] The previous image is still used by another container.
echo [WARN] Docker kept it to avoid breaking that container.
) else (
echo Previous image data released: !OLD_IMAGE_ID!
)
)
echo.
echo Export completed:
echo Image: %IMAGE%
echo File: %OUTPUT%
echo Hash: %HASH_FILE%
echo SHA256: !HASH!
echo Local container: recreated with the new image
echo.
echo Ubuntu import command:
echo sudo docker load -i inspect-nvr-app-amd64-latest.tar
echo.
echo For a clean rebuild:
echo export-inspect-nvr-amd64.bat --no-cache
echo.
pause
endlocal
exit /b 0
:usage
echo Usage:
echo export-inspect-nvr-amd64.bat
echo export-inspect-nvr-amd64.bat --no-cache
echo export-inspect-nvr-amd64.bat OUTPUT_FILE [--no-cache]
echo export-inspect-nvr-amd64.bat --preflight
endlocal
exit /b 0
:try_ffmpeg_image
if defined FFMPEG_IMAGE exit /b 0
set "FFMPEG_CANDIDATE=%~1"
set "FFMPEG_CHECK_FILE=%TEMP%\inspect-nvr-ffmpeg-%RANDOM%.txt"
echo Trying !FFMPEG_CANDIDATE!...
docker buildx imagetools inspect "!FFMPEG_CANDIDATE!" >"!FFMPEG_CHECK_FILE!" 2>&1
if errorlevel 1 (
echo Unavailable.
del /f /q "!FFMPEG_CHECK_FILE!" >nul 2>&1
exit /b 0
)
findstr /L /C:"!FFMPEG_DIGEST!" "!FFMPEG_CHECK_FILE!" >nul 2>&1
if errorlevel 1 (
echo Rejected because the manifest digest does not match.
del /f /q "!FFMPEG_CHECK_FILE!" >nul 2>&1
exit /b 0
)
del /f /q "!FFMPEG_CHECK_FILE!" >nul 2>&1
set "FFMPEG_IMAGE=!FFMPEG_CANDIDATE!"
echo Available and digest verified.
exit /b 0
:fail
echo.
echo Script stopped. Press any key to close this window.
pause >nul
endlocal
exit /b 1