1:: Make sure the extensions are enabled 2@verify other 2>nul 3@setlocal EnableExtensions 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 "script_name=%~nx0" 18@set "script_folder=%~dp0" 19@set "script_folder=%script_folder:~0,-1%" 20@set "dependency_path=%TEMP%\mingw-build-dependencies" 21 22:: Check the command line parameters 23@set logging_level=1 24:options_loop 25@if [%1] == [] goto :options_parsed 26@set "arg=%~1" 27@set one=%arg:~0,1% 28@set two=%arg:~0,2% 29@set three=%arg:~0,3% 30@if /i [%arg%] == [/?] ( 31 @call :print_usage "Downloads a specific version of MinGW" 32 @exit /b 0 33) 34@if /i [%arg%] == [/q] set quiet=true 35@if /i [%two%] == [/v] @if /i not [%three%] == [/ve] @call :verbosity "!arg!" 36@if /i [%arg%] == [/version] set "version=%~2" & shift 37@if /i [%arg%] == [/arch] set "arch=%~2" & shift 38@if /i [%arg%] == [/exceptions] set "exceptions=%~2" & shift 39@if /i [%arg%] == [/threading] set "threading=%~2" & shift 40@if /i [%arg%] == [/revision] set "revision=%~2" & shift 41@if /i not [!one!] == [/] ( 42 if not defined output_path ( 43 set output_path=!arg! 44 ) else ( 45 @call :print_usage "Too many output locations: !output_path! !arg!" ^ 46 "There should only be one output location" 47 @exit /b 1 48 ) 49) 50@shift 51@goto :options_loop 52:options_parsed 53@if defined quiet set logging_level=0 54@if not defined output_path set "output_path=%script_folder%\mingw-builds" 55@set "output_path=%output_path:/=\%" 56 57:: Set up the logging 58@set "log_folder=%output_path%\logs" 59@call :iso8601 timestamp 60@set "log_path=%log_folder%\%timestamp%.log" 61@set log_keep=10 62 63:: Get default architecture 64@if not defined arch @call :architecture arch 65 66:: Only keep a certain amount of logs 67@set /a "log_keep=log_keep-1" 68@if not exist %log_folder% @mkdir %log_folder% 69@for /f "skip=%log_keep%" %%f in ('dir /b /o-D /tc %log_folder%') do @( 70 @call :log 4 "Removing old log file %log_folder%\%%f" 71 del %log_folder%\%%f 72) 73 74:: Set up some more global variables 75@call :windows_version win_ver win_ver_major win_ver_minor win_ver_rev 76@call :script_source script_source 77@if [%script_source%] == [explorer] ( 78 set /a "logging_level=logging_level+1" 79) 80 81:: Execute the main function 82@call :main "%arch%" "%version%" "%threading%" "%exceptions%" "%revision%" 83@if errorlevel 1 ( 84 @call :log 0 "Failed to download MinGW" 85 @call :log 0 "View the log at %log_path%" 86 @exit /b 1 87) 88 89:: Stop the script if the user double clicked 90@if [%script_source%] == [explorer] ( 91 pause 92) 93 94@endlocal 95@goto :eof 96 97:: -------------------------- Functions start here ---------------------------- 98 99:main - Main function that performs the download 100:: %1 - Target architecture 101:: %2 - Version of MinGW to get [optional] 102:: %3 - Threading model [optional] 103:: %4 - Exception model [optional] 104:: %5 - Package revision [optional] 105@setlocal 106@call :log 6 107@call :log 2 "Welcome to the MinGW download script" 108@call :log 6 "------------------------------------" 109@call :log 6 110@call :log 2 "This script downloads a specific version of MinGW" 111@set "arch=%~1" 112@if "%arch%" == "" @exit /b 1 113@set "version=%~2" 114@set "threading=%~3" 115@set "exceptions=%~4" 116@set "revision=%~5" 117@call :log 3 "arch = %arch%" 118@call :log 3 "version = %version%" 119@call :log 3 "exceptions = %exceptions%" 120@call :log 3 "threading = %threading%" 121@call :log 3 "revision = %revision%" 122@call :repository repo 123@if errorlevel 1 ( 124 @call :log 0 "Failed to get the MinGW-builds repository information" 125 @exit /b 1 126) 127@call :resolve slug url "%repo%" "%arch%" "%version%" "%threading%" "%exceptions%" "%revision%" 128@if errorlevel 1 ( 129 @call :log 0 "Failed to resolve the correct URL of MinGW" 130 @exit /b 1 131) 132@call :unpack compiler_path "%url%" "%output_path%\mingw\%slug%" 133@if errorlevel 1 ( 134 @call :log 0 "Failed to unpack the MinGW archive" 135 @exit /b 1 136) 137@rmdir /s /q "%dependency_path%" 138@echo.%compiler_path% 139@endlocal 140@goto :eof 141 142:repository - Gets the MinGW-builds repository 143:: %1 - The return variable for the repository file path 144@verify other 2>nul 145@setlocal EnableDelayedExpansion 146@if errorlevel 1 ( 147 @call :log 0 "Failed to enable extensions" 148 @exit /b 1 149) 150@set "var=%~1" 151@if "%var%" == "" @exit /b 1 152@call :log 7 153@call :log 2 "Getting MinGW repository information" 154@set "url=http://downloads.sourceforge.net/project/mingw-w64/Toolchains targetting Win32/Personal Builds/mingw-builds/installer/repository.txt" 155@call :log 6 156@call :log 1 "Downloading MinGW repository" 157@set "file_path=%dependency_path%\mingw-repository.txt" 158@call :download "%url%" "%file_path%" 159@if errorlevel 1 ( 160 @call :log 0 "Failed to download the MinGW repository information" 161 @exit /b 1 162) 163@set "repository_path=%dependency_path%\repository.txt" 164@del "%repository_path%" 2>nul 165@for /f "delims=| tokens=1-6,*" %%a in (%file_path%) do @( 166 @set "version=%%~a" 167 @set "version=!version: =!" 168 @set "arch=%%~b" 169 @set "arch=!arch: =!" 170 @set "threading=%%~c" 171 @set "threading=!threading: =!" 172 @set "exceptions=%%~d" 173 @set "exceptions=!exceptions: =!" 174 @set "revision=%%~e" 175 @set "revision=!revision: =!" 176 @set "revision=!revision:rev=!" 177 @set "url=%%~f" 178 @set "url=!url:%%20= !" 179 @for /l %%a in (1,1,32) do @if "!url:~-1!" == " " set url=!url:~0,-1! 180 @echo !arch!^|!version!^|!threading!^|!exceptions!^|!revision!^|!url!>> "%repository_path%" 181) 182@del "%file_path%" 2>nul 183@endlocal & set "%var%=%repository_path%" 184@goto :eof 185 186:resolve - Gets the MinGW-builds repository 187:: %1 - The return variable for the MinGW slug 188:: %2 - The return variable for the MinGW URL 189:: %3 - The repository information to use 190:: %4 - Target architecture 191:: %5 - Version of MinGW to get [optional] 192:: %6 - Threading model [optional] 193:: %7 - Exception model [optional] 194:: %8 - Package revision [optional] 195@setlocal 196@set "slug_var=%~1" 197@if "%slug_var%" == "" @exit /b 1 198@set "url_var=%~2" 199@if "%url_var%" == "" @exit /b 1 200@set "repository=%~3" 201@if "%repository%" == "" @exit /b 1 202@set "arch=%~4" 203@if "%arch%" == "" @exit /b 1 204@call :resolve_version version "%repository%" "%arch%" "%~5" 205@if errorlevel 1 @exit /b 1 206@call :resolve_threading threading "%repository%" "%arch%" "%version%" "%~6" 207@if errorlevel 1 @exit /b 1 208@call :resolve_exceptions exceptions "%repository%" "%arch%" "%version%" "%threading%" "%~7" 209@if errorlevel 1 @exit /b 1 210@call :resolve_revision revision "%repository%" "%arch%" "%version%" "%threading%" "%exceptions%" "%~8" 211@if errorlevel 1 @exit /b 1 212@call :log 3 "Finding URL" 213@for /f "delims=| tokens=1-6" %%a in (%repository%) do @( 214 @if "%arch%" == "%%a" ( 215 @if "%version%" == "%%b" ( 216 @if "%threading%" == "%%c" ( 217 @if "%exceptions%" == "%%d" ( 218 @if "%revision%" == "%%e" ( 219 @set "url=%%f" 220) ) ) ) ) ) 221@if "%url%" == "" ( 222 @call :log 0 "Failed to resolve URL" 223 @exit /b 1 224) 225@set slug=gcc-%version%-%arch%-%threading%-%exceptions%-rev%revision% 226@call :log 2 "Resolved slug: %slug%" 227@call :log 2 "Resolved url: %url%" 228@endlocal & set "%slug_var%=%slug%" & set "%url_var%=%url%" 229@goto :eof 230 231:unpack - Unpacks the MinGW archive 232:: %1 - The return variable name for the compiler path 233:: %2 - The filepath or URL of the archive 234:: %3 - The folder to unpack to 235@verify other 2>nul 236@setlocal EnableDelayedExpansion 237@if errorlevel 1 ( 238 @call :log 0 "Failed to enable extensions" 239 @exit /b 1 240) 241@set "var=%~1" 242@if "%var%" == "" @exit /b 1 243@set "archive_path=%~2" 244@if "%archive_path%" == "" @exit /b 1 245@set "folder_path=%~3" 246@if "%folder_path%" == "" @exit /b 1 247@set "compiler_path=%folder_path%\bin" 248@if exist "%compiler_path%" goto :unpack_done 249@call :log 7 250@call :log 2 "Unpacking MinGW archive" 251@set "http=%archive_path:~0,4%" 252@if "%http%" == "http" ( 253 @set "url=%archive_path%" 254 @for /f %%a in ("!url: =-!") do @set "file_name=%%~na" 255 @for /f %%a in ("!url: =-!") do @set "file_ext=%%~xa" 256 @set "archive_path=%dependency_path%\!file_name!!file_ext!" 257 @if not exist "!archive_path!" ( 258 @call :log 6 259 @call :log 1 "Downloading MinGW archive" 260 @call :download "!url!" "!archive_path!" 261 @if errorlevel 1 ( 262 @del "!archive_path!" 2>nul 263 @call :log 0 "Failed to download: !file_name!!file_ext!" 264 @exit /b 1 265 ) 266 ) 267) 268@if not exist "%archive_path%" ( 269 @call :log 0 "The archive did not exist to unpack: %archive_path%" 270 @exit /b 1 271) 272@for /f %%a in ("%archive_path: =-%") do @set "file_name=%%~na" 273@for /f %%a in ("%archive_path: =-%") do @set "file_ext=%%~xa" 274@call :log 6 275@call :log 1 "Unpacking MinGW %file_name%%file_ext%" 276@call :find_sevenzip sevenzip_executable 277@if errorlevel 1 ( 278 @call :log 0 "Need 7zip to unpack the MinGW archive" 279 @exit /b 1 280) 281@call :iso8601 iso8601 282@for /f %%a in ("%folder_path%") do @set "tmp_path=%%~dpatmp-%iso8601%" 283@"%sevenzip_executable%" x -y "-o%tmp_path%" "%archive_path%" > nul 284@if errorlevel 1 ( 285 @rmdir /s /q "%folder_path%" 286 @call :log 0 "Failed to unpack the MinGW archive" 287 @exit /b 1 288) 289@set "expected_path=%tmp_path%\mingw64" 290@if not exist "%expected_path%" ( 291 @set "expected_path=%tmp_path%\mingw32" 292) 293@move /y "%expected_path%" "%folder_path%" > nul 294@if errorlevel 1 ( 295 @rmdir /s /q "%tmp_path%" 2>nul 296 @call :log 0 "Failed to move MinGW folder" 297 @call :log 0 "%expected_path%" 298 @call :log 0 "%folder_path%" 299 @exit /b 1 300) 301@rmdir /s /q %tmp_path% 302@set "compiler_path=%folder_path%\bin" 303:unpack_done 304@if not exist "%compiler_path%\gcc.exe" ( 305 @call :log 0 "Failed to find gcc: %compiler_path%" 306 @exit /b 1 307) 308@endlocal & set "%var%=%compiler_path%" 309@goto :eof 310 311:find_sevenzip - Finds (or downloads) the 7zip executable 312:: %1 - The return variable for the 7zip executable path 313@setlocal 314@set "var=%~1" 315@if "%var%" == "" @exit /b 1 316@call :log 2 "Finding 7zip" 317@call :find_in_path sevenzip_executable 7z.exe 318@if not errorlevel 1 goto :find_sevenzip_done 319@call :find_in_path sevenzip_executable 7za.exe 320@if not errorlevel 1 goto :find_sevenzip_done 321@set checksum=2FAC454A90AE96021F4FFC607D4C00F8 322@set "url=http://7-zip.org/a/7za920.zip" 323@for /f %%a in ("%url: =-%") do @set "file_name=%%~na" 324@for /f %%a in ("%url: =-%") do @set "file_ext=%%~xa" 325@set "archive_path=%dependency_path%\%file_name%%file_ext%" 326@if not exist "%archive_path%" ( 327 @call :log 6 328 @call :log 1 "Downloading 7zip archive" 329 @call :download "%url%" "%archive_path%" %checksum% 330 @if errorlevel 1 ( 331 @del "%archive_path%" 2>nul 332 @call :log 0 "Failed to download: %file_name%%file_ext%" 333 @exit /b 1 334 ) 335) 336@set "sevenzip_path=%dependency_path%\sevenzip" 337@if not exist "%sevenzip_path%" ( 338 @call :unzip "%archive_path%" "%sevenzip_path%" 339 @if errorlevel 1 ( 340 @call :log 0 "Failed to unzip the7zip archive" 341 @exit /b 1 342 ) 343) 344@set "sevenzip_executable=%sevenzip_path%\7za.exe" 345@if not exist "%sevenzip_executable%" ( 346 @call :log 0 "Failed to find unpacked 7zip: %sevenzip_executable%" 347 @exit /b 1 348) 349:find_sevenzip_done 350@call :log 2 "Found 7zip: %sevenzip_executable%" 351@endlocal & set "%var%=%sevenzip_executable%" 352@goto :eof 353 354:unzip - Unzips a .zip archive 355:: %1 - The archive to unzip 356:: %2 - The location to unzip to 357@setlocal 358@set "archive_path=%~1" 359@if "%archive_path%" == "" @exit /b 1 360@set "folder_path=%~2" 361@if "%folder_path%" == "" @exit /b 1 362@for /f %%a in ("%archive_path: =-%") do @set "file_name=%%~na" 363@for /f %%a in ("%archive_path: =-%") do @set "file_ext=%%~xa" 364@call :log 2 "Unzipping: %file_name%%file_ext%" 365@call :iso8601 iso8601 366@set "log_path=%temp%\unzip-%iso8601%-%file_name%.log" 367@powershell ^ 368 Add-Type -assembly "system.io.compression.filesystem"; ^ 369 [io.compression.zipfile]::ExtractToDirectory(^ 370 '%archive_path%', '%folder_path%') 2>"%log_path%" 371@if errorlevel 1 ( 372 @call :log 0 "Failed to unzip: %file_name%%file_ext%" 373 @call :log_append "%log_path%" 374 @exit /b 1 375) 376@endlocal 377@goto :eof 378 379:resolve_version - Gets the version of the MinGW compiler 380:: %1 - The return variable for the version 381:: %2 - The repository information to use 382:: %3 - The architecture of the compiler 383:: %4 - Version of MinGW to get [optional] 384@verify other 2>nul 385@setlocal EnableDelayedExpansion 386@if errorlevel 1 ( 387 @call :log 0 "Failed to enable extensions" 388 @exit /b 1 389) 390@set "var=%~1" 391@if "%var%" == "" @exit /b 1 392@set "repository=%~2" 393@if "%repository%" == "" @exit /b 1 394@set "arch=%~3" 395@if "%arch%" == "" @exit /b 1 396@set "version=%~4" 397@if not "%version%" == "" goto :resolve_version_done 398:: Find the latest version 399@call :log 3 "Finding latest version" 400@set version=0.0.0 401@for /f "delims=| tokens=1-6" %%a in (%repository%) do @( 402 @if "%arch%" == "%%a" ( 403 @call :version_compare result "%version%" "%%b" 404 @if errorlevel 1 ( 405 @call :log 0 "Failed to compare versions: %version% %%a" 406 @exit /b 1 407 ) 408 @if !result! lss 0 set version=%%b 409 ) 410) 411:resolve_version_done 412@if "%version%" == "" ( 413 @call :log 0 "Failed to resolve latest version number" 414 @exit /b 1 415) 416@call :log 2 "Resolved version: %version%" 417@endlocal & set "%var%=%version%" 418@goto :eof 419 420:resolve_threading - Gets the threading model of the MinGW compiler 421:: %1 - The return variable for the threading model 422:: %2 - The repository information to use 423:: %3 - The architecture of the compiler 424:: %4 - The version of the compiler 425:: %5 - threading model of MinGW to use [optional] 426@verify other 2>nul 427@setlocal EnableDelayedExpansion 428@if errorlevel 1 ( 429 @call :log 0 "Failed to enable extensions" 430 @exit /b 1 431) 432@set "var=%~1" 433@if "%var%" == "" @exit /b 1 434@set "repository=%~2" 435@if "%repository%" == "" @exit /b 1 436@set "arch=%~3" 437@if "%arch%" == "" @exit /b 1 438@set "version=%~4" 439@if "%version%" == "" @exit /b 1 440@set "threading=%~5" 441@if not "%threading%" == "" goto :resolve_threading_done 442@call :log 3 "Finding best threading model" 443@for /f "delims=| tokens=1-6" %%a in (%repository%) do @( 444 @if "%arch%" == "%%a" ( 445 @if "%version%" == "%%b" ( 446 @if not defined threading ( 447 @set "threading=%%c" 448 ) 449 @if "%%c" == "posix" ( 450 @set "threading=%%c" 451) ) ) ) 452:resolve_threading_done 453@if "%threading%" == "" ( 454 @call :log 0 "Failed to resolve the best threading model" 455 @exit /b 1 456) 457@call :log 2 "Resolved threading model: %threading%" 458@endlocal & set "%var%=%threading%" 459@goto :eof 460 461:resolve_exceptions - Gets the exception model of the MinGW compiler 462:: %1 - The return variable for the exception model 463:: %2 - The repository information to use 464:: %3 - The architecture of the compiler 465:: %4 - The version of the compiler 466:: %4 - The threading model of the compiler 467:: %5 - exception model of MinGW to use [optional] 468@verify other 2>nul 469@setlocal EnableDelayedExpansion 470@if errorlevel 1 ( 471 @call :log 0 "Failed to enable extensions" 472 @exit /b 1 473) 474@set "var=%~1" 475@if "%var%" == "" @exit /b 1 476@set "repository=%~2" 477@if "%repository%" == "" @exit /b 1 478@set "arch=%~3" 479@if "%arch%" == "" @exit /b 1 480@set "version=%~4" 481@if "%version%" == "" @exit /b 1 482@set "threading=%~5" 483@if "%threading%" == "" @exit /b 1 484@set "exceptions=%~6" 485@if not "%exceptions%" == "" goto :resolve_exceptions_done 486@call :log 3 "Finding best exception model" 487@for /f "delims=| tokens=1-6" %%a in (%repository%) do @( 488 @if "%arch%" == "%%a" ( 489 @if "%version%" == "%%b" ( 490 @if "%threading%" == "%%c" ( 491 @if not defined exceptions ( 492 @set "exceptions=%%d" 493 ) 494 @if "%%d" == "dwarf" ( 495 @set "exceptions=%%d" 496 ) 497 @if "%%d" == "seh" ( 498 @set "exceptions=%%d" 499) ) ) ) ) 500:resolve_exceptions_done 501@if "%exceptions%" == "" ( 502 @call :log 0 "Failed to resolve the best exception model" 503 @exit /b 1 504) 505@call :log 2 "Resolved exception model: %exceptions%" 506@endlocal & set "%var%=%exceptions%" 507@goto :eof 508 509:resolve_revision - Gets the revision of the MinGW compiler 510:: %1 - The return variable for the revision 511:: %2 - The repository information to use 512:: %3 - The architecture of the compiler 513:: %4 - The version of the compiler 514:: %4 - The threading model of the compiler 515:: %4 - The exception model of the compiler 516:: %5 - revision of the MinGW package to use [optional] 517@verify other 2>nul 518@setlocal EnableDelayedExpansion 519@if errorlevel 1 ( 520 @call :log 0 "Failed to enable extensions" 521 @exit /b 1 522) 523@set "var=%~1" 524@if "%var%" == "" @exit /b 1 525@set "repository=%~2" 526@if "%repository%" == "" @exit /b 1 527@set "arch=%~3" 528@if "%arch%" == "" @exit /b 1 529@set "version=%~4" 530@if "%version%" == "" @exit /b 1 531@set "threading=%~5" 532@if "%threading%" == "" @exit /b 1 533@set "exceptions=%~6" 534@if "%exceptions%" == "" @exit /b 1 535@set "revision=%~7" 536@if not "%revision%" == "" goto :resolve_revision_done 537@call :log 3 "Finding latest revision" 538@for /f "delims=| tokens=1-6" %%a in (%repository%) do @( 539 @if "%arch%" == "%%a" ( 540 @if "%version%" == "%%b" ( 541 @if "%threading%" == "%%c" ( 542 @if "%exceptions%" == "%%d" ( 543 @if "%%e" gtr "%revision%" ( 544 @set "revision=%%e" 545) ) ) ) ) ) 546:resolve_revision_done 547@if "%revision%" == "" ( 548 @call :log 0 "Failed to resolve latest revision" 549 @exit /b 1 550) 551@call :log 2 "Resolved revision: %revision%" 552@endlocal & set "%var%=%revision%" 553@goto :eof 554 555:version_compare - Compares two semantic version numbers 556:: %1 - The return variable: 557:: - < 0 : if %2 < %3 558:: - 0 : if %2 == %3 559:: - > 0 : if %2 > %3 560:: %2 - The first version to compare 561:: %3 - The second version to compare 562@setlocal 563@set "var=%~1" 564@if "%var%" == "" @exit /b 1 565@set "lhs=%~2" 566@if "%lhs%" == "" @exit /b 1 567@set "rhs=%~3" 568@if "%lhs%" == "" @exit /b 1 569@set result=0 570@for /f "delims=. tokens=1-6" %%a in ("%lhs%.%rhs%") do @( 571 @if %%a lss %%d ( 572 set result=-1 573 goto :version_compare_done 574 ) else ( 575 @if %%a gtr %%d ( 576 set result=1 577 goto :version_compare_done 578 ) else ( 579 @if %%b lss %%e ( 580 set result=-1 581 goto :version_compare_done 582 ) else ( 583 @if %%b gtr %%e ( 584 set result=1 585 goto :version_compare_done 586 ) else ( 587 @if %%c lss %%f ( 588 set result=-1 589 goto :version_compare_done 590 ) else ( 591 @if %%c gtr %%f ( 592 set result=1 593 goto :version_compare_done 594 ) 595 ) 596 ) 597 ) 598 ) 599 ) 600) 601:version_compare_done 602@endlocal & set "%var%=%result%" 603@goto :eof 604 605:print_usage - Prints the usage of the script 606:: %* - message to print, each argument on it's own line 607@setlocal 608@for %%a in (%*) do @echo.%%~a 609@echo. 610@echo.build [/?][/v[v...]^|/q][/version][/arch a][/threading t] 611@echo. [/exceptions e][/revision r] location 612@echo. 613@echo. /version v The version of MinGW to download 614@echo. /arch a The target architecture [i686^|x86_64] 615@echo. /threading t 616@echo. Threading model to use [posix^|win32] 617@echo. /exceptions e 618@echo. Exception model to use [sjlj^|seh^|dwarf] 619@echo. /revision e Revision of the release to use 620@echo. /v Sets the output to be more verbose 621@echo. /v[v...] Extra verbosity, /vv, /vvv, etc 622@echo. /q Quiets the output 623@echo. /? Shows this usage message 624@echo. 625@endlocal 626@goto :eof 627 628:script_source - Determines if the script was ran from the cli or explorer 629:: %1 - The return variable [cli|explorer] 630@verify other 2>nul 631@setlocal EnableDelayedExpansion 632@if errorlevel 1 ( 633 @call :log 0 "Failed to enable extensions" 634 @exit /b 1 635) 636@call :log 3 "Attempting to detect the script source" 637@echo "The invocation command was: '%cmdcmdline%'" >> %log_path% 638@for /f "tokens=1-3,*" %%a in ("%cmdcmdline%") do @( 639 set cmd=%%~a 640 set arg1=%%~b 641 set arg2=%%~c 642 set rest=%%~d 643) 644@set quote=" 645@if "!arg2:~0,1!" equ "!quote!" ( 646 if "!arg2:~-1!" neq "!quote!" ( 647 set "arg2=!arg2:~1!" 648 ) 649) 650@call :log 4 "cmd = %cmd%" 651@call :log 4 "arg1 = %arg1%" 652@call :log 4 "arg2 = %arg2%" 653@call :log 4 "rest = %rest%" 654@call :log 4 "src = %~f0" 655@if /i "%arg2%" == "call" ( 656 set script_source=cli 657) else ( 658 @if /i "%arg1%" == "/c" ( 659 set script_source=explorer 660 ) else ( 661 set script_source=cli 662 ) 663) 664@call :log 3 "The script was invoked from %script_source%" 665@endlocal & set "%~1=%script_source%" 666@goto :eof 667 668:architecture - Finds the system architecture 669:: %1 - The return variable [i686|x86_64] 670@setlocal 671@call :log 3 "Determining the processor architecture" 672@set "key=HKLM\System\CurrentControlSet\Control\Session Manager\Environment" 673@set "var=PROCESSOR_ARCHITECTURE" 674@for /f "skip=2 tokens=2,*" %%a in ('reg query "%key%" /v "%var%"') do @set "arch=%%b" 675@if "%arch%" == "AMD64" set arch=x86_64 676@if "%arch%" == "x64" set arch=i686 677@call :log 4 "arch = %arch%" 678@endlocal & set "%~1=%arch%" 679@goto :eof 680 681:md5 - Gets the MD5 checksum for a file 682:: %1 - The hash 683:: %2 - The file path 684@setlocal 685@set "var=%~1" 686@set "file_path=%~2" 687@if "%var%" == "" @exit /b 1 688@if "%file_path%" == "" @exit /b 1 689@if not exist "%file_path%" @exit /b 1 690@for /f "skip=3 tokens=1,*" %%a in ('powershell Get-FileHash -Algorithm MD5 "'%file_path%'"') do @set hash=%%b 691@if not defined hash ( 692 @call :log 6 693 @call :log 0 "Failed to get MD5 hash for %file_path%" 694 @exit /b 1 695) 696@endlocal & set "%var%=%hash: =%" 697@goto :eof 698 699:windows_version - Checks the windows version 700:: %1 - The windows version 701:: %2 - The major version number return variable 702:: %3 - The minor version number return variable 703:: %4 - The revision version number return variable 704@setlocal 705@call :log 3 "Retrieving the Windows version" 706@for /f "tokens=2 delims=[]" %%x in ('ver') do @set win_ver=%%x 707@set win_ver=%win_ver:Version =% 708@set win_ver_major=%win_ver:~0,1% 709@set win_ver_minor=%win_ver:~2,1% 710@set win_ver_rev=%win_ver:~4% 711@call :log 4 "win_ver = %win_ver%" 712@endlocal & set "%~1=%win_ver%" ^ 713 & set "%~2=%win_ver_major%" ^ 714 & set "%~3=%win_ver_minor%" ^ 715 & set "%~4=%win_ver_rev%" 716@goto :eof 717 718:find_in_path - Finds a program of file in the PATH 719:: %1 - return variable of the file path 720@setlocal 721@set "var=%~1" 722@if "%var%" == "" @exit /b 1 723@set "file=%~2" 724@if "%file%" == "" @exit /b 1 725@call :log 3 "Searching PATH for %file%" 726@for %%x in ("%file%") do @set "file_path=%%~f$PATH:x" 727@if not defined file_path @exit /b 1 728@endlocal & set "%var%=%file_path%" 729@goto :eof 730 731:log_append - Appends another file into the current logging file 732:: %1 - the file_path to the file to concatenate 733@setlocal 734@set "file_path=%~1" 735@if "%file_path%" == "" @exit /b 1 736@call :log 3 "Appending to log: %file_path%" 737@call :iso8601 iso8601 738@set temp_log=%temp%\append-%iso8601%.log 739@call :log 4 "Using temp file %temp_log%" 740@type "%log_path%" "%file_path%" > "%temp_log%" 2>nul 741@move /y "%temp_log%" "%log_path%" 1>nul 742@del "%file_path% 2>nul 743@del "%temp_log% 2>nul 744@endlocal 745@goto :eof 746 747:iso8601 - Returns the current time in ISO8601 format 748:: %1 - the return variable 749:: %2 - format [extended|basic*] 750:: iso8601 - contains the resulting timestamp 751@setlocal 752@wmic Alias /? >NUL 2>&1 || @exit /b 1 753@set "var=%~1" 754@if "%var%" == "" @exit /b 1 755@set "format=%~2" 756@if "%format%" == "" set format=basic 757@for /F "skip=1 tokens=1-6" %%g IN ('wmic Path Win32_UTCTime Get Day^,Hour^,Minute^,Month^,Second^,Year /Format:table') do @( 758 @if "%%~l"=="" goto :iso8601_done 759 @set "yyyy=%%l" 760 @set "mm=00%%j" 761 @set "dd=00%%g" 762 @set "hour=00%%h" 763 @set "minute=00%%i" 764 @set "seconds=00%%k" 765) 766:iso8601_done 767@set mm=%mm:~-2% 768@set dd=%dd:~-2% 769@set hour=%hour:~-2% 770@set minute=%minute:~-2% 771@set seconds=%seconds:~-2% 772@if /i [%format%] == [extended] ( 773 set iso8601=%yyyy%-%mm%-%dd%T%hour%:%minute%:%seconds%Z 774) else ( 775 if /i [%format%] == [basic] ( 776 set iso8601=%yyyy%%mm%%dd%T%hour%%minute%%seconds%Z 777 ) else ( 778 @exit /b 1 779 ) 780) 781@set iso8601=%iso8601: =0% 782@endlocal & set %var%=%iso8601% 783@goto :eof 784 785:verbosity - Processes the verbosity parameter '/v[v...] 786:: %1 - verbosity given on the command line 787:: logging_level - set to the number of v's 788@setlocal 789@set logging_level=0 790@set verbosity=%~1 791:verbosity_loop 792@set verbosity=%verbosity:~1% 793@if not [%verbosity%] == [] @( 794 set /a "logging_level=logging_level+1" 795 goto verbosity_loop 796) 797@endlocal & set logging_level=%logging_level% 798@goto :eof 799 800:log - Logs a message, depending on verbosity 801:: %1 - level 802:: [0-4] for CLI logging 803:: [5-9] for GUI logging 804:: %2 - message to print 805@setlocal 806@set "level=%~1" 807@set "msg=%~2" 808@if "%log_folder%" == "" ( 809 echo Logging was used to early in the script, log_folder isn't set yet 810 goto :eof 811) 812@if "%log_path%" == "" ( 813 echo Logging was used to early in the script, log_path isn't set yet 814 goto :eof 815) 816@if not exist "%log_folder%" mkdir "%log_folder%" 817@if not exist "%log_path%" echo. 1>nul 2>"%log_path%" 818@echo.%msg% >> "%log_path%" 819@if %level% geq 5 ( 820 @if [%script_source%] == [explorer] ( 821 set /a "level=level-5" 822 ) else ( 823 @goto :eof 824 ) 825) 826@if "%logging_level%" == "" ( 827 echo Logging was used to early in the script, logging_level isn't set yet 828 goto :eof 829) 830@if %logging_level% geq %level% echo.%msg% 1>&2 831@endlocal 832@goto :eof 833 834:download - Downloads a file from the internet 835:: %1 - the url of the file to download 836:: %2 - the file to download to 837:: %3 - the MD5 checksum of the file (optional) 838@setlocal EnableDelayedExpansion 839@if errorlevel 1 ( 840 @call :print_usage "Failed to enable extensions" 841 @exit /b 1 842) 843@set "url=%~1" 844@set "file_path=%~2" 845@set "checksum=%~3" 846@for %%a in (%file_path%) do @set dir_path=%%~dpa 847@for %%a in (%file_path%) do @set file_name=%%~nxa 848@if "%url%" == "" @exit /b 1 849@if "%file_path%" == "" @exit /b 1 850@if "%dir_path%" == "" @exit /b 1 851@if "%file_name%" == "" @exit /b 1 852@if not exist "%dir_path%" mkdir "%dir_path%" 853@call :log 2 "Downloading %url%" 854@call :iso8601 iso8601 855@set "temp_path=%temp%\download-%iso8601%-%file_name%" 856@set "log_path=%temp%\download-%iso8601%-log-%file_name%" 857@call :log 4 "Using temp file %temp_path%" 858@powershell Invoke-WebRequest "'%url%'" ^ 859 -OutFile "'%temp_path%'" ^ 860 -UserAgent [Microsoft.PowerShell.Commands.PSUserAgent]::IE ^ 861 1>nul 2>"%log_path%" 862@if errorlevel 1 ( 863 @call :log 0 "Failed to download %url%" 864 @call :log_append "%log_path%" 865 @exit /b 1 866) 867@if [%checksum%] neq [] ( 868 @call :log 4 "Checking %checksum% against %temp_path%" 869 @call :md5 hash "%temp_path%" 870 if "!hash!" neq "%checksum%" ( 871 @call :log 0 "Failed to match checksum: %temp_path%" 872 @call :log 0 "Hash : !hash!" 873 @call :log 0 "Checksum: %checksum%" 874 @exit /b 1 875 ) else ( 876 @call :log 3 "Checksum matched: %temp_path%" 877 @call :log 3 "Hash : !hash!" 878 @call :log 3 "Checksum: %checksum%" 879 ) 880) 881@call :log 4 "Renaming %temp_path% to %file_path%" 882@move /y "%temp_path%" "%file_path%" 1>nul 883@endlocal 884@goto :eof 885