| :: Make sure the extensions are enabled |
| @verify other 2>nul |
| @setlocal EnableDelayedExpansion |
| @if errorlevel 1 ( |
| call :print_usage "Failed to enable extensions" |
| exit /b 1 |
| ) |
| |
| ::Change the code page to unicode |
| @chcp 65001 1>nul 2>nul |
| @if errorlevel 1 ( |
| call :print_usage "Failed to change the code page to unicode" |
| exit /b 1 |
| ) |
| |
| :: Set up some global variables |
| @set project=civetweb |
| @set "script_name=%~nx0" |
| @set "script_folder=%~dp0" |
| @set "script_folder=%script_folder:~0,-1%" |
| @set "output_path=%script_folder%\output" |
| @set "build_path=%output_path%\build" |
| @set "install_path=%output_path%\install" |
| @set build_shared=OFF |
| @set build_type=Release |
| @set dependency_path=%TEMP%\%project%-build-dependencies |
| |
| :: Check the command line parameters |
| @set logging_level=1 |
| @set "options=%* " |
| @if not "!options!"=="!options:/? =!" set usage="Convenience script to build %project% with CMake" |
| @for %%a in (%options%) do @( |
| @set arg=%%~a |
| @set arg=!arg: =! |
| @set one=!arg:~0,1! |
| @set two=!arg:~0,2! |
| @if /i [!arg!] == [/q] set quiet=true |
| @if /i [!two!] == [/v] call :verbosity "!arg!" |
| @if /i [!arg!] == [/s] set build_shared=ON |
| @if /i [!arg!] == [/d] set build_type=Debug |
| @if /i not [!one!] == [/] ( |
| if not defined generator ( |
| set generator=!arg! |
| ) else ( |
| set usage="Too many generators: !method! !arg!" ^ |
| "There should only be one generator parameter" |
| ) |
| ) |
| ) |
| @if defined quiet ( |
| set logging_level=0 |
| ) |
| @if not defined generator ( |
| set generator=MSVC |
| ) |
| @if /i not [%generator%] == [MinGW] ( |
| if /i not [%generator%] == [MSVC] ( |
| call :print_usage "Invalid argument: %generator%" |
| exit /b 1 |
| ) |
| ) |
| |
| :: Set up the logging |
| @set log_folder=%output_path%\logs |
| @call :iso8601 timestamp |
| @set log_path=%log_folder%\%timestamp%.log |
| @set log_keep=10 |
| |
| :: Only keep a certain amount of logs |
| @set /a "log_keep=log_keep-1" |
| @if not exist %log_folder% @mkdir %log_folder% |
| @for /f "skip=%log_keep%" %%f in ('dir /b /o-D /tc %log_folder%') do @( |
| call :log 4 "Removing old log file %log_folder%\%%f" |
| del %log_folder%\%%f |
| ) |
| |
| :: Set up some more global variables |
| @call :architecture arch |
| @call :windows_version win_ver win_ver_major win_ver_minor win_ver_rev |
| @call :script_source script_source |
| @if [%script_source%] == [explorer] ( |
| set /a "logging_level=logging_level+1" |
| ) |
| |
| :: Print the usage or start the script |
| @set exit_code=0 |
| @if defined usage ( |
| call :print_usage %usage% |
| ) else ( |
| call :main |
| @if errorlevel 1 ( |
| @call :log 0 "Failed to build the %project% project" |
| @set exit_code=1 |
| ) |
| ) |
| |
| :: Tell the user where the built files are |
| @call :log 5 |
| @call :log 0 "The built files are available in %install_path%" |
| |
| :: Stop the script if the user double clicked |
| @if [%script_source%] == [explorer] ( |
| pause |
| ) |
| |
| @exit /b %exit_code% |
| @endlocal |
| @goto :eof |
| |
| :: -------------------------- Functions start here ---------------------------- |
| |
| :main - Main function that performs the build |
| @setlocal |
| @call :log 6 |
| @call :log 2 "Welcome to the %project% build script" |
| @call :log 6 "------------------------------------" |
| @call :log 6 |
| @call :log 2 "This script builds the project using CMake" |
| @call :log 6 |
| @call :log 2 "Generating %generator%..." |
| @call :log 6 |
| @set methods=dependencies ^ |
| generate ^ |
| build ^ |
| install |
| @for %%m in (%methods%) do @( |
| call :log 3 "Excuting the '%%m' method" |
| call :log 8 |
| call :%%~m |
| if errorlevel 1 ( |
| call :log 0 "Failed to complete the '%%~m' dependency routine" |
| call :log 0 "View the log at %log_path%" |
| exit /b 1 |
| ) |
| ) |
| @call :log 6 "------------------------------------" |
| @call :log 2 "Build complete" |
| @call :log 6 |
| @endlocal |
| @goto :eof |
| |
| :print_usage - Prints the usage of the script |
| :: %* - message to print, each argument on it's own line |
| @setlocal |
| @for %%a in (%*) do @echo.%%~a |
| @echo. |
| @echo.build [/?][/v[v...]^|/q][MinGW^|MSVC] |
| @echo. |
| @echo. [MinGW^|(MSVC)] |
| @echo. Builds the library with one of the compilers |
| @echo. /s Builds shared libraries |
| @echo. /d Builds a debug variant of the project |
| @echo. /v Sets the output to be more verbose |
| @echo. /v[v...] Extra verbosity, /vv, /vvv, etc |
| @echo. /q Quiets the output |
| @echo. /? Shows this usage message |
| @echo. |
| @endlocal |
| @goto :eof |
| |
| :dependencies - Installs any prerequisites for the build |
| @setlocal EnableDelayedExpansion |
| @if errorlevel 1 ( |
| call :log 0 "Failed to enable extensions" |
| exit /b 1 |
| ) |
| @call :log 5 |
| @call :log 0 "Installing dependencies for %generator%" |
| @if /i [%generator%] == [MinGW] ( |
| call :mingw compiler_path |
| @if errorlevel 1 ( |
| @call :log 5 |
| @call :log 0 "Failed to find MinGW" |
| @exit /b 1 |
| ) |
| set "PATH=!compiler_path!;%PATH%" |
| @call :find_in_path gcc_executable gcc.exe |
| @if errorlevel 1 ( |
| @call :log 5 |
| @call :log 0 "Failed to find gcc.exe" |
| @exit /b 1 |
| ) |
| ) |
| @if [%reboot_required%] equ [1] call :reboot |
| @endlocal & set "PATH=%PATH%" |
| @goto :eof |
| |
| :generate - Uses CMake to generate the build files |
| @setlocal EnableDelayedExpansion |
| @if errorlevel 1 ( |
| call :log 0 "Failed to enable extensions" |
| exit /b 1 |
| ) |
| @call :log 5 |
| @call :log 0 "Generating CMake files for %generator%" |
| @call :cmake cmake_executable |
| @if errorlevel 1 ( |
| @call :log 5 |
| @call :log 0 "Need CMake to create the build files" |
| @exit /b 1 |
| ) |
| @if /i [%generator%] == [MinGW] @( |
| @set "generator_var=-G "MinGW Makefiles^"" |
| ) |
| @if /i [%generator%] == [MSVC] @( |
| rem We could figure out the correct MSVS generator here |
| ) |
| @call :iso8601 iso8601 |
| @set output=%temp%\cmake-%iso8601%.log |
| @if not exist %build_path% mkdir %build_path% |
| @cd %build_path% |
| @"%cmake_executable%" ^ |
| !generator_var! ^ |
| -DCMAKE_BUILD_TYPE=!build_type! ^ |
| -DBUILD_SHARED_LIBS=!build_shared! ^ |
| "%script_folder%" > "%output%" |
| @if errorlevel 1 ( |
| @call :log 5 |
| @call :log 0 "Failed to generate build files with CMake" |
| @call :log_append "%output%" |
| @cd %script_folder% |
| @exit /b 1 |
| ) |
| @cd %script_folder% |
| @endlocal |
| @goto :eof |
| |
| :build - Builds the library |
| @setlocal EnableDelayedExpansion |
| @if errorlevel 1 ( |
| call :log 0 "Failed to enable extensions" |
| exit /b 1 |
| ) |
| @call :log 5 |
| @call :log 0 "Building %project% with %generator%" |
| @if /i [%generator%] == [MinGW] @( |
| @call :find_in_path mingw32_make_executable mingw32-make.exe |
| @if errorlevel 1 ( |
| @call :log 5 |
| @call :log 0 "Failed to find mingw32-make" |
| @exit /b 1 |
| ) |
| @set "build_command=^"!mingw32_make_executable!^" all test" |
| ) |
| @if /i [%generator%] == [MSVC] @( |
| @call :msbuild msbuild_executable |
| @if errorlevel 1 ( |
| @call :log 5 |
| @call :log 0 "Failed to find MSBuild" |
| @exit /b 1 |
| ) |
| @set "build_command=^"!msbuild_executable!^" /m:4 /p:Configuration=%build_type% %project%.sln" |
| ) |
| @if not defined build_command ( |
| @call :log 5 |
| @call :log 0 "No build command for %generator%" |
| @exit /b 1 |
| ) |
| @cd %build_path% |
| @call :iso8601 iso8601 |
| @set output=%temp%\build-%iso8601%.log |
| @call :log 7 |
| @call :log 2 "Build command: %build_command:"=%" |
| @%build_command% > "%output%" |
| @if errorlevel 1 ( |
| @call :log_append "%output%" |
| @call :log 5 |
| @call :log 0 "Failed to complete the build" |
| @exit /b 1 |
| ) |
| @call :log_append "%output%" |
| @cd %script_folder% |
| @endlocal |
| @goto :eof |
| |
| :install - Installs the built files |
| @setlocal |
| @call :log 5 |
| @call :log 0 "Installing built files" |
| @call :cmake cmake_executable |
| @if errorlevel 1 ( |
| @call :log 5 |
| @call :log 0 "Need CMake to install the built files" |
| @exit /b 1 |
| ) |
| @call :iso8601 iso8601 |
| @set output=%temp%\install-%iso8601%.log |
| @"%cmake_executable%" ^ |
| "-DCMAKE_INSTALL_PREFIX=%install_path%" ^ |
| -P "%build_path%/cmake_install.cmake" ^ |
| > "%output%" |
| @if errorlevel 1 ( |
| @call :log_append "%output%" |
| @call :log 5 |
| @call :log 0 "Failed to install the files" |
| @exit /b 1 |
| ) |
| @call :log_append "%output%" |
| @endlocal |
| @goto :eof |
| |
| :script_source - Determines if the script was ran from the cli or explorer |
| :: %1 - The return variable [cli|explorer] |
| @verify other 2>nul |
| @setlocal EnableDelayedExpansion |
| @if errorlevel 1 ( |
| call :log 0 "Failed to enable extensions" |
| exit /b 1 |
| ) |
| @call :log 3 "Attempting to detect the script source" |
| @echo "The invocation command was: '%cmdcmdline%'" >> %log_path% |
| @for /f "tokens=1-3,*" %%a in ("%cmdcmdline%") do @( |
| set cmd=%%~a |
| set arg1=%%~b |
| set arg2=%%~c |
| set rest=%%~d |
| ) |
| @set quote=" |
| @if "!arg2:~0,1!" equ "!quote!" ( |
| if "!arg2:~-1!" neq "!quote!" ( |
| set "arg2=!arg2:~1!" |
| ) |
| ) |
| @call :log 4 "cmd = %cmd%" |
| @call :log 4 "arg1 = %arg1%" |
| @call :log 4 "arg2 = %arg2%" |
| @call :log 4 "rest = %rest%" |
| @call :log 4 "src = %~f0" |
| @if /i "%arg2%" == "call" ( |
| set script_source=cli |
| ) else ( |
| @if /i "%arg1%" == "/c" ( |
| set script_source=explorer |
| ) else ( |
| set script_source=cli |
| ) |
| ) |
| @call :log 3 "The script was invoked from %script_source%" |
| @endlocal & set "%~1=%script_source%" |
| @goto :eof |
| |
| :architecture - Finds the system architecture |
| :: %1 - The return variable [x86|x86_64] |
| @setlocal |
| @call :log 3 "Determining the processor architecture" |
| @set "key=HKLM\System\CurrentControlSet\Control\Session Manager\Environment" |
| @set "var=PROCESSOR_ARCHITECTURE" |
| @for /f "skip=2 tokens=2,*" %%a in ('reg query "%key%" /v "%var%"') do @set "arch=%%b" |
| @if "%arch%" == "AMD64" set arch=x86_64 |
| @call :log 4 "arch = %arch%" |
| @endlocal & set "%~1=%arch%" |
| @goto :eof |
| |
| :md5 - Gets the MD5 checksum for a file |
| :: %1 - The hash |
| :: %2 - The file path |
| @setlocal |
| @set var=%~1 |
| @set file_path=%~2 |
| @if [%var%] == [] exit /b 1 |
| @if "%file_path%" == "" exit /b 1 |
| @if not exist "%file_path%" exit /b 1 |
| @for /f "skip=3 tokens=1,*" %%a in ('powershell Get-FileHash -Algorithm MD5 "'%file_path%'"') do @set hash=%%b |
| @if not defined hash ( |
| call :log 6 |
| call :log 0 "Failed to get MD5 hash for %file_path%" |
| exit /b 1 |
| ) |
| @endlocal & set "%var%=%hash: =%" |
| @goto :eof |
| |
| :windows_version - Checks the windows version |
| :: %1 - The windows version |
| :: %2 - The major version number return variable |
| :: %3 - The minor version number return variable |
| :: %4 - The revision version number return variable |
| @setlocal |
| @call :log 3 "Retrieving the Windows version" |
| @for /f "tokens=2 delims=[]" %%x in ('ver') do @set win_ver=%%x |
| @set win_ver=%win_ver:Version =% |
| @set win_ver_major=%win_ver:~0,1% |
| @set win_ver_minor=%win_ver:~2,1% |
| @set win_ver_rev=%win_ver:~4% |
| @call :log 4 "win_ver = %win_ver%" |
| @endlocal & set "%~1=%win_ver%" ^ |
| & set "%~2=%win_ver_major%" ^ |
| & set "%~3=%win_ver_minor%" ^ |
| & set "%~4=%win_ver_rev%" |
| @goto :eof |
| |
| :find_in_path - Finds a program of file in the PATH |
| @setlocal |
| @set var=%~1 |
| @set file=%~2 |
| @if [%var%] == [] exit /b 1 |
| @if [%file%] == [] exit /b 1 |
| @call :log 3 "Searching PATH for %file%" |
| @for %%x in ("%file%") do @set "file_path=%%~f$PATH:x" |
| @if not defined file_path exit /b 1 |
| @endlocal & set "%var%=%file_path%" |
| @goto :eof |
| |
| :administrator_check - Checks for administrator priviledges |
| @setlocal |
| @call :log 2 "Checking for administrator priviledges" |
| @set "key=HKLM\Software\VCA\Tool Chain\Admin Check" |
| @reg add "%key%" /v Elevated /t REG_DWORD /d 1 /f > nul 2>&1 |
| @if errorlevel 1 exit /b 1 |
| @reg delete "%key%" /va /f > nul 2>&1 |
| @endlocal |
| @goto :eof |
| |
| :log_append - Appends another file into the current logging file |
| :: %1 - the file_path to the file to concatenate |
| @setlocal |
| @set "file_path=%~1" |
| @if [%file_path%] == [] exit /b 1 |
| @call :log 3 "Appending to log: %file_path%" |
| @call :iso8601 iso8601 |
| @set "temp_log=%temp%\append-%iso8601%.log" |
| @call :log 4 "Using temp file %temp_log%" |
| @type "%log_path%" "%file_path%" > "%temp_log%" 2>nul |
| @move /y "%temp_log%" "%log_path%" 1>nul |
| @del "%file_path%" 2>nul |
| @del "%temp_log%" 2>nul |
| @endlocal |
| @goto :eof |
| |
| :iso8601 - Returns the current time in ISO8601 format |
| :: %1 - the return variable |
| :: %2 - format [extended|basic*] |
| :: iso8601 - contains the resulting timestamp |
| @setlocal |
| @wmic Alias /? >NUL 2>&1 || @exit /b 1 |
| @set "var=%~1" |
| @if "%var%" == "" @exit /b 1 |
| @set "format=%~2" |
| @if "%format%" == "" set format=basic |
| @for /F "skip=1 tokens=1-6" %%g IN ('wmic Path Win32_UTCTime Get Day^,Hour^,Minute^,Month^,Second^,Year /Format:table') do @( |
| @if "%%~l"=="" goto :iso8601_done |
| @set "yyyy=%%l" |
| @set "mm=00%%j" |
| @set "dd=00%%g" |
| @set "hour=00%%h" |
| @set "minute=00%%i" |
| @set "seconds=00%%k" |
| ) |
| :iso8601_done |
| @set mm=%mm:~-2% |
| @set dd=%dd:~-2% |
| @set hour=%hour:~-2% |
| @set minute=%minute:~-2% |
| @set seconds=%seconds:~-2% |
| @if /i [%format%] == [extended] ( |
| set iso8601=%yyyy%-%mm%-%dd%T%hour%:%minute%:%seconds%Z |
| ) else ( |
| if /i [%format%] == [basic] ( |
| set iso8601=%yyyy%%mm%%dd%T%hour%%minute%%seconds%Z |
| ) else ( |
| @exit /b 1 |
| ) |
| ) |
| @set iso8601=%iso8601: =0% |
| @endlocal & set %var%=%iso8601% |
| @goto :eof |
| |
| :verbosity - Processes the verbosity parameter '/v[v...] |
| :: %1 - verbosity given on the command line |
| :: logging_level - set to the number of v's |
| @setlocal |
| @set logging_level=0 |
| @set verbosity=%~1 |
| :verbosity_loop |
| @set verbosity=%verbosity:~1% |
| @if not [%verbosity%] == [] @( |
| set /a "logging_level=logging_level+1" |
| goto verbosity_loop |
| ) |
| @endlocal & set logging_level=%logging_level% |
| @goto :eof |
| |
| :log - Logs a message, depending on verbosity |
| :: %1 - level |
| :: [0-4] for CLI logging |
| :: [5-9] for GUI logging |
| :: %2 - message to print |
| @setlocal |
| @set "level=%~1" |
| @set "msg=%~2" |
| @if "%log_folder%" == "" ( |
| echo Logging was used to early in the script, log_folder isn't set yet |
| goto :eof |
| ) |
| @if "%log_path%" == "" ( |
| echo Logging was used to early in the script, log_path isn't set yet |
| goto :eof |
| ) |
| @if not exist "%log_folder%" mkdir "%log_folder%" |
| @if not exist "%log_path%" echo. 1>nul 2>"%log_path%" |
| @echo.%msg% >> "%log_path%" |
| @if %level% geq 5 ( |
| @if [%script_source%] == [explorer] ( |
| set /a "level=level-5" |
| ) else ( |
| @goto :eof |
| ) |
| ) |
| @if "%logging_level%" == "" ( |
| echo Logging was used to early in the script, logging_level isn't set yet |
| goto :eof |
| ) |
| @if %logging_level% geq %level% echo.%msg% 1>&2 |
| @endlocal |
| @goto :eof |
| |
| |
| :start_browser - Opens the default browser to a URL |
| :: %1 - the url to open |
| @setlocal |
| @set url=%~1 |
| @call :log 4 "Opening default browser: %url%" |
| @start %url% |
| @endlocal |
| @goto :eof |
| |
| :find_cmake - Finds cmake on the command line or in the registry |
| :: %1 - the cmake file path |
| @setlocal |
| @set var=%~1 |
| @if [%var%] == [] exit /b 1 |
| @call :log 6 |
| @call :log 6 "Finding CMake" |
| @call :log 6 "--------------" |
| @call :find_in_path cmake_executable cmake.exe |
| @if not errorlevel 1 goto found_cmake |
| @for /l %%i in (5,-1,0) do @( |
| @for /l %%j in (9,-1,0) do @( |
| @for /l %%k in (9,-1,0) do @( |
| @for %%l in (HKCU HKLM) do @( |
| @for %%m in (SOFTWARE SOFTWARE\Wow6432Node) do @( |
| @reg query "%%l\%%m\Kitware\CMake %%i.%%j.%%k" /ve > nul 2>nul |
| @if not errorlevel 1 ( |
| @for /f "skip=2 tokens=2,*" %%a in ('reg query "%%l\%%m\Kitware\CMake %%i.%%j.%%k" /ve') do @( |
| @if exist "%%b\bin\cmake.exe" ( |
| @set "cmake_executable=%%b\bin\cmake.exe" |
| goto found_cmake |
| ) |
| ) |
| ) |
| ))))) |
| @call :log 5 |
| @call :log 0 "Failed to find cmake" |
| @exit /b 1 |
| :found_cmake |
| @endlocal & set "%var%=%cmake_executable%" |
| @goto :eof |
| |
| :cmake - Finds cmake and installs it if necessary |
| :: %1 - the cmake file path |
| @setlocal |
| @set var=%~1 |
| @if [%var%] == [] exit /b 1 |
| @call :log 6 |
| @call :log 6 "Checking for CMake" |
| @call :log 6 "------------------" |
| @call :find_cmake cmake_executable cmake.exe |
| @if not errorlevel 1 goto got_cmake |
| @set checksum=C00267A3D3D9619A7A2E8FA4F46D7698 |
| @set version=3.2.2 |
| @call :install_nsis cmake http://www.cmake.org/files/v%version:~0,3%/cmake-%version%-win32-x86.exe %checksum% |
| @if errorlevel 1 ( |
| call :log 5 |
| call :log 0 "Failed to install cmake" |
| @exit /b 1 |
| ) |
| @call :find_cmake cmake_executable cmake.exe |
| @if not errorlevel 1 goto got_cmake |
| @call :log 5 |
| @call :log 0 "Failed to check for cmake" |
| @exit /b 1 |
| :got_cmake |
| @endlocal & set "%var%=%cmake_executable%" |
| @goto :eof |
| |
| :mingw - Finds MinGW, installing it if needed |
| :: %1 - the compiler path that should be added to PATH |
| @setlocal EnableDelayedExpansion |
| @if errorlevel 1 ( |
| @call :log 5 |
| @call :log 0 "Failed to enable extensions" |
| @exit /b 1 |
| ) |
| @set var=%~1 |
| @if [%var%] == [] exit /b 1 |
| @call :log 6 |
| @call :log 6 "Checking for MinGW" |
| @call :log 6 "------------------" |
| @call :find_in_path gcc_executable gcc.exe |
| @if not errorlevel 1 ( |
| @for %%a in ("%gcc_executable%") do @set "compiler_path=%%~dpa" |
| goto got_mingw |
| ) |
| @call :log 7 |
| @call :log 2 "Downloading MinGW" |
| @if %logging_level% leq 1 set "logging=/q" |
| @if %logging_level% gtr 1 set "logging=/v" |
| @set output_path= |
| @for /f %%a in ('call |
| "%script_folder%\mingw.cmd" |
| %logging% |
| /arch "%arch%" |
| "%dependency_path%"' |
| ) do @set "compiler_path=%%a\" |
| @if not defined compiler_path ( |
| @call :log_append "%output%" |
| @call :log 5 |
| @call :log 0 "Failed to download MinGW" |
| @exit /b 1 |
| ) |
| :got_mingw |
| @call :log 5 |
| @call :log 0 "Found MinGW: %compiler_path%gcc.exe" |
| @endlocal & set "%var%=%compiler_path%" |
| @goto :eof |
| |
| :msbuild - Finds MSBuild |
| :: %1 - the path to MSBuild executable |
| @setlocal |
| @set var=%~1 |
| @if [%var%] == [] exit /b 1 |
| @call :find_in_path msbuild_executable msbuild.exe |
| @if not errorlevel 1 goto got_msbuild |
| @for /l %%i in (20,-1,4) do @( |
| @for /l %%j in (9,-1,0) do @( |
| @for %%k in (HKCU HKLM) do @( |
| @for %%l in (SOFTWARE SOFTWARE\Wow6432Node) do @( |
| @reg query "%%k\%%l\Microsoft\MSBuild\%%i.%%j" /v MSBuildOverrideTasksPath > nul 2>nul |
| @if not errorlevel 1 ( |
| @for /f "skip=2 tokens=2,*" %%a in ('reg query "%%k\%%l\Microsoft\MSBuild\%%i.%%j" /v MSBuildOverrideTasksPath') do @( |
| @if exist "%%bmsbuild.exe" ( |
| @set "msbuild_executable=%%bmsbuild.exe" |
| goto got_msbuild |
| ) |
| ) |
| ) |
| )))) |
| @call :log 5 |
| @call :log 0 "Failed to check for MSBuild" |
| @exit /b 1 |
| :got_msbuild |
| @endlocal & set "%var%=%msbuild_executable%" |
| @goto :eof |
| |
| :download - Downloads a file from the internet |
| :: %1 - the url of the file to download |
| :: %2 - the file to download to |
| :: %3 - the MD5 checksum of the file (optional) |
| @setlocal EnableDelayedExpansion |
| @if errorlevel 1 ( |
| call :print_usage "Failed to enable extensions" |
| exit /b 1 |
| ) |
| @set url=%~1 |
| @set file_path=%~2 |
| @set checksum=%~3 |
| @for %%a in (%file_path%) do @set dir_path=%%~dpa |
| @for %%a in (%file_path%) do @set file_name=%%~nxa |
| @if [%url%] == [] exit /b 1 |
| @if [%file_path%] == [] exit /b 1 |
| @if [%dir_path%] == [] exit /b 1 |
| @if [%file_name%] == [] exit /b 1 |
| @if not exist "%dir_path%" mkdir "%dir_path%" |
| @call :log 1 "Downloading %url%" |
| @call :iso8601 iso8601 |
| @set temp_path=%temp%\download-%iso8601%-%file_name% |
| @call :log 3 "Using temp file %temp_path%" |
| @powershell Invoke-WebRequest "%url%" -OutFile %temp_path% |
| @if errorlevel 1 ( |
| call :log 0 "Failed to download %url%" |
| exit /b 1 |
| ) |
| @if [%checksum%] neq [] ( |
| @call :log 4 "Checking %checksum% against %temp_path%" |
| @call :md5 hash "%temp_path%" |
| if "!hash!" neq "%checksum%" ( |
| call :log 0 "Failed to match checksum: %temp_path%" |
| call :log 0 "Hash : !hash!" |
| call :log 0 "Checksum: %checksum%" |
| exit /b 1 |
| ) else ( |
| call :log 3 "Checksum matched: %temp_path%" |
| call :log 3 "Hash : !hash!" |
| call :log 3 "Checksum: %checksum%" |
| ) |
| ) |
| @call :log 4 "Renaming %temp_path% to %file_path%" |
| @move /y "%temp_path%" "%file_path%" 1>nul |
| @endlocal |
| @goto :eof |
| |
| :install_msi - Installs a dependency from an Microsoft Installer package (.msi) |
| :: %1 - [string] name of the project to install |
| :: %2 - The location of the .msi, a url must start with 'http://' or file_path |
| :: %3 - The checksum of the msi (optional) |
| @setlocal |
| @set name=%~1 |
| @set file_path=%~2 |
| @set checksum=%~3 |
| @set msi=%~nx2 |
| @set msi_path=%dependency_path%\%msi% |
| @if [%name%] == [] exit /b 1 |
| @if [%file_path%] == [] exit /b 1 |
| @if [%msi%] == [] exit /b 1 |
| @if [%msi_path%] == [] exit /b 1 |
| @for %%x in (msiexec.exe) do @set "msiexec_path=%%~f$PATH:x" |
| @if "msiexec_path" == "" ( |
| call :log 0 "Failed to find the Microsoft package installer (msiexec.exe)" |
| call :log 6 |
| call :log 0 "Please install it from the Microsoft Download center" |
| call :log 6 |
| choice /C YN /T 60 /D N /M "Would you like to go there now?" |
| if !errorlevel! equ 1 call :start_browser ^ |
| "http://search.microsoft.com/DownloadResults.aspx?q=Windows+Installer" |
| exit /b 1 |
| ) |
| @call :log 6 |
| @call :log 1 "Installing the '%name%' dependency" |
| @call :log 6 "-------------------------------------" |
| @call :administrator_check |
| @if errorlevel 1 ( |
| call :log 0 "You must run %~nx0 in elevated mode to install '%name%'" |
| call :log 5 "Right-Click and select 'Run as Administrator' |
| call :log 0 "Install the dependency manually by running %file_path%" |
| @exit /b 740 |
| ) |
| @if [%file_path:~0,4%] == [http] ( |
| if not exist "%msi_path%" ( |
| call :download "%file_path%" "%msi_path%" %checksum% |
| if errorlevel 1 ( |
| call :log 0 "Failed to download the %name% dependency" |
| exit /b 1 |
| ) |
| ) |
| ) else ( |
| call :log 2 "Copying MSI %file_path% to %msi_path%" |
| call :log 7 |
| if not exist "%msi_path%" ( |
| xcopy /q /y /z "%file_path%" "%msi_path%" 1>nul |
| if errorlevel 1 ( |
| call :log 0 "Failed to copy the Microsoft Installer" |
| exit /b 1 |
| ) |
| ) |
| ) |
| @call :log 1 "Running the %msi%" |
| @call :log 6 |
| @set msi_log=%temp%\msiexec-%timestamp%.log |
| @call :log 3 "Logging to: %msi_log%" |
| @msiexec /i "%msi_path%" /passive /log "%msi_log%" ALLUSERS=1 |
| @set msi_errorlevel=%errorlevel% |
| @call :log_append "%msi_log%" |
| @if %msi_errorlevel% equ 0 goto install_msi_success |
| @if %msi_errorlevel% equ 3010 goto install_msi_success_reboot |
| @if %msi_errorlevel% equ 1641 goto install_msi_success_reboot |
| @if %msi_errorlevel% equ 3015 goto install_msi_in_progress_reboot |
| @if %msi_errorlevel% equ 1615 goto install_msi_in_progress_reboot |
| @call :log 0 "Microsoft Installer failed: %msi_errorlevel%" |
| @call :log 0 "Install the dependency manually by running %msi_path%" |
| @exit /b 1 |
| :install_msi_in_progress_reboot |
| @call :log 0 "The installation requires a reboot to continue" |
| @call :log 5 |
| @call :reboot |
| @exit /b 1 |
| :install_msi_success_reboot |
| @call :log 3 "The installation requires a reboot to be fully functional" |
| @set reboot_required=1 |
| :install_msi_success |
| @call :log 2 "Successfully installed %name%" |
| @call :log 7 |
| @endlocal & set reboot_required=%reboot_required% |
| @goto :eof |
| |
| :install_nsis - Installs a dependency from an Nullsoft Installer package (.exe) |
| :: %1 - [string] name of the project to install |
| :: %2 - The location of the .exe, a url must start with 'http://' or file_path |
| :: %3 - The checksum of the exe (optional) |
| @setlocal |
| @set name=%~1 |
| @set file_path=%~2 |
| @set checksum=%~3 |
| @set exe=%~nx2 |
| @set exe_path=%dependency_path%\%exe% |
| @if [%name%] == [] exit /b 1 |
| @if [%file_path%] == [] exit /b 1 |
| @if [%exe%] == [] exit /b 1 |
| @if [%exe_path%] == [] exit /b 1 |
| @call :log 6 |
| @call :log 1 "Installing the '%name%' dependency" |
| @call :log 6 "-------------------------------------" |
| @call :administrator_check |
| @if errorlevel 1 ( |
| call :log 0 "You must run %~nx0 in elevated mode to install '%name%'" |
| call :log 5 "Right-Click and select 'Run as Administrator' |
| call :log 0 "Install the dependency manually by running %file_path%" |
| @exit /b 740 |
| ) |
| @if [%file_path:~0,4%] == [http] ( |
| if not exist "%exe_path%" ( |
| call :download "%file_path%" "%exe_path%" %checksum% |
| if errorlevel 1 ( |
| call :log 0 "Failed to download the %name% dependency" |
| exit /b 1 |
| ) |
| ) |
| ) else ( |
| call :log 2 "Copying installer %file_path% to %exe_path%" |
| call :log 7 |
| if not exist "%exe_path%" ( |
| xcopy /q /y /z "%file_path%" "%exe_path%" 1>nul |
| if errorlevel 1 ( |
| call :log 0 "Failed to copy the Nullsoft Installer" |
| exit /b 1 |
| ) |
| ) |
| ) |
| @call :log 1 "Running the %exe%" |
| @call :log 6 |
| @"%exe_path%" /S |
| @set nsis_errorlevel=%errorlevel% |
| @if %nsis_errorlevel% equ 0 goto install_nsis_success |
| @if %nsis_errorlevel% equ 3010 goto install_nsis_success_reboot |
| @if %nsis_errorlevel% equ 1641 goto install_nsis_success_reboot |
| @if %nsis_errorlevel% equ 3015 goto install_nsis_in_progress_reboot |
| @if %nsis_errorlevel% equ 1615 goto install_nsis_in_progress_reboot |
| @call :log 0 "Nullsoft Installer failed: %nsis_errorlevel%" |
| @call :log 0 "Install the dependency manually by running %exe_path%" |
| @exit /b 1 |
| :install_nsis_in_progress_reboot |
| @call :log 0 "The installation requires a reboot to continue" |
| @call :log 5 |
| @call :reboot |
| @exit /b 1 |
| :install_nsis_success_reboot |
| @call :log 3 "The installation requires a reboot to be fully functional" |
| @set reboot_required=1 |
| :install_nsis_success |
| @call :log 2 "Successfully installed %name%" |
| @call :log 7 |
| @endlocal & set reboot_required=%reboot_required% |
| @goto :eof |
| |
| :reboot - Asks the user if they would like to reboot then stops the script |
| @setlocal |
| @call :log 6 "-------------------------------------------" |
| @choice /C YN /T 60 /D N /M "The %method% requires a reboot, reboot now?" |
| @set ret=%errorlevel% |
| @call :log 6 |
| @if %ret% equ 1 ( |
| @shutdown /r |
| ) else ( |
| @call :log 0 "You will need to reboot to complete the %method%" |
| @call :log 5 |
| ) |
| @endlocal |
| @goto :eof |