فهرست منبع

Batch script for downloading MinGW

The script allows for a specific version of MniGW to be downloaded.
This is useful for testing compilation of the project using MinGW on
Windows build servers
Matt Clarkson 10 سال پیش
والد
کامیت
6199d6a4fa
1فایلهای تغییر یافته به همراه879 افزوده شده و 0 حذف شده
  1. 879 0
      mingw.cmd

+ 879 - 0
mingw.cmd

@@ -0,0 +1,879 @@
+:: Make sure the extensions are enabled
+@verify other 2>nul
+@setlocal EnableExtensions 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 "script_name=%~nx0"
+@set "script_folder=%~dp0"
+@set "script_folder=%script_folder:~0,-1%"
+@set "dependency_path=%TEMP%\mingw-build-dependencies"
+
+:: Check the command line parameters
+@set logging_level=1
+:options_loop
+@if [%1] == [] goto :options_parsed
+@set "arg=%~1"
+@set one=%arg:~0,1%
+@set two=%arg:~0,2%
+@set three=%arg:~0,3%
+@if /i [%arg%] == [/?] (
+  @call :print_usage "Downloads a specific version of MinGW"
+  @exit /b 0
+)
+@if /i [%arg%] == [/q] set quiet=true
+@if /i [%two%] == [/v] @if /i not [%three%] == [/ve] @call :verbosity "!arg!"
+@if /i [%arg%] == [/version] set "version=%~2" & shift
+@if /i [%arg%] == [/arch] set "arch=%~2" & shift
+@if /i [%arg%] == [/exceptions] set "exceptions=%~2" & shift
+@if /i [%arg%] == [/threading] set "threading=%~2" & shift
+@if /i [%arg%] == [/revision] set "revision=%~2" & shift
+@if /i not [!one!] == [/] (
+  if not defined output_path (
+    set output_path=!arg!
+  ) else (
+    @call :print_usage "Too many output locations: !output_path! !arg!" ^
+                       "There should only be one output location"
+    @exit /b 1
+  )
+)
+@shift
+@goto :options_loop
+:options_parsed
+@if defined quiet set logging_level=0
+@if not defined output_path set "output_path=%script_folder%\mingw-builds"
+@set "output_path=%output_path:/=\%"
+
+:: Set up the logging
+@set "log_folder=%output_path%\logs"
+@call :iso8601 timestamp
+@set "log_path=%log_folder%\%timestamp%.log"
+@set log_keep=10
+
+:: Get default architecture
+@if not defined arch @call :architecture arch
+
+:: 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 :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"
+)
+
+:: Execute the main function
+@call :main "%arch%" "%version%" "%threading%" "%exceptions%" "%revision%"
+@if errorlevel 1 (
+  @call :log 0 "Failed to download MinGW"
+  @call :log 0 "View the log at %log_path%"
+  @exit /b 1
+)
+
+:: Stop the script if the user double clicked
+@if [%script_source%] == [explorer] (
+  pause
+)
+
+@endlocal
+@goto :eof
+
+:: -------------------------- Functions start here ----------------------------
+
+:main - Main function that performs the download
+:: %1 - Target architecture
+:: %2 - Version of MinGW to get [optional]
+:: %3 - Threading model [optional]
+:: %4 - Exception model [optional]
+:: %5 - Package revision [optional]
+@setlocal
+@call :log 6
+@call :log 2 "Welcome to the MinGW download script"
+@call :log 6 "------------------------------------"
+@call :log 6
+@call :log 2 "This script downloads a specific version of MinGW"
+@set "arch=%~1"
+@if "%arch%" == "" @exit /b 1
+@set "version=%~2"
+@set "threading=%~3"
+@set "exceptions=%~4"
+@set "revision=%~5"
+@call :log 3 "arch       = %arch%"
+@call :log 3 "version    = %version%"
+@call :log 3 "exceptions = %exceptions%"
+@call :log 3 "threading  = %threading%"
+@call :log 3 "revision   = %revision%"
+@call :repository repo
+@if errorlevel 1 (
+  @call :log 0 "Failed to get the MinGW-builds repository information"
+  @exit /b 1
+)
+@call :resolve slug url "%repo%" "%arch%" "%version%" "%threading%" "%exceptions%" "%revision%"
+@if errorlevel 1 (
+  @call :log 0 "Failed to resolve the correct URL of MinGW"
+  @exit /b 1
+)
+@call :unpack compiler_path "%url%" "%output_path%\mingw\%slug%"
+@if errorlevel 1 (
+  @call :log 0 "Failed to unpack the MinGW archive"
+  @exit /b 1
+)
+@rmdir /s /q "%dependency_path%"
+@echo.%compiler_path%
+@endlocal
+@goto :eof
+
+:repository - Gets the MinGW-builds repository
+:: %1 - The return variable for the repository file path
+@verify other 2>nul
+@setlocal EnableDelayedExpansion
+@if errorlevel 1 (
+  @call :log 0 "Failed to enable extensions"
+  @exit /b 1
+)
+@set "var=%~1"
+@if "%var%" == "" @exit /b 1
+@call :log 7
+@call :log 2 "Getting MinGW repository information"
+@set "url=http://downloads.sourceforge.net/project/mingw-w64/Toolchains targetting Win32/Personal Builds/mingw-builds/installer/repository.txt"
+@call :log 6
+@call :log 1 "Downloading MinGW repository"
+@set "file_path=%dependency_path%\mingw-repository.txt"
+@call :download "%url%" "%file_path%"
+@if errorlevel 1 (
+  @call :log 0 "Failed to download the MinGW repository information"
+  @exit /b 1
+)
+@set "repository_path=%dependency_path%\repository.txt"
+@del "%repository_path%" 2>nul
+@for /f "delims=| tokens=1-6,*" %%a in (%file_path%) do @(
+  @set "version=%%~a"
+  @set "version=!version: =!"
+  @set "arch=%%~b"
+  @set "arch=!arch: =!"
+  @set "threading=%%~c"
+  @set "threading=!threading: =!"
+  @set "exceptions=%%~d"
+  @set "exceptions=!exceptions: =!"
+  @set "revision=%%~e"
+  @set "revision=!revision: =!"
+  @set "revision=!revision:rev=!"
+  @set "url=%%~f"
+  @set "url=!url:%%20= !"
+  @for /l %%a in (1,1,32) do @if "!url:~-1!" == " " set url=!url:~0,-1!
+  @echo !arch!^|!version!^|!threading!^|!exceptions!^|!revision!^|!url!>> "%repository_path%"
+)
+@del "%file_path%" 2>nul
+@endlocal & set "%var%=%repository_path%"
+@goto :eof
+
+:resolve - Gets the MinGW-builds repository
+:: %1 - The return variable for the MinGW slug
+:: %2 - The return variable for the MinGW URL
+:: %3 - The repository information to use
+:: %4 - Target architecture
+:: %5 - Version of MinGW to get [optional]
+:: %6 - Threading model [optional]
+:: %7 - Exception model [optional]
+:: %8 - Package revision [optional]
+@setlocal
+@set "slug_var=%~1"
+@if "%slug_var%" == "" @exit /b 1
+@set "url_var=%~2"
+@if "%url_var%" == "" @exit /b 1
+@set "repository=%~3"
+@if "%repository%" == "" @exit /b 1
+@set "arch=%~4"
+@if "%arch%" == "" @exit /b 1
+@call :resolve_version version "%repository%" "%arch%" "%~5"
+@if errorlevel 1 @exit /b 1
+@call :resolve_threading threading "%repository%" "%arch%" "%version%" "%~6"
+@if errorlevel 1 @exit /b 1
+@call :resolve_exceptions exceptions "%repository%" "%arch%" "%version%" "%threading%" "%~7"
+@if errorlevel 1 @exit /b 1
+@call :resolve_revision revision "%repository%" "%arch%" "%version%" "%threading%" "%exceptions%" "%~8"
+@if errorlevel 1 @exit /b 1
+@call :log 3 "Finding URL"
+@for /f "delims=| tokens=1-6" %%a in (%repository%) do @(
+  @if "%arch%" == "%%a" (
+    @if "%version%" == "%%b" (
+      @if "%threading%" == "%%c" (
+        @if "%exceptions%" == "%%d" (
+          @if "%revision%" == "%%e" (
+            @set "url=%%f"
+) ) ) ) ) )
+@if "%url%" == "" (
+  @call :log 0 "Failed to resolve URL"
+  @exit /b 1
+)
+@set slug=gcc-%version%-%arch%-%threading%-%exceptions%-rev%revision%
+@call :log 2 "Resolved slug: %slug%"
+@call :log 2 "Resolved url: %url%"
+@endlocal & set "%slug_var%=%slug%" & set "%url_var%=%url%"
+@goto :eof
+
+:unpack - Unpacks the MinGW archive
+:: %1 - The return variable name for the compiler path
+:: %2 - The filepath or URL of the archive
+:: %3 - The folder to unpack to
+@verify other 2>nul
+@setlocal EnableDelayedExpansion
+@if errorlevel 1 (
+  @call :log 0 "Failed to enable extensions"
+  @exit /b 1
+)
+@set "var=%~1"
+@if "%var%" == "" @exit /b 1
+@set "archive_path=%~2"
+@if "%archive_path%" == "" @exit /b 1
+@set "folder_path=%~3"
+@if "%folder_path%" == "" @exit /b 1
+@set "compiler_path=%folder_path%\bin"
+@if exist "%compiler_path%" goto :unpack_done
+@call :log 7
+@call :log 2 "Unpacking MinGW archive"
+@set "http=%archive_path:~0,4%"
+@if "%http%" == "http" (
+  @set "url=%archive_path%"
+  @for /f %%a in ("!url: =-!") do @set "file_name=%%~na"
+  @for /f %%a in ("!url: =-!") do @set "file_ext=%%~xa"
+  @set "archive_path=%dependency_path%\!file_name!!file_ext!"
+  @if not exist "!archive_path!" (
+    @call :log 6
+    @call :log 1 "Downloading MinGW archive"
+    @call :download "!url!" "!archive_path!"
+    @if errorlevel 1 (
+      @del "!archive_path!" 2>nul
+      @call :log 0 "Failed to download: !file_name!!file_ext!"
+      @exit /b 1
+    )
+  )
+)
+@if not exist "%archive_path%" (
+  @call :log 0 "The archive did not exist to unpack: %archive_path%"
+  @exit /b 1
+)
+@for /f %%a in ("%archive_path: =-%") do @set "file_name=%%~na"
+@for /f %%a in ("%archive_path: =-%") do @set "file_ext=%%~xa"
+@call :log 6
+@call :log 1 "Unpacking MinGW %file_name%%file_ext%"
+@call :find_sevenzip sevenzip_executable
+@if errorlevel 1 (
+  @call :log 0 "Need 7zip to unpack the MinGW archive"
+  @exit /b 1
+)
+@call :iso8601 iso8601
+@for /f %%a in ("%folder_path%") do @set "tmp_path=%%~dpatmp-%iso8601%"
+@"%sevenzip_executable%" x -y "-o%tmp_path%" "%archive_path%" > nul
+@if errorlevel 1 (
+  @rmdir /s /q "%folder_path%"
+  @call :log 0 "Failed to unpack the MinGW archive"
+  @exit /b 1
+)
+@set "expected_path=%tmp_path%\mingw64"
+@if not exist "%expected_path%" (
+  @set "expected_path=%tmp_path%\mingw32"
+)
+@move /y "%expected_path%" "%folder_path%" > nul
+@if errorlevel 1 (
+  @rmdir /s /q "%tmp_path%" 2>nul
+  @call :log 0 "Failed to move MinGW folder"
+  @call :log 0 "%expected_path%"
+  @call :log 0 "%folder_path%"
+  @exit /b 1
+)
+@rmdir /s /q %tmp_path%
+@set "compiler_path=%folder_path%\bin"
+:unpack_done
+@if not exist "%compiler_path%\gcc.exe" (
+  @call :log 0 "Failed to find gcc: %compiler_path%"
+  @exit /b 1
+)
+@endlocal & set "%var%=%compiler_path%"
+@goto :eof
+
+:find_sevenzip - Finds (or downloads) the 7zip executable
+:: %1 - The return variable for the 7zip executable path
+@setlocal
+@set "var=%~1"
+@if "%var%" == "" @exit /b 1
+@call :log 2 "Finding 7zip"
+@call :find_in_path sevenzip_executable 7z.exe
+@if not errorlevel 1 goto :find_sevenzip_done
+@call :find_in_path sevenzip_executable 7za.exe
+@if not errorlevel 1 goto :find_sevenzip_done
+@set checksum=2FAC454A90AE96021F4FFC607D4C00F8
+@set "url=http://7-zip.org/a/7za920.zip"
+@for /f %%a in ("%url: =-%") do @set "file_name=%%~na"
+@for /f %%a in ("%url: =-%") do @set "file_ext=%%~xa"
+@set "archive_path=%dependency_path%\%file_name%%file_ext%"
+@if not exist "%archive_path%" (
+  @call :log 6
+  @call :log 1 "Downloading 7zip archive"
+  @call :download "%url%" "%archive_path%" %checksum%
+  @if errorlevel 1 (
+    @del "%archive_path%" 2>nul
+    @call :log 0 "Failed to download: %file_name%%file_ext%"
+    @exit /b 1
+  )
+)
+@set "sevenzip_path=%dependency_path%\sevenzip"
+@if not exist "%sevenzip_path%" (
+  @call :unzip "%archive_path%" "%sevenzip_path%"
+  @if errorlevel 1 (
+    @call :log 0 "Failed to unzip the7zip archive"
+    @exit /b 1
+  )
+)
+@set "sevenzip_executable=%sevenzip_path%\7za.exe"
+@if not exist "%sevenzip_executable%" (
+  @call :log 0 "Failed to find unpacked 7zip: %sevenzip_executable%"
+  @exit /b 1
+)
+:find_sevenzip_done
+@call :log 2 "Found 7zip: %sevenzip_executable%"
+@endlocal & set "%var%=%sevenzip_executable%"
+@goto :eof
+
+:unzip - Unzips a .zip archive
+:: %1 - The archive to unzip
+:: %2 - The location to unzip to
+@setlocal
+@set "archive_path=%~1"
+@if "%archive_path%" == "" @exit /b 1
+@set "folder_path=%~2"
+@if "%folder_path%" == "" @exit /b 1
+@for /f %%a in ("%archive_path: =-%") do @set "file_name=%%~na"
+@for /f %%a in ("%archive_path: =-%") do @set "file_ext=%%~xa"
+@call :log 2 "Unzipping: %file_name%%file_ext%"
+@powershell ^
+  Add-Type -assembly "system.io.compression.filesystem"; ^
+  [io.compression.zipfile]::ExtractToDirectory(^
+    '%archive_path%', '%folder_path%') 2>nul
+@if errorlevel 1 (
+  @call :log 0 "Failed to unzip: %file_name%%file_ext%"
+  @exit /b 1
+)
+@endlocal
+@goto :eof
+
+:resolve_version - Gets the version of the MinGW compiler
+:: %1 - The return variable for the version
+:: %2 - The repository information to use
+:: %3 - The architecture of the compiler
+:: %4 - Version of MinGW to get [optional]
+@verify other 2>nul
+@setlocal EnableDelayedExpansion
+@if errorlevel 1 (
+  @call :log 0 "Failed to enable extensions"
+  @exit /b 1
+)
+@set "var=%~1"
+@if "%var%" == "" @exit /b 1
+@set "repository=%~2"
+@if "%repository%" == "" @exit /b 1
+@set "arch=%~3"
+@if "%arch%" == "" @exit /b 1
+@set "version=%~4"
+@if not "%version%" == "" goto :resolve_version_done
+:: Find the latest version
+@call :log 3 "Finding latest version"
+@set version=0.0.0
+@for /f "delims=| tokens=1-6" %%a in (%repository%) do @(
+  @if "%arch%" == "%%a" (
+    @call :version_compare result "%version%" "%%b"
+    @if errorlevel 1 (
+      @call :log 0 "Failed to compare versions: %version% %%a"
+      @exit /b 1
+    )
+    @if !result! lss 0 set version=%%b
+  )
+)
+:resolve_version_done
+@if "%version%" == "" (
+  @call :log 0 "Failed to resolve latest version number"
+  @exit /b 1
+)
+@call :log 2 "Resolved version: %version%"
+@endlocal & set "%var%=%version%"
+@goto :eof
+
+:resolve_threading - Gets the threading model of the MinGW compiler
+:: %1 - The return variable for the threading model
+:: %2 - The repository information to use
+:: %3 - The architecture of the compiler
+:: %4 - The version of the compiler
+:: %5 - threading model of MinGW to use [optional]
+@verify other 2>nul
+@setlocal EnableDelayedExpansion
+@if errorlevel 1 (
+  @call :log 0 "Failed to enable extensions"
+  @exit /b 1
+)
+@set "var=%~1"
+@if "%var%" == "" @exit /b 1
+@set "repository=%~2"
+@if "%repository%" == "" @exit /b 1
+@set "arch=%~3"
+@if "%arch%" == "" @exit /b 1
+@set "version=%~4"
+@if "%version%" == "" @exit /b 1
+@set "threading=%~5"
+@if not "%threading%" == "" goto :resolve_threading_done
+@call :log 3 "Finding best threading model"
+@for /f "delims=| tokens=1-6" %%a in (%repository%) do @(
+  @if "%arch%" == "%%a" (
+    @if "%version%" == "%%b" (
+      @if not defined threading (
+        @set "threading=%%c"
+      )
+      @if "%%c" == "posix" (
+        @set "threading=%%c"
+) ) ) )
+:resolve_threading_done
+@if "%threading%" == "" (
+  @call :log 0 "Failed to resolve the best threading model"
+  @exit /b 1
+)
+@call :log 2 "Resolved threading model: %threading%"
+@endlocal & set "%var%=%threading%"
+@goto :eof
+
+:resolve_exceptions - Gets the exception model of the MinGW compiler
+:: %1 - The return variable for the exception model
+:: %2 - The repository information to use
+:: %3 - The architecture of the compiler
+:: %4 - The version of the compiler
+:: %4 - The threading model of the compiler
+:: %5 - exception model of MinGW to use [optional]
+@verify other 2>nul
+@setlocal EnableDelayedExpansion
+@if errorlevel 1 (
+  @call :log 0 "Failed to enable extensions"
+  @exit /b 1
+)
+@set "var=%~1"
+@if "%var%" == "" @exit /b 1
+@set "repository=%~2"
+@if "%repository%" == "" @exit /b 1
+@set "arch=%~3"
+@if "%arch%" == "" @exit /b 1
+@set "version=%~4"
+@if "%version%" == "" @exit /b 1
+@set "threading=%~5"
+@if "%threading%" == "" @exit /b 1
+@set "exceptions=%~6"
+@if not "%exceptions%" == "" goto :resolve_exceptions_done
+@call :log 3 "Finding best exception model"
+@for /f "delims=| tokens=1-6" %%a in (%repository%) do @(
+  @if "%arch%" == "%%a" (
+    @if "%version%" == "%%b" (
+      @if "%threading%" == "%%c" (
+        @if not defined exceptions (
+          @set "exceptions=%%d"
+        )
+        @if "%%d" == "dwarf" (
+          @set "exceptions=%%d"
+        )
+        @if "%%d" == "seh" (
+          @set "exceptions=%%d"
+) ) ) ) )
+:resolve_exceptions_done
+@if "%exceptions%" == "" (
+  @call :log 0 "Failed to resolve the best exception model"
+  @exit /b 1
+)
+@call :log 2 "Resolved exception model: %exceptions%"
+@endlocal & set "%var%=%exceptions%"
+@goto :eof
+
+:resolve_revision - Gets the revision of the MinGW compiler
+:: %1 - The return variable for the revision
+:: %2 - The repository information to use
+:: %3 - The architecture of the compiler
+:: %4 - The version of the compiler
+:: %4 - The threading model of the compiler
+:: %4 - The exception model of the compiler
+:: %5 - revision of the MinGW package to use [optional]
+@verify other 2>nul
+@setlocal EnableDelayedExpansion
+@if errorlevel 1 (
+  @call :log 0 "Failed to enable extensions"
+  @exit /b 1
+)
+@set "var=%~1"
+@if "%var%" == "" @exit /b 1
+@set "repository=%~2"
+@if "%repository%" == "" @exit /b 1
+@set "arch=%~3"
+@if "%arch%" == "" @exit /b 1
+@set "version=%~4"
+@if "%version%" == "" @exit /b 1
+@set "threading=%~5"
+@if "%threading%" == "" @exit /b 1
+@set "exceptions=%~6"
+@if "%exceptions%" == "" @exit /b 1
+@set "revision=%~7"
+@if not "%revision%" == "" goto :resolve_revision_done
+@call :log 3 "Finding latest revision"
+@for /f "delims=| tokens=1-6" %%a in (%repository%) do @(
+  @if "%arch%" == "%%a" (
+    @if "%version%" == "%%b" (
+      @if "%threading%" == "%%c" (
+        @if "%exceptions%" == "%%d" (
+          @if "%%e" gtr "%revision%" (
+            @set "revision=%%e"
+) ) ) ) ) )
+:resolve_revision_done
+@if "%revision%" == "" (
+  @call :log 0 "Failed to resolve latest revision"
+  @exit /b 1
+)
+@call :log 2 "Resolved revision: %revision%"
+@endlocal & set "%var%=%revision%"
+@goto :eof
+
+:version_compare - Compares two semantic version numbers
+:: %1 - The return variable:
+::        - < 0 : if %2 < %3
+::        -   0 : if %2 == %3
+::        - > 0 : if %2 > %3
+:: %2 - The first version to compare
+:: %3 - The second version to compare
+@setlocal
+@set "var=%~1"
+@if "%var%" == "" @exit /b 1
+@set "lhs=%~2"
+@if "%lhs%" == "" @exit /b 1
+@set "rhs=%~3"
+@if "%lhs%" == "" @exit /b 1
+@set result=0
+@for /f "delims=. tokens=1-6" %%a in ("%lhs%.%rhs%") do @(
+  @if %%a lss %%d (
+    set result=-1
+    goto :version_compare_done
+  ) else (
+    @if %%a gtr %%d (
+      set result=1
+      goto :version_compare_done
+    ) else (
+      @if %%b lss %%e (
+        set result=-1
+        goto :version_compare_done
+      ) else (
+        @if %%b gtr %%e (
+          set result=1
+          goto :version_compare_done
+        ) else (
+          @if %%c lss %%f (
+            set result=-1
+            goto :version_compare_done
+          ) else (
+            @if %%c gtr %%f (
+              set result=1
+              goto :version_compare_done
+            )
+          )
+        )
+      )
+    )
+  )
+)
+:version_compare_done
+@endlocal & set "%var%=%result%"
+@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][/version][/arch a][/threading t]
+@echo.      [/exceptions e][/revision r] location
+@echo.
+@echo.  /version v  The version of MinGW to download
+@echo.  /arch a     The target architecture [i686^|x86_64]
+@echo.  /threading t
+@echo.              Threading model to use [posix^|win32]
+@echo.  /exceptions e
+@echo.              Exception model to use [sjlj^|seh^|dwarf]
+@echo.  /revision e Revision of the release to use
+@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
+
+: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 [i686|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
+@if "%arch%" == "x64" set arch=i686
+@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
+:: %1 - return variable of the file path
+@setlocal
+@set "var=%~1"
+@if "%var%" == "" @exit /b 1
+@set "file=%~2"
+@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
+
+: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
+
+: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 2 "Downloading %url%"
+@call :iso8601 iso8601
+@set "temp_path=%temp%\download-%iso8601%-%file_name%"
+@call :log 4 "Using temp file %temp_path%"
+@powershell Invoke-WebRequest "'%url%'" ^
+  -OutFile "'%temp_path%'" ^
+  -UserAgent [Microsoft.PowerShell.Commands.PSUserAgent]::IE ^
+  1> nul 2> nul
+@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