1:: Make sure the extensions are enabled
2@verify other 2>nul
3@setlocal EnableDelayedExpansion
4@if errorlevel 1 (
5  call :print_usage "Failed to enable extensions"
6  exit /b 1
7)
8
9::Change the code page to unicode
10@chcp 65001 1>nul 2>nul
11@if errorlevel 1 (
12  call :print_usage "Failed to change the code page to unicode"
13  exit /b 1
14)
15
16:: Set up some global variables
17@set project=civetweb
18@set "script_name=%~nx0"
19@set "script_folder=%~dp0"
20@set "script_folder=%script_folder:~0,-1%"
21@set "output_path=%script_folder%\output"
22@set "build_path=%output_path%\build"
23@set "install_path=%output_path%\install"
24@set build_shared=OFF
25@set build_type=Release
26@set dependency_path=%TEMP%\%project%-build-dependencies
27
28:: Check the command line parameters
29@set logging_level=1
30@set "options=%* "
31@if not "!options!"=="!options:/? =!" set usage="Convenience script to build %project% with CMake"
32@for %%a in (%options%) do @(
33  @set arg=%%~a
34  @set arg=!arg: =!
35  @set one=!arg:~0,1!
36  @set two=!arg:~0,2!
37  @if /i [!arg!] == [/q] set quiet=true
38  @if /i [!two!] == [/v] call :verbosity "!arg!"
39  @if /i [!arg!] == [/s] set build_shared=ON
40  @if /i [!arg!] == [/d] set build_type=Debug
41  @if /i not [!one!] == [/] (
42    if not defined generator (
43      set generator=!arg!
44    ) else (
45      set usage="Too many generators: !method! !arg!" ^
46                "There should only be one generator parameter"
47    )
48  )
49)
50@if defined quiet (
51  set logging_level=0
52)
53@if not defined generator (
54  set generator=MSVC
55)
56@if /i not [%generator%] == [MinGW] (
57  if /i not [%generator%] == [MSVC] (
58    call :print_usage "Invalid argument: %generator%"
59    exit /b 1
60  )
61)
62
63:: Set up the logging
64@set log_folder=%output_path%\logs
65@call :iso8601 timestamp
66@set log_path=%log_folder%\%timestamp%.log
67@set log_keep=10
68
69:: Only keep a certain amount of logs
70@set /a "log_keep=log_keep-1"
71@if not exist %log_folder% @mkdir %log_folder%
72@for /f "skip=%log_keep%" %%f in ('dir /b /o-D /tc %log_folder%') do @(
73  call :log 4 "Removing old log file %log_folder%\%%f"
74  del %log_folder%\%%f
75)
76
77:: Set up some more global variables
78@call :architecture arch
79@call :windows_version win_ver win_ver_major win_ver_minor win_ver_rev
80@call :script_source script_source
81@if [%script_source%] == [explorer] (
82  set /a "logging_level=logging_level+1"
83)
84
85:: Print the usage or start the script
86@set exit_code=0
87@if defined usage (
88  call :print_usage %usage%
89) else (
90  call :main
91  @if errorlevel 1 (
92    @call :log 0 "Failed to build the %project% project"
93    @set exit_code=1
94  )
95)
96
97:: Tell the user where the built files are
98@call :log 5
99@call :log 0 "The built files are available in %install_path%"
100
101:: Stop the script if the user double clicked
102@if [%script_source%] == [explorer] (
103  pause
104)
105
106@exit /b %exit_code%
107@endlocal
108@goto :eof
109
110:: -------------------------- Functions start here ----------------------------
111
112:main - Main function that performs the build
113@setlocal
114@call :log 6
115@call :log 2 "Welcome to the %project% build script"
116@call :log 6 "------------------------------------"
117@call :log 6
118@call :log 2 "This script builds the project using CMake"
119@call :log 6
120@call :log 2 "Generating %generator%..."
121@call :log 6
122@set methods=dependencies ^
123             generate ^
124             build ^
125             install
126@for %%m in (%methods%) do @(
127  call :log 3 "Excuting the '%%m' method"
128  call :log 8
129  call :%%~m
130  if errorlevel 1 (
131    call :log 0 "Failed to complete the '%%~m' dependency routine"
132    call :log 0 "View the log at %log_path%"
133    exit /b 1
134  )
135)
136@call :log 6 "------------------------------------"
137@call :log 2 "Build complete"
138@call :log 6
139@endlocal
140@goto :eof
141
142:print_usage - Prints the usage of the script
143:: %* - message to print, each argument on it's own line
144@setlocal
145@for %%a in (%*) do @echo.%%~a
146@echo.
147@echo.build [/?][/v[v...]^|/q][MinGW^|MSVC]
148@echo.
149@echo.  [MinGW^|(MSVC)]
150@echo.              Builds the library with one of the compilers
151@echo.  /s          Builds shared libraries
152@echo.  /d          Builds a debug variant of the project
153@echo.  /v          Sets the output to be more verbose
154@echo.  /v[v...]    Extra verbosity, /vv, /vvv, etc
155@echo.  /q          Quiets the output
156@echo.  /?          Shows this usage message
157@echo.
158@endlocal
159@goto :eof
160
161:dependencies - Installs any prerequisites for the build
162@setlocal EnableDelayedExpansion
163@if errorlevel 1 (
164  call :log 0 "Failed to enable extensions"
165  exit /b 1
166)
167@call :log 5
168@call :log 0 "Installing dependencies for %generator%"
169@if /i [%generator%] == [MinGW] (
170  call :mingw compiler_path
171  @if errorlevel 1 (
172    @call :log 5
173    @call :log 0 "Failed to find MinGW"
174    @exit /b 1
175  )
176  set "PATH=!compiler_path!;%PATH%"
177  @call :find_in_path gcc_executable gcc.exe
178  @if errorlevel 1 (
179    @call :log 5
180    @call :log 0 "Failed to find gcc.exe"
181    @exit /b 1
182  )
183)
184@if [%reboot_required%] equ [1] call :reboot
185@endlocal & set "PATH=%PATH%"
186@goto :eof
187
188:generate - Uses CMake to generate the build files
189@setlocal EnableDelayedExpansion
190@if errorlevel 1 (
191  call :log 0 "Failed to enable extensions"
192  exit /b 1
193)
194@call :log 5
195@call :log 0 "Generating CMake files for %generator%"
196@call :cmake cmake_executable
197@if errorlevel 1 (
198  @call :log 5
199  @call :log 0 "Need CMake to create the build files"
200  @exit /b 1
201)
202@if /i [%generator%] == [MinGW] @(
203  @set "generator_var=-G "MinGW Makefiles^""
204)
205@if /i [%generator%] == [MSVC] @(
206  rem We could figure out the correct MSVS generator here
207)
208@call :iso8601 iso8601
209@set output=%temp%\cmake-%iso8601%.log
210@if not exist %build_path% mkdir %build_path%
211@cd %build_path%
212@"%cmake_executable%" ^
213  !generator_var! ^
214  -DCMAKE_BUILD_TYPE=!build_type! ^
215  -DBUILD_SHARED_LIBS=!build_shared! ^
216  "%script_folder%" > "%output%"
217@if errorlevel 1 (
218  @call :log 5
219  @call :log 0 "Failed to generate build files with CMake"
220  @call :log_append "%output%"
221  @cd %script_folder%
222  @exit /b 1
223)
224@cd %script_folder%
225@endlocal
226@goto :eof
227
228:build - Builds the library
229@setlocal EnableDelayedExpansion
230@if errorlevel 1 (
231  call :log 0 "Failed to enable extensions"
232  exit /b 1
233)
234@call :log 5
235@call :log 0 "Building %project% with %generator%"
236@if /i [%generator%] == [MinGW] @(
237  @call :find_in_path mingw32_make_executable mingw32-make.exe
238  @if errorlevel 1 (
239    @call :log 5
240    @call :log 0 "Failed to find mingw32-make"
241    @exit /b 1
242  )
243  @set "build_command=^"!mingw32_make_executable!^" all test"
244)
245@if /i [%generator%] == [MSVC] @(
246  @call :msbuild msbuild_executable
247  @if errorlevel 1 (
248    @call :log 5
249    @call :log 0 "Failed to find MSBuild"
250    @exit /b 1
251  )
252  @set "build_command=^"!msbuild_executable!^" /m:4 /p:Configuration=%build_type% %project%.sln"
253)
254@if not defined build_command (
255  @call :log 5
256  @call :log 0 "No build command for %generator%"
257  @exit /b 1
258)
259@cd %build_path%
260@call :iso8601 iso8601
261@set output=%temp%\build-%iso8601%.log
262@call :log 7
263@call :log 2 "Build command: %build_command:"=%"
264@%build_command% > "%output%"
265@if errorlevel 1 (
266  @call :log_append "%output%"
267  @call :log 5
268  @call :log 0 "Failed to complete the build"
269  @exit /b 1
270)
271@call :log_append "%output%"
272@cd %script_folder%
273@endlocal
274@goto :eof
275
276:install - Installs the built files
277@setlocal
278@call :log 5
279@call :log 0 "Installing built files"
280@call :cmake cmake_executable
281@if errorlevel 1 (
282  @call :log 5
283  @call :log 0 "Need CMake to install the built files"
284  @exit /b 1
285)
286@call :iso8601 iso8601
287@set output=%temp%\install-%iso8601%.log
288@"%cmake_executable%" ^
289  "-DCMAKE_INSTALL_PREFIX=%install_path%" ^
290  -P "%build_path%/cmake_install.cmake" ^
291  > "%output%"
292@if errorlevel 1 (
293  @call :log_append "%output%"
294  @call :log 5
295  @call :log 0 "Failed to install the files"
296  @exit /b 1
297)
298@call :log_append "%output%"
299@endlocal
300@goto :eof
301
302:script_source - Determines if the script was ran from the cli or explorer
303:: %1 - The return variable [cli|explorer]
304@verify other 2>nul
305@setlocal EnableDelayedExpansion
306@if errorlevel 1 (
307  call :log 0 "Failed to enable extensions"
308  exit /b 1
309)
310@call :log 3 "Attempting to detect the script source"
311@echo "The invocation command was: '%cmdcmdline%'" >> %log_path%
312@for /f "tokens=1-3,*" %%a in ("%cmdcmdline%") do @(
313  set cmd=%%~a
314  set arg1=%%~b
315  set arg2=%%~c
316  set rest=%%~d
317)
318@set quote="
319@if "!arg2:~0,1!" equ "!quote!" (
320  if "!arg2:~-1!" neq "!quote!" (
321    set "arg2=!arg2:~1!"
322  )
323)
324@call :log 4 "cmd  = %cmd%"
325@call :log 4 "arg1 = %arg1%"
326@call :log 4 "arg2 = %arg2%"
327@call :log 4 "rest = %rest%"
328@call :log 4 "src  = %~f0"
329@if /i "%arg2%" == "call" (
330  set script_source=cli
331) else (
332  @if /i "%arg1%" == "/c" (
333    set script_source=explorer
334  ) else (
335    set script_source=cli
336  )
337)
338@call :log 3 "The script was invoked from %script_source%"
339@endlocal & set "%~1=%script_source%"
340@goto :eof
341
342:architecture - Finds the system architecture
343:: %1 - The return variable [x86|x86_64]
344@setlocal
345@call :log 3 "Determining the processor architecture"
346@set "key=HKLM\System\CurrentControlSet\Control\Session Manager\Environment"
347@set "var=PROCESSOR_ARCHITECTURE"
348@for /f "skip=2 tokens=2,*" %%a in ('reg query "%key%" /v "%var%"') do @set "arch=%%b"
349@if "%arch%" == "AMD64" set arch=x86_64
350@call :log 4 "arch = %arch%"
351@endlocal & set "%~1=%arch%"
352@goto :eof
353
354:md5 - Gets the MD5 checksum for a file
355:: %1 - The hash
356:: %2 - The file path
357@setlocal
358@set var=%~1
359@set file_path=%~2
360@if [%var%] == [] exit /b 1
361@if "%file_path%" == "" exit /b 1
362@if not exist "%file_path%" exit /b 1
363@for /f "skip=3 tokens=1,*" %%a in ('powershell Get-FileHash -Algorithm MD5 "'%file_path%'"') do @set hash=%%b
364@if not defined hash (
365  call :log 6
366  call :log 0 "Failed to get MD5 hash for %file_path%"
367  exit /b 1
368)
369@endlocal & set "%var%=%hash: =%"
370@goto :eof
371
372:windows_version - Checks the windows version
373:: %1 - The windows version
374:: %2 - The major version number return variable
375:: %3 - The minor version number return variable
376:: %4 - The revision version number return variable
377@setlocal
378@call :log 3 "Retrieving the Windows version"
379@for /f "tokens=2 delims=[]" %%x in ('ver') do @set win_ver=%%x
380@set win_ver=%win_ver:Version =%
381@set win_ver_major=%win_ver:~0,1%
382@set win_ver_minor=%win_ver:~2,1%
383@set win_ver_rev=%win_ver:~4%
384@call :log 4 "win_ver = %win_ver%"
385@endlocal & set "%~1=%win_ver%" ^
386          & set "%~2=%win_ver_major%" ^
387          & set "%~3=%win_ver_minor%" ^
388          & set "%~4=%win_ver_rev%"
389@goto :eof
390
391:find_in_path - Finds a program of file in the PATH
392@setlocal
393@set var=%~1
394@set file=%~2
395@if [%var%] == [] exit /b 1
396@if [%file%] == [] exit /b 1
397@call :log 3 "Searching PATH for %file%"
398@for %%x in ("%file%") do @set "file_path=%%~f$PATH:x"
399@if not defined file_path exit /b 1
400@endlocal & set "%var%=%file_path%"
401@goto :eof
402
403:administrator_check - Checks for administrator priviledges
404@setlocal
405@call :log 2 "Checking for administrator priviledges"
406@set "key=HKLM\Software\VCA\Tool Chain\Admin Check"
407@reg add "%key%" /v Elevated /t REG_DWORD /d 1 /f > nul 2>&1
408@if errorlevel 1 exit /b 1
409@reg delete "%key%" /va /f > nul 2>&1
410@endlocal
411@goto :eof
412
413:log_append - Appends another file into the current logging file
414:: %1 - the file_path to the file to concatenate
415@setlocal
416@set "file_path=%~1"
417@if [%file_path%] == [] exit /b 1
418@call :log 3 "Appending to log: %file_path%"
419@call :iso8601 iso8601
420@set "temp_log=%temp%\append-%iso8601%.log"
421@call :log 4 "Using temp file %temp_log%"
422@type "%log_path%" "%file_path%" > "%temp_log%" 2>nul
423@move /y "%temp_log%" "%log_path%" 1>nul
424@del "%file_path%" 2>nul
425@del "%temp_log%" 2>nul
426@endlocal
427@goto :eof
428
429:iso8601 - Returns the current time in ISO8601 format
430:: %1 - the return variable
431:: %2 - format [extended|basic*]
432:: iso8601 - contains the resulting timestamp
433@setlocal
434@wmic Alias /? >NUL 2>&1 || @exit /b 1
435@set "var=%~1"
436@if "%var%" == "" @exit /b 1
437@set "format=%~2"
438@if "%format%" == "" set format=basic
439@for /F "skip=1 tokens=1-6" %%g IN ('wmic Path Win32_UTCTime Get Day^,Hour^,Minute^,Month^,Second^,Year /Format:table') do @(
440  @if "%%~l"=="" goto :iso8601_done
441  @set "yyyy=%%l"
442  @set "mm=00%%j"
443  @set "dd=00%%g"
444  @set "hour=00%%h"
445  @set "minute=00%%i"
446  @set "seconds=00%%k"
447)
448:iso8601_done
449@set mm=%mm:~-2%
450@set dd=%dd:~-2%
451@set hour=%hour:~-2%
452@set minute=%minute:~-2%
453@set seconds=%seconds:~-2%
454@if /i [%format%] == [extended] (
455  set iso8601=%yyyy%-%mm%-%dd%T%hour%:%minute%:%seconds%Z
456) else (
457  if /i [%format%] == [basic] (
458    set iso8601=%yyyy%%mm%%dd%T%hour%%minute%%seconds%Z
459  ) else (
460    @exit /b 1
461  )
462)
463@set iso8601=%iso8601: =0%
464@endlocal & set %var%=%iso8601%
465@goto :eof
466
467:verbosity - Processes the verbosity parameter '/v[v...]
468:: %1 - verbosity given on the command line
469:: logging_level - set to the number of v's
470@setlocal
471@set logging_level=0
472@set verbosity=%~1
473:verbosity_loop
474@set verbosity=%verbosity:~1%
475@if not [%verbosity%] == [] @(
476  set /a "logging_level=logging_level+1"
477  goto verbosity_loop
478)
479@endlocal & set logging_level=%logging_level%
480@goto :eof
481
482:log - Logs a message, depending on verbosity
483:: %1 - level
484::       [0-4] for CLI logging
485::       [5-9] for GUI logging
486:: %2 - message to print
487@setlocal
488@set "level=%~1"
489@set "msg=%~2"
490@if "%log_folder%" == "" (
491  echo Logging was used to early in the script, log_folder isn't set yet
492  goto :eof
493)
494@if "%log_path%" == "" (
495  echo Logging was used to early in the script, log_path isn't set yet
496  goto :eof
497)
498@if not exist "%log_folder%" mkdir "%log_folder%"
499@if not exist "%log_path%" echo. 1>nul 2>"%log_path%"
500@echo.%msg% >> "%log_path%"
501@if %level% geq 5 (
502  @if [%script_source%] == [explorer] (
503    set /a "level=level-5"
504  ) else (
505    @goto :eof
506  )
507)
508@if "%logging_level%" == "" (
509  echo Logging was used to early in the script, logging_level isn't set yet
510  goto :eof
511)
512@if %logging_level% geq %level% echo.%msg% 1>&2
513@endlocal
514@goto :eof
515
516
517:start_browser - Opens the default browser to a URL
518:: %1 - the url to open
519@setlocal
520@set url=%~1
521@call :log 4 "Opening default browser: %url%"
522@start %url%
523@endlocal
524@goto :eof
525
526:find_cmake - Finds cmake on the command line or in the registry
527:: %1 - the cmake file path
528@setlocal
529@set var=%~1
530@if [%var%] == [] exit /b 1
531@call :log 6
532@call :log 6 "Finding CMake"
533@call :log 6 "--------------"
534@call :find_in_path cmake_executable cmake.exe
535@if not errorlevel 1 goto found_cmake
536@for /l %%i in (5,-1,0) do @(
537@for /l %%j in (9,-1,0) do @(
538@for /l %%k in (9,-1,0) do @(
539@for %%l in (HKCU HKLM) do @(
540@for %%m in (SOFTWARE SOFTWARE\Wow6432Node) do @(
541  @reg query "%%l\%%m\Kitware\CMake %%i.%%j.%%k" /ve > nul 2>nul
542  @if not errorlevel 1 (
543    @for /f "skip=2 tokens=2,*" %%a in ('reg query "%%l\%%m\Kitware\CMake %%i.%%j.%%k" /ve') do @(
544      @if exist "%%b\bin\cmake.exe" (
545        @set "cmake_executable=%%b\bin\cmake.exe"
546        goto found_cmake
547      )
548    )
549  )
550)))))
551@call :log 5
552@call :log 0 "Failed to find cmake"
553@exit /b 1
554:found_cmake
555@endlocal & set "%var%=%cmake_executable%"
556@goto :eof
557
558:cmake - Finds cmake and installs it if necessary
559:: %1 - the cmake file path
560@setlocal
561@set var=%~1
562@if [%var%] == [] exit /b 1
563@call :log 6
564@call :log 6 "Checking for CMake"
565@call :log 6 "------------------"
566@call :find_cmake cmake_executable cmake.exe
567@if not errorlevel 1 goto got_cmake
568@set checksum=C00267A3D3D9619A7A2E8FA4F46D7698
569@set version=3.2.2
570@call :install_nsis cmake http://www.cmake.org/files/v%version:~0,3%/cmake-%version%-win32-x86.exe %checksum%
571@if errorlevel 1 (
572  call :log 5
573  call :log 0 "Failed to install cmake"
574  @exit /b 1
575)
576@call :find_cmake cmake_executable cmake.exe
577@if not errorlevel 1 goto got_cmake
578@call :log 5
579@call :log 0 "Failed to check for cmake"
580@exit /b 1
581:got_cmake
582@endlocal & set "%var%=%cmake_executable%"
583@goto :eof
584
585:mingw - Finds MinGW, installing it if needed
586:: %1 - the compiler path that should be added to PATH
587@setlocal EnableDelayedExpansion
588@if errorlevel 1 (
589  @call :log 5
590  @call :log 0 "Failed to enable extensions"
591  @exit /b 1
592)
593@set var=%~1
594@if [%var%] == [] exit /b 1
595@call :log 6
596@call :log 6 "Checking for MinGW"
597@call :log 6 "------------------"
598@call :find_in_path gcc_executable gcc.exe
599@if not errorlevel 1 (
600  @for %%a in ("%gcc_executable%") do @set "compiler_path=%%~dpa"
601  goto got_mingw
602)
603@call :log 7
604@call :log 2 "Downloading MinGW"
605@if %logging_level% leq 1 set "logging=/q"
606@if %logging_level% gtr 1 set "logging=/v"
607@set output_path=
608@for /f %%a in ('call
609    "%script_folder%\mingw.cmd"
610    %logging%
611    /arch "%arch%"
612    "%dependency_path%"'
613) do @set "compiler_path=%%a\"
614@if not defined compiler_path (
615  @call :log_append "%output%"
616  @call :log 5
617  @call :log 0 "Failed to download MinGW"
618  @exit /b 1
619)
620:got_mingw
621@call :log 5
622@call :log 0 "Found MinGW: %compiler_path%gcc.exe"
623@endlocal & set "%var%=%compiler_path%"
624@goto :eof
625
626:msbuild - Finds MSBuild
627:: %1 - the path to MSBuild executable
628@setlocal
629@set var=%~1
630@if [%var%] == [] exit /b 1
631@call :find_in_path msbuild_executable msbuild.exe
632@if not errorlevel 1 goto got_msbuild
633@for /l %%i in (20,-1,4) do @(
634@for /l %%j in (9,-1,0) do @(
635@for %%k in (HKCU HKLM) do @(
636@for %%l in (SOFTWARE SOFTWARE\Wow6432Node) do @(
637  @reg query "%%k\%%l\Microsoft\MSBuild\%%i.%%j" /v MSBuildOverrideTasksPath > nul 2>nul
638  @if not errorlevel 1 (
639    @for /f "skip=2 tokens=2,*" %%a in ('reg query "%%k\%%l\Microsoft\MSBuild\%%i.%%j" /v MSBuildOverrideTasksPath') do @(
640      @if exist "%%bmsbuild.exe" (
641        @set "msbuild_executable=%%bmsbuild.exe"
642        goto got_msbuild
643      )
644    )
645  )
646))))
647@call :log 5
648@call :log 0 "Failed to check for MSBuild"
649@exit /b 1
650:got_msbuild
651@endlocal & set "%var%=%msbuild_executable%"
652@goto :eof
653
654:download - Downloads a file from the internet
655:: %1 - the url of the file to download
656:: %2 - the file to download to
657:: %3 - the MD5 checksum of the file (optional)
658@setlocal EnableDelayedExpansion
659@if errorlevel 1 (
660  call :print_usage "Failed to enable extensions"
661  exit /b 1
662)
663@set url=%~1
664@set file_path=%~2
665@set checksum=%~3
666@for %%a in (%file_path%) do @set dir_path=%%~dpa
667@for %%a in (%file_path%) do @set file_name=%%~nxa
668@if [%url%] == [] exit /b 1
669@if [%file_path%] == [] exit /b 1
670@if [%dir_path%] == [] exit /b 1
671@if [%file_name%] == [] exit /b 1
672@if not exist "%dir_path%" mkdir "%dir_path%"
673@call :log 1 "Downloading %url%"
674@call :iso8601 iso8601
675@set temp_path=%temp%\download-%iso8601%-%file_name%
676@call :log 3 "Using temp file %temp_path%"
677@powershell Invoke-WebRequest "%url%" -OutFile %temp_path%
678@if errorlevel 1 (
679  call :log 0 "Failed to download %url%"
680  exit /b 1
681)
682@if [%checksum%] neq [] (
683  @call :log 4 "Checking %checksum% against %temp_path%"
684  @call :md5 hash "%temp_path%"
685  if "!hash!" neq "%checksum%" (
686    call :log 0 "Failed to match checksum: %temp_path%"
687    call :log 0 "Hash    : !hash!"
688    call :log 0 "Checksum: %checksum%"
689    exit /b 1
690  ) else (
691    call :log 3 "Checksum matched: %temp_path%"
692    call :log 3 "Hash    : !hash!"
693    call :log 3 "Checksum: %checksum%"
694  )
695)
696@call :log 4 "Renaming %temp_path% to %file_path%"
697@move /y "%temp_path%" "%file_path%" 1>nul
698@endlocal
699@goto :eof
700
701:install_msi - Installs a dependency from an Microsoft Installer package (.msi)
702:: %1 - [string] name of the project to install
703:: %2 - The location of the .msi, a url must start with 'http://' or file_path
704:: %3 - The checksum of the msi (optional)
705@setlocal
706@set name=%~1
707@set file_path=%~2
708@set checksum=%~3
709@set msi=%~nx2
710@set msi_path=%dependency_path%\%msi%
711@if [%name%] == [] exit /b 1
712@if [%file_path%] == [] exit /b 1
713@if [%msi%] == [] exit /b 1
714@if [%msi_path%] == [] exit /b 1
715@for %%x in (msiexec.exe) do @set "msiexec_path=%%~f$PATH:x"
716@if "msiexec_path" == "" (
717  call :log 0 "Failed to find the Microsoft package installer (msiexec.exe)"
718  call :log 6
719  call :log 0 "Please install it from the Microsoft Download center"
720  call :log 6
721  choice /C YN /T 60 /D N /M "Would you like to go there now?"
722  if !errorlevel! equ 1 call :start_browser ^
723    "http://search.microsoft.com/DownloadResults.aspx?q=Windows+Installer"
724  exit /b 1
725)
726@call :log 6
727@call :log 1 "Installing the '%name%' dependency"
728@call :log 6 "-------------------------------------"
729@call :administrator_check
730@if errorlevel 1 (
731  call :log 0 "You must run %~nx0 in elevated mode to install '%name%'"
732  call :log 5 "Right-Click and select 'Run as Administrator'
733  call :log 0 "Install the dependency manually by running %file_path%"
734  @exit /b 740
735)
736@if [%file_path:~0,4%] == [http] (
737  if not exist "%msi_path%" (
738    call :download "%file_path%" "%msi_path%" %checksum%
739    if errorlevel 1 (
740      call :log 0 "Failed to download the %name% dependency"
741      exit /b 1
742    )
743  )
744) else (
745  call :log 2 "Copying MSI %file_path% to %msi_path%"
746  call :log 7
747  if not exist "%msi_path%" (
748    xcopy /q /y /z "%file_path%" "%msi_path%" 1>nul
749    if errorlevel 1 (
750      call :log 0 "Failed to copy the Microsoft Installer"
751      exit /b 1
752    )
753  )
754)
755@call :log 1 "Running the %msi%"
756@call :log 6
757@set msi_log=%temp%\msiexec-%timestamp%.log
758@call :log 3 "Logging to: %msi_log%"
759@msiexec /i "%msi_path%" /passive /log "%msi_log%" ALLUSERS=1
760@set msi_errorlevel=%errorlevel%
761@call :log_append "%msi_log%"
762@if %msi_errorlevel% equ 0 goto install_msi_success
763@if %msi_errorlevel% equ 3010 goto install_msi_success_reboot
764@if %msi_errorlevel% equ 1641 goto install_msi_success_reboot
765@if %msi_errorlevel% equ 3015 goto install_msi_in_progress_reboot
766@if %msi_errorlevel% equ 1615 goto install_msi_in_progress_reboot
767@call :log 0 "Microsoft Installer failed: %msi_errorlevel%"
768@call :log 0 "Install the dependency manually by running %msi_path%"
769@exit /b 1
770:install_msi_in_progress_reboot
771@call :log 0 "The installation requires a reboot to continue"
772@call :log 5
773@call :reboot
774@exit /b 1
775:install_msi_success_reboot
776@call :log 3 "The installation requires a reboot to be fully functional"
777@set reboot_required=1
778:install_msi_success
779@call :log 2 "Successfully installed %name%"
780@call :log 7
781@endlocal & set reboot_required=%reboot_required%
782@goto :eof
783
784:install_nsis - Installs a dependency from an Nullsoft Installer package (.exe)
785:: %1 - [string] name of the project to install
786:: %2 - The location of the .exe, a url must start with 'http://' or file_path
787:: %3 - The checksum of the exe (optional)
788@setlocal
789@set name=%~1
790@set file_path=%~2
791@set checksum=%~3
792@set exe=%~nx2
793@set exe_path=%dependency_path%\%exe%
794@if [%name%] == [] exit /b 1
795@if [%file_path%] == [] exit /b 1
796@if [%exe%] == [] exit /b 1
797@if [%exe_path%] == [] exit /b 1
798@call :log 6
799@call :log 1 "Installing the '%name%' dependency"
800@call :log 6 "-------------------------------------"
801@call :administrator_check
802@if errorlevel 1 (
803  call :log 0 "You must run %~nx0 in elevated mode to install '%name%'"
804  call :log 5 "Right-Click and select 'Run as Administrator'
805  call :log 0 "Install the dependency manually by running %file_path%"
806  @exit /b 740
807)
808@if [%file_path:~0,4%] == [http] (
809  if not exist "%exe_path%" (
810    call :download "%file_path%" "%exe_path%" %checksum%
811    if errorlevel 1 (
812      call :log 0 "Failed to download the %name% dependency"
813      exit /b 1
814    )
815  )
816) else (
817  call :log 2 "Copying installer %file_path% to %exe_path%"
818  call :log 7
819  if not exist "%exe_path%" (
820    xcopy /q /y /z "%file_path%" "%exe_path%" 1>nul
821    if errorlevel 1 (
822      call :log 0 "Failed to copy the Nullsoft Installer"
823      exit /b 1
824    )
825  )
826)
827@call :log 1 "Running the %exe%"
828@call :log 6
829@"%exe_path%" /S
830@set nsis_errorlevel=%errorlevel%
831@if %nsis_errorlevel% equ 0 goto install_nsis_success
832@if %nsis_errorlevel% equ 3010 goto install_nsis_success_reboot
833@if %nsis_errorlevel% equ 1641 goto install_nsis_success_reboot
834@if %nsis_errorlevel% equ 3015 goto install_nsis_in_progress_reboot
835@if %nsis_errorlevel% equ 1615 goto install_nsis_in_progress_reboot
836@call :log 0 "Nullsoft Installer failed: %nsis_errorlevel%"
837@call :log 0 "Install the dependency manually by running %exe_path%"
838@exit /b 1
839:install_nsis_in_progress_reboot
840@call :log 0 "The installation requires a reboot to continue"
841@call :log 5
842@call :reboot
843@exit /b 1
844:install_nsis_success_reboot
845@call :log 3 "The installation requires a reboot to be fully functional"
846@set reboot_required=1
847:install_nsis_success
848@call :log 2 "Successfully installed %name%"
849@call :log 7
850@endlocal & set reboot_required=%reboot_required%
851@goto :eof
852
853:reboot - Asks the user if they would like to reboot then stops the script
854@setlocal
855@call :log 6 "-------------------------------------------"
856@choice /C YN /T 60 /D N /M "The %method% requires a reboot, reboot now?"
857@set ret=%errorlevel%
858@call :log 6
859@if %ret% equ 1 (
860  @shutdown /r
861) else (
862  @call :log 0 "You will need to reboot to complete the %method%"
863  @call :log 5
864)
865@endlocal
866@goto :eof
867