@ECHO off SETLOCAL SET WD=%CD% SET "BUILDROOT=%WD%\win-build" SET "TMPDIR=%WD%\win-temp" SET "DISTROOT=%WD%\dist" SET CMDOPTIONS="" IF "%1" == "clean" SET CMDOPTIONS="VALID" IF "%1" == "" SET CMDOPTIONS="VALID" IF NOT %CMDOPTIONS%=="VALID" ( GOTO USAGE ) IF "%1" == "clean" ( CALL :CLEAN EXIT /B %ERRORLEVEL% ) REM Main build sequence CALL :SET_ENVIRONMENT CALL :VALIDATE_ENVIRONMENT || EXIT /B 1 CALL :CLEAN || EXIT /B 1 CALL :CREATE_VIRTUAL_ENV || EXIT /B 1 CALL :CREATE_PYTHON_ENV || EXIT /B 1 CALL :CREATE_RUNTIME_ENV || EXIT /B 1 CALL :GENERATE_SBOM || EXIT /B 1 CALL :CREATE_INSTALLER || EXIT /B 1 CALL :SIGN_INSTALLER || EXIT /B 1 EXIT /B %ERRORLEVEL% REM Main build sequence Ends :CLEAN ECHO Removing build directory... IF EXIST "%BUILDROOT%" RD "%BUILDROOT%" /S /Q > nul || EXIT /B 1 ECHO Removing tmp directory... IF EXIST "%TMPDIR%" RD "%TMPDIR%" /S /Q > nul || EXIT /B 1 ECHO Removing installer build directory... IF EXIST "%WD%\pkg\win32\Output" rd "%WD%\pkg\win32\Output" /S /Q > nul || EXIT /B 1 ECHO Removing installer configuration script... IF EXIST DEL /q "%WD%\pkg\win32\installer.iss" > nul || EXIT /B 1 EXIT /B 0 :SET_ENVIRONMENT ECHO Configuring the environment... IF "%PGADMIN_PYTHON_DIR%" == "" SET "PGADMIN_PYTHON_DIR=C:\Python38" IF "%PGADMIN_KRB5_DIR%" == "" SET "PGADMIN_KRB5_DIR=C:\Program Files\MIT\Kerberos" IF "%PGADMIN_POSTGRES_DIR%" == "" SET "PGADMIN_POSTGRES_DIR=C:\Program Files (x86)\PostgreSQL\12" IF "%PGADMIN_INNOTOOL_DIR%" == "" SET "PGADMIN_INNOTOOL_DIR=C:\Program Files (x86)\Inno Setup 6" IF "%PGADMIN_VCREDIST_DIR%" == "" SET "PGADMIN_VCREDIST_DIR=C:\Program Files (x86)\Microsoft Visual Studio\2017\Professional\VC\Redist\MSVC\14.16.27012" IF "%PGADMIN_SIGNTOOL_DIR%" == "" SET "PGADMIN_SIGNTOOL_DIR=C:\Program Files (x86)\Windows Kits\10\bin\10.0.17763.0\x64" REM Set REDIST_NAME (the filename) set "VCREDIST_FILE=vcredist_x64.exe" REM Set additional variables we need FOR /F "tokens=3" %%a IN ('findstr /C:"APP_RELEASE =" %WD%\web\version.py') DO SET APP_MAJOR=%%a FOR /F "tokens=3" %%a IN ('findstr /C:"APP_REVISION =" %WD%\web\version.py') DO SET APP_MINOR=%%a FOR /F "tokens=3" %%a IN ('findstr /C:"APP_SUFFIX =" %WD%\web\version.py') DO SET APP_VERSION_SUFFIX=%%a REM remove single quote from the string SET APP_VERSION_SUFFIX=%APP_VERSION_SUFFIX:'=% SET APP_NAME="" FOR /F "tokens=2* DELims='" %%a IN ('findstr /C:"APP_NAME =" web\branding.py') DO SET APP_NAME=%%a FOR /f "tokens=1 DELims=." %%G IN ('%PGADMIN_PYTHON_DIR%/python.exe -c "print('%APP_NAME%'.lower().replace(' ', ''))"') DO SET APP_SHORTNAME=%%G SET APP_VERSION=%APP_MAJOR%.%APP_MINOR% SET INSTALLERNAME=%APP_SHORTNAME%-%APP_MAJOR%.%APP_MINOR%-%APP_VERSION_SUFFIX%-x64.exe IF "%APP_VERSION_SUFFIX%" == "" SET INSTALLERNAME=%APP_SHORTNAME%-%APP_MAJOR%.%APP_MINOR%-x64.exe REM get Python version for the runtime build ex. 3.9.2 will be 39 FOR /f "tokens=1 DELims=." %%G IN ('%PGADMIN_PYTHON_DIR%/python.exe -c "import sys; print(sys.version.split(' ')[0])"') DO SET PYTHON_MAJOR=%%G FOR /f "tokens=2 DELims=." %%G IN ('%PGADMIN_PYTHON_DIR%/python.exe -c "import sys; print(sys.version.split(' ')[0])"') DO SET PYTHON_MINOR=%%G FOR /f "tokens=3 DELims=." %%G IN ('%PGADMIN_PYTHON_DIR%/python.exe -c "import sys; print(sys.version.split(' ')[0])"') DO SET PYTHON_REVISION=%%G EXIT /B 0 :VALIDATE_ENVIRONMENT ECHO **************************************************************** ECHO * Build summary ECHO **************************************************************** ECHO Build path: %BUILDROOT% ECHO Output directory: %DISTROOT% ECHO Installer name: %INSTALLERNAME% ECHO. ECHO Python directory: %PGADMIN_PYTHON_DIR% ECHO Python version: %PYTHON_MAJOR%.%PYTHON_MINOR%.%PYTHON_REVISION% ECHO. ECHO KRB5 directory: %PGADMIN_KRB5_DIR% ECHO PostgreSQL directory: %PGADMIN_POSTGRES_DIR% ECHO. ECHO VC++ redist directory: %PGADMIN_VCREDIST_DIR% ECHO VC++ redist file: %VCREDIST_FILE% ECHO InnoTool directory: %PGADMIN_INNOTOOL_DIR% ECHO signtool directory: %PGADMIN_SIGNTOOL_DIR% ECHO. ECHO App version: %APP_VERSION% ECHO App version suffix: %APP_VERSION_SUFFIX% ECHO App short name: %APP_SHORTNAME% ECHO App name: %APP_NAME% ECHO **************************************************************** ECHO Checking the environment... IF NOT EXIST "%PGADMIN_INNOTOOL_DIR%" ( ECHO !PGADMIN_INNOTOOL_DIR! does not exist ECHO Please install InnoTool and set the PGADMIN_INNOTOOL_DIR environment variable. EXIT /B 1 ) IF NOT EXIST "%PGADMIN_VCREDIST_DIR%" ( ECHO !PGADMIN_VCREDIST_DIR! does not exist ECHO Please install Microsoft Visual studio and set the PGADMIN_VCREDIST_DIR environment variable. EXIT /B 1 ) IF NOT EXIST "%PGADMIN_KRB5_DIR%" ( ECHO !PGADMIN_KRB5_DIR! does not exist. ECHO Please install MIT Kerberos for Windows and set the PGADMIN_KRB5_DIR environment variable. EXIT /B 1 ) IF NOT EXIST "%PGADMIN_PYTHON_DIR%" ( ECHO !PGADMIN_PYTHON_DIR! does not exist. ECHO Please install Python and set the PGADMIN_PYTHON_DIR environment variable. EXIT /B 1 ) IF NOT EXIST "%PGADMIN_POSTGRES_DIR%" ( ECHO !PGADMIN_POSTGRES_DIR! does not exist. ECHO Please install PostgreSQL and set the PGADMIN_POSTGRES_DIR environment variable. EXIT /B 1 ) IF NOT EXIST "%PGADMIN_PYTHON_DIR%\Scripts\virtualenv.exe" ( ECHO !PGADMIN_PYTHON_DIR!\Scripts\virtualenv.exe does not exist. ECHO Please install the virtualenv package in Python. EXIT /B 1 ) SET "PATH=%PGADMIN_POSTGRES_DIR%\bin;%PATH%" EXIT /B 0 :CREATE_VIRTUAL_ENV ECHO Creating virtual environment... IF NOT EXIST "%TMPDIR%" MKDIR "%TMPDIR%" CD "%TMPDIR%" REM Note that we must use virtualenv.exe here, as the venv module doesn't allow python.exe to relocate. "%PGADMIN_PYTHON_DIR%\Scripts\virtualenv.exe" venv XCOPY /S /I /E /H /Y "%PGADMIN_PYTHON_DIR%\DLLs" "%TMPDIR%\venv\DLLs" > nul || EXIT /B 1 XCOPY /S /I /E /H /Y "%PGADMIN_PYTHON_DIR%\Lib" "%TMPDIR%\venv\Lib" > nul || EXIT /B 1 ECHO Activating virtual environment - %TMPDIR%\venv... CALL "%TMPDIR%\venv\Scripts\activate" || EXIT /B 1 ECHO Installing dependencies... CALL python -m pip install --upgrade pip || EXIT /B 1 CALL pip install --only-binary=cryptography -r "%WD%\requirements.txt" || EXIT /B 1 CD %WD% EXIT /B 0 :CREATE_PYTHON_ENV ECHO Staging Python... MKDIR "%BUILDROOT%\python\Lib" || EXIT /B 1 ECHO Downloading embedded Python... REM Get the python embeddable and extract it to %BUILDROOT%\python CD "%TMPDIR% %PGADMIN_PYTHON_DIR%\python -c "import sys; from urllib.request import urlretrieve; urlretrieve('https://www.python.org/ftp/python/' + sys.version.split(' ')[0] + '/python-' + sys.version.split(' ')[0] + '-embed-amd64.zip', 'python-embedded.zip')" || EXIT /B 1 %PGADMIN_PYTHON_DIR%\python -c "import zipfile; z = zipfile.ZipFile('python-embedded.zip', 'r'); z.extractall('../win-build/python/')" || EXIT /B 1 ECHO Copying site-packages... XCOPY /S /I /E /H /Y "%TMPDIR%\venv\Lib\site-packages" "%BUILDROOT%\python\Lib\site-packages" > nul || EXIT /B 1 REM NOTE: There is intentionally no space after "site" in the line below, to prevent Python barfing if there's one in the file ECHO import site>> "%BUILDROOT%\python\python%PYTHON_MAJOR%%PYTHON_MINOR%._pth" ECHO Staging Kerberos components... COPY "%PGADMIN_KRB5_DIR%\bin\kinit.exe" "%BUILDROOT%\python" > nul || EXIT /B 1 COPY "%PGADMIN_KRB5_DIR%\bin\krb5_64.dll" "%BUILDROOT%\python" > nul || EXIT /B 1 COPY "%PGADMIN_KRB5_DIR%\bin\comerr64.dll" "%BUILDROOT%\python" > nul || EXIT /B 1 COPY "%PGADMIN_KRB5_DIR%\bin\k5sprt64.dll" "%BUILDROOT%\python" > nul || EXIT /B 1 COPY "%PGADMIN_KRB5_DIR%\bin\gssapi64.dll" "%BUILDROOT%\python" > nul || EXIT /B 1 ECHO Cleaning up unnecessary .pyc and .pyo files... FOR /R "%BUILDROOT%\python" %%f in (*.pyc *.pyo) do DEL /q "%%f" 1> nul 2>&1 ECHO Removing tests... FOR /R "%BUILDROOT%\python\Lib" %%f in (test tests) do RD /Q /S "%%f" 1> nul 2>&1 EXIT /B 0 :CREATE_RUNTIME_ENV IF NOT EXIST "%BUILDROOT%" MKDIR "%BUILDROOT%" MKDIR "%BUILDROOT%\runtime" ECHO Removing webpack caches... RD /Q /S "%WD%\web\pgadmin\static\js\generated\.cache" 1> nul 2>&1 ECHO Copying web directory... ROBOCOPY /S "%WD%\web" "%BUILDROOT%\web" > nul CALL :CHECK_ROBOCOPY_ERROR ECHO Installing javascript dependencies... CD "%BUILDROOT%\web" CALL yarn install || EXIT /B 1 CALL npm rebuild || EXIT /B 1 ECHO Bundling javascript... CALL yarn run bundle || EXIT /B 1 ECHO Cleaning up unnecessary .pyc and .pyo files... FOR /R "%BUILDROOT%\web" %%f in (*.pyc *.pyo) do DEL /q "%%f" 1> nul 2>&1 ECHO Removing tests, Python caches and node modules... FOR /R "%BUILDROOT%\web" %%f in (tests feature_tests __pycache__ node_modules) do RD /Q /S "%%f" 1> nul 2>&1 ECHO Removing the test framework... RD /Q /S "%BUILDROOT%\web\regression" 1> nul 2>&1 ECHO Removing tools... RD /Q /S "%BUILDROOT%\web\tools" 1> nul 2>&1 ECHO Removing any existing configurations... DEL /q "%BUILDROOT%\web\pgadmin4.db" 1> nul 2>&1 DEL /q "%BUILDROOT%\web\config_local.py" 1> nul 2>&1 ECHO Staging license files... COPY "%WD%\LICENSE" "%BUILDROOT%\" > nul || EXIT /B 1 COPY "%WD%\DEPENDENCIES" "%BUILDROOT%\" > nul || EXIT /B 1 ECHO Creating config_distro.py ECHO SERVER_MODE = False > "%BUILDROOT%\web\config_distro.py" ECHO HELP_PATH = '../../../docs/en_US/html/' >> "%BUILDROOT%\web\config_distro.py" ECHO DEFAULT_BINARY_PATHS = { >> "%BUILDROOT%\web\config_distro.py" ECHO 'pg': '$DIR/../runtime', >> "%BUILDROOT%\web\config_distro.py" ECHO 'ppas': '' >> "%BUILDROOT%\web\config_distro.py" ECHO } >> "%BUILDROOT%\web\config_distro.py" ECHO Building docs... CALL pip install sphinx || EXIT /B 1 CALL pip install sphinxcontrib-youtube || EXIT /B 1 MKDIR "%BUILDROOT%\docs\en_US\html" CD "%WD%\docs\en_US" CALL "%TMPDIR%\venv\Scripts\python.exe" build_code_snippet.py || EXIT /B 1 CALL "%TMPDIR%\venv\Scripts\sphinx-build.exe" "%WD%\docs\en_US" "%BUILDROOT%\docs\en_US\html" || EXIT /B 1 REM Remove unnecessary doc files DEL /q "%BUILDROOT%\docs\en_US\html\_static\*.png" 1> nul 2>&1 RD /Q /S "%BUILDROOT%\docs\en_US\html\_sources" 1> nul 2>&1 ECHO Staging runtime components... XCOPY /S /I /E /H /Y "%WD%\runtime\assets" "%BUILDROOT%\runtime\assets" > nul || EXIT /B 1 XCOPY /S /I /E /H /Y "%WD%\runtime\src" "%BUILDROOT%\runtime\src" > nul || EXIT /B 1 COPY "%WD%\runtime\package.json" "%BUILDROOT%\runtime\" > nul || EXIT /B 1 CD "%BUILDROOT%\runtime\" CALL yarn install --production=true || EXIT /B 1 ECHO Downloading NWjs to %TMPDIR%... REM Get a fresh copy of nwjs. REM NOTE: The nw download servers seem to be very unreliable, so at the moment we're using wget which retries REM YARN REM CALL yarn --cwd "%TMPDIR%" add nw || EXIT /B REM YARN END REM WGET REM Comment out the below line as the latest version having some REM problem https://github.com/nwjs/nw.js/issues/7964, so for the time being REM hardcoded the version to 0.77.0 REM FOR /f "tokens=2 delims='" %%i IN ('yarn info nw ^| findstr "latest: "') DO SET "NW_VERSION=%%i" REM :GET_NW REM wget https://dl.nwjs.io/v%NW_VERSION%/nwjs-v%NW_VERSION%-win-x64.zip -O "%TMPDIR%\nwjs-v%NW_VERSION%-win-x64.zip" REM IF %ERRORLEVEL% NEQ 0 GOTO GET_NW SET "NW_VERSION=0.77.0" wget https://dl.nwjs.io/v%NW_VERSION%/nwjs-v%NW_VERSION%-win-x64.zip -O "%TMPDIR%\nwjs-v%NW_VERSION%-win-x64.zip" tar -C "%TMPDIR%" -xvf "%TMPDIR%\nwjs-v%NW_VERSION%-win-x64.zip" || EXIT /B 1 REM WGET END REM YARN REM XCOPY /S /I /E /H /Y "%TMPDIR%\node_modules\nw\nwjs\*" "%BUILDROOT%\runtime" > nul || EXIT /B 1 REM YARN END REM WGET XCOPY /S /I /E /H /Y "%TMPDIR%\nwjs-v%NW_VERSION%-win-x64\*" "%BUILDROOT%\runtime" > nul || EXIT /B 1 REM WGET END MOVE "%BUILDROOT%\runtime\nw.exe" "%BUILDROOT%\runtime\pgAdmin4.exe" ECHO Attempting to sign the pgAdmin4.exe... CALL "%PGADMIN_SIGNTOOL_DIR%\signtool.exe" sign /tr http://timestamp.digicert.com "%BUILDROOT%\runtime\pgAdmin4.exe" IF %ERRORLEVEL% NEQ 0 ( ECHO. ECHO ************************************************************ ECHO * Failed to sign the pgAdmin4.exe ECHO ************************************************************ PAUSE ) ECHO Replacing executable icon... CALL yarn --cwd "%TMPDIR%" add winresourcer || EXIT /B "%TMPDIR%\node_modules\winresourcer\bin\Resourcer.exe" -op:upd -src:"%BUILDROOT%\runtime\pgAdmin4.exe" -type:Icongroup -name:IDR_MAINFRAME -file:"%WD%\pkg\win32\Resources\pgAdmin4.ico" ECHO Staging PostgreSQL components... COPY "%PGADMIN_POSTGRES_DIR%\bin\libpq.dll" "%BUILDROOT%\runtime" > nul || EXIT /B 1 COPY "%PGADMIN_POSTGRES_DIR%\bin\libcrypto-*-x64.dll" "%BUILDROOT%\runtime" > nul || EXIT /B 1 COPY "%PGADMIN_POSTGRES_DIR%\bin\libssl-*-x64.dll" "%BUILDROOT%\runtime" > nul || EXIT /B 1 IF EXIST "%PGADMIN_POSTGRES_DIR%\bin\libintl-*.dll" COPY "%PGADMIN_POSTGRES_DIR%\bin\libintl-*.dll" "%BUILDROOT%\runtime" > nul IF EXIST "%PGADMIN_POSTGRES_DIR%\bin\libiconv-*.dll" COPY "%PGADMIN_POSTGRES_DIR%\bin\libiconv-*.dll" "%BUILDROOT%\runtime" > nul COPY "%PGADMIN_POSTGRES_DIR%\bin\zlib.dll" "%BUILDROOT%\runtime" > nul || EXIT /B 1 COPY "%PGADMIN_POSTGRES_DIR%\bin\pg_dump.exe" "%BUILDROOT%\runtime" > nul || EXIT /B 1 COPY "%PGADMIN_POSTGRES_DIR%\bin\pg_dumpall.exe" "%BUILDROOT%\runtime" > nul || EXIT /B 1L% COPY "%PGADMIN_POSTGRES_DIR%\bin\pg_restore.exe" "%BUILDROOT%\runtime" > nul || EXIT /B 1 COPY "%PGADMIN_POSTGRES_DIR%\bin\psql.exe" "%BUILDROOT%\runtime" > nul || EXIT /B 1 ECHO Staging VC++ runtime... MKDIR "%BUILDROOT%\installer" || EXIT /B 1 COPY "%PGADMIN_VCREDIST_DIR%\%VCREDIST_FILE%" "%BUILDROOT%\installer" > nul || EXIT /B 1 CD %WD% EXIT /B 0 :CREATE_INSTALLER ECHO Preparing for creation of windows installer... IF NOT EXIST "%DISTROOT%" MKDIR "%DISTROOT%" ECHO Copying icon file... COPY "%WD%\pkg\win32\Resources\pgAdmin4.ico" "%BUILDROOT%" > nul || EXIT /B 1 CD "%WD%\pkg\win32" ECHO Processing installer configuration script... CALL "%PGADMIN_PYTHON_DIR%\python" "%WD%\pkg\win32\replace.py" "-i" "%WD%\pkg\win32\installer.iss.in" "-o" "%WD%\pkg\win32\installer.iss.in_stage1" "-s" MYAPP_FULLVERSION -r """%APP_VERSION%""" CALL "%PGADMIN_PYTHON_DIR%\python" "%WD%\pkg\win32\replace.py" "-i" "%WD%\pkg\win32\installer.iss.in_stage1" "-o" "%WD%\pkg\win32\installer.iss.in_stage2" "-s" MYAPP_VERSION -r """v%APP_MAJOR%""" CALL "%PGADMIN_PYTHON_DIR%\python" "%WD%\pkg\win32\replace.py" "-i" "%WD%\pkg\win32\installer.iss.in_stage2" "-o" "%WD%\pkg\win32\installer.iss" "-s" MYAPP_VCDIST -r """%PGADMIN_VCREDIST_DIRNAME%\%VCREDIST_FILE%""" ECHO Cleaning up... DEL /s "%WD%\pkg\win32\installer.iss.in_stage*" > nul ECHO Creating windows installer using INNO tool... CALL "%PGADMIN_INNOTOOL_DIR%\ISCC.exe" "%WD%\pkg\win32\installer.iss" || EXIT /B 1 ECHO Renaming installer... MOVE "%WD%\pkg\win32\Output\pgadmin4-setup.exe" "%DISTROOT%\%INSTALLERNAME%" > nul || EXIT /B 1 ECHO Location - %DISTROOT%\%INSTALLERNAME% ECHO Installer generated successfully. CD %WD% EXIT /B 0 :GENERATE_SBOM ECHO Generating SBOM... CALL syft "%BUILDROOT%" -o cyclonedx-json > "%BUILDROOT%\sbom.json" :SIGN_INSTALLER ECHO Attempting to sign the installer... CALL "%PGADMIN_SIGNTOOL_DIR%\signtool.exe" sign /tr http://timestamp.digicert.com "%DISTROOT%\%INSTALLERNAME%" IF %ERRORLEVEL% NEQ 0 ( ECHO. ECHO ************************************************************ ECHO * Failed to sign the installer ECHO ************************************************************ PAUSE ) EXIT /B 0 :USAGE ECHO Invalid command line options. ECHO Usage: "Make.bat [clean]" ECHO. EXIT /B 1 :CHECK_ROBOCOPY_ERROR IF %ERRORLEVEL% GEQ 8 EXIT /B %ERRORLEVEL% EXIT /B 0