update-vsintegration.cmd 28.1 KB
Newer Older
1
@rem ===========================================================================================================
2 3
@rem Copyright (c) Microsoft Corporation.  All Rights Reserved.
@rem               See License.txt in the project root for license information.
4 5
@rem ===========================================================================================================

6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
@rem Notes/instructions for modifications:
@rem
@rem * Do not use "::" for comments, as the line will be parsed and can create spurious 
@rem   errors, i.e. if it contains variables, "|" or ">"  characters, esp. within "IF" 
@rem   and "FOR" compound statements
@rem
@rem * The coloring method uses the colors from color /h through a hacky trick with findstr. 
@rem   Only use filename-safe characters if you use CALL :colorEcho
@rem
@rem * Parts of this batch file require administrator permission. If such permissions aren't
@rem   available, a warning will be issued and relevant parts will not be executed.
@rem
@rem * Currently, only one paramter is parsed and combinations are not possible
@rem
@rem * Installation of F# FSC compiler and FSI are done in the SHARED SDK directory. Henceforth
@rem   each installation of Visual Studio 2017 will use the updated FSC.exe and the commandline
@rem   FSI.exe. The in-product VS FSI plugin, syntax highlighting and IntelliSense must be 
23
@rem   installed through VSIXInstaller.exe debug\net40\bin\VisualFSharpFull.vsix
24 25 26
@rem   
@rem   This procedure needs to be changed once F# supports multiple side-by-side installations
@rem   at which point everything will go through VSIXInstaller.exe
27

28 29
@echo off
setlocal EnableDelayedExpansion
30

31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66
rem Count errors, warnings and succesful copies
set ERRORCOUNT=0
set WARNCOUNT=0
set COPYCOUNT=0

rem Enable colors, but can ONLY BE USED WITH PRINTING LINES THAT FIT IN A FILENAME!
for /F "tokens=1,2 delims=#" %%a in ('"prompt #$H#$E# & echo on & for %%b in (1) do     rem"') do (
  set "DEL=%%a"
)

if /i "%1" == "debug" (
    set ACTION=debug
    set DEPLOY=yes
    set BINDIR=%~dp0..\%1\net40\bin
    goto :ok
)
if /i "%1" == "release" (
    set ACTION=release
    set DEPLOY=yes
    set BINDIR=%~dp0..\%1\net40\bin
    goto :ok
)
if /i "%1" == "restore" (
    set ACTION=restore
    set DEPLOY=no
    set BINDIR=%~dp0..\%1
    goto :ok
)
if /i "%1" == "backup" (
    set ACTION=backup
    set DEPLOY=no
    set BINDIR=%~dp0..\restore
    goto :ok
)

set GOTOHELP=yes
67 68 69

:ok

70
set RESTOREDIR=%~dp0..\restore
71
set TOPDIR=%~dp0..
72

73 74 75 76 77 78 79 80 81 82 83 84 85
rem By using a token that does not exist in paths, this will resolve any ".." and "." in the path, even if path contains spaces
FOR /F "tokens=*" %%I IN ("%RESTOREDIR%") DO set RESTOREDIR=%%~fI
FOR /F "tokens=*" %%I IN ("%BINDIR%") DO set BINDIR=%%~fI
FOR /F "tokens=*" %%I IN ("%TOPDIR%") DO set TOPDIR=%%~fI

if /i "%GOTOHELP%" == "yes" goto :help
GOTO :start


:help

echo.
echo Installs or restores F# SDK bits, which applies system-wide to all Visual Studio
86
echo 2017 installations. After running this, each project targeting F# 4.5 will use
87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119
echo your locally built FSC.exe. It will not update other F# tools, see remarks below.
echo.
echo Requires Administrator privileges for removing/restoring strong-naming.
echo.
echo Syntax: %0 [debug^|release^|restore^|backup]
echo.
echo   debug     integrates debug builds of FSC, FSI ^& tools
echo   release   integrates release builds of FSC, FSI ^& tools
echo   restore   restores original SDK from an earlier backup
echo   backup    backups the files that would be overwritten, does not deploy anything
echo.
echo Paths used:
echo.
echo Root location:        %TOPDIR%
echo Debug bin location:   %TOPDIR%\debug\net40\bin
echo Release bin location: %TOPDIR%\release\net40\bin
echo Backup location:      %RESTOREDIR%
echo.
echo Remarks:
echo.
echo This script should only be run after build.cmd has completed successfully.
echo.
echo Clearing the git repository may clear the backup directory. To be on the safe
echo side, you should place a copy of the backup dir outside of the git repo.
echo.
echo This batch script will only update the relevant SDK bits, and remove or restore
echo strong-naming automatically. It is recommended that you also update the F# Tools
echo by running the following two commands after a build of "build vs" or
echo "build vs debug" has completed. More instructions in DEVGUIDE.md in the root.
echo.
echo For Release builds:
echo.
echo ^> VSIXInstaller.exe /u:"VisualFSharp"
120
echo ^> VSIXInstaller.exe release\net40\bin\VisualFSharpFull.vsix
121 122 123 124
echo.
echo For Debug builds:
echo.
echo ^> VSIXInstaller.exe /u:"VisualFSharp"
125
echo ^> VSIXInstaller.exe debug\net40\bin\VisualFSharpFull.vsix
126 127 128 129 130 131 132 133 134 135 136 137 138 139
echo.

exit /b 1

:start

echo.
if "%DEPLOY%" == "yes" echo Starting deployment of %ACTION% bits.
if not "%DEPLOY%" == "yes" echo Starting %ACTION%
echo.

rem This check whether we're started with administrator rights
CALL :checkPrequisites

140 141 142
if /i "%PROCESSOR_ARCHITECTURE%"=="x86" set X86_PROGRAMFILES=%ProgramFiles%
if /I "%PROCESSOR_ARCHITECTURE%"=="AMD64" set X86_PROGRAMFILES=%ProgramFiles(x86)%

143 144 145
set REGEXE32BIT=reg.exe
if not "%OSARCH%"=="x86" set REGEXE32BIT=%WINDIR%\syswow64\reg.exe

146 147
rem See https://stackoverflow.com/a/17113667/111575 on 2^>NUL for suppressing the error "ERROR: The system was unable to find the specified registry key or value." from reg.exe, this fixes #3619
rem The delims are a TAB and a SPACE, do not normalize it!
148 149 150 151 152 153 154
                            FOR /F "tokens=2* delims=	 " %%A IN ('%REGEXE32BIT% QUERY "HKLM\Software\WOW6432Node\Microsoft\Microsoft SDKs\NETFXSDK\4.6.2\WinSDK-NetFx40Tools" /v InstallationFolder 2^>NUL') DO SET WINSDKNETFXTOOLS=%%B
if "%WINSDKNETFXTOOLS%"=="" FOR /F "tokens=2* delims=	 " %%A IN ('%REGEXE32BIT% QUERY "HKLM\Software\WOW6432Node\Microsoft\Microsoft SDKs\NETFXSDK\4.6.1\WinSDK-NetFx40Tools" /v InstallationFolder 2^>NUL') DO SET WINSDKNETFXTOOLS=%%B
if "%WINSDKNETFXTOOLS%"=="" FOR /F "tokens=2* delims=	 " %%A IN ('%REGEXE32BIT% QUERY "HKLM\Software\Microsoft\Microsoft SDKs\NETFXSDK\4.6\WinSDK-NetFx40Tools" /v InstallationFolder 2^>NUL') DO SET WINSDKNETFXTOOLS=%%B
if "%WINSDKNETFXTOOLS%"=="" FOR /F "tokens=2* delims=	 " %%A IN ('%REGEXE32BIT% QUERY "HKLM\Software\Microsoft\Microsoft SDKs\Windows\v8.1A\WinSDK-NetFx40Tools" /v InstallationFolder 2^>NUL') DO SET WINSDKNETFXTOOLS=%%B
if "%WINSDKNETFXTOOLS%"=="" FOR /F "tokens=2* delims=	 " %%A IN ('%REGEXE32BIT% QUERY "HKLM\Software\Microsoft\Microsoft SDKs\Windows\v8.0A\WinSDK-NetFx40Tools" /v InstallationFolder 2^>NUL') DO SET WINSDKNETFXTOOLS=%%B
if "%WINSDKNETFXTOOLS%"=="" FOR /F "tokens=2* delims=	 " %%A IN ('%REGEXE32BIT% QUERY "HKLM\Software\Microsoft\Microsoft SDKs\Windows\v7.1\WinSDK-NetFx40Tools" /v InstallationFolder 2^>NUL') DO SET WINSDKNETFXTOOLS=%%B
if "%WINSDKNETFXTOOLS%"=="" FOR /F "tokens=2* delims=	 " %%A IN ('%REGEXE32BIT% QUERY "HKLM\Software\Microsoft\Microsoft SDKs\Windows\v7.0A\WinSDK-NetFx40Tools" /v InstallationFolder 2^>NUL') DO SET WINSDKNETFXTOOLS=%%B
155

156 157
set SN32="%WINSDKNETFXTOOLS%sn.exe"
set SN64="%WINSDKNETFXTOOLS%x64\sn.exe"
158 159 160
set NGEN32=%windir%\Microsoft.NET\Framework\v4.0.30319\ngen.exe
set NGEN64=%windir%\Microsoft.NET\Framework64\v4.0.30319\ngen.exe

161 162
set FSHARPVERSION=4.3
set FSHARPVERSION2=43
D
Don Syme 已提交
163

164 165 166
rem The various locations of the SDK and tools

rem SDK path, will be created if it doesn't exist
D
Don Syme 已提交
167
set COMPILERSDKPATH=%X86_PROGRAMFILES%\Microsoft SDKs\F#\%FSHARPVERSION%\Framework\v4.0
168

169
rem Main assemblies path, will be created if it doesn't exist
170
set COMPILERMAINASSEMBLIESPATH=%X86_PROGRAMFILES%\Reference Assemblies\Microsoft\FSharp\.NETFramework\v4.0\4.%FSHARPVERSION%.0
171

172
rem The .NET Core 3.7 assemblies path, will be created if it doesn't exist
173
set COMPILER7ASSEMBLIESPATH=%X86_PROGRAMFILES%\Reference Assemblies\Microsoft\FSharp\.NETCore\3.7.%FSHARPVERSION2%.0
174

175
rem The .NET Core 3.78 assemblies path, will be created if it doesn't exist
176
set COMPILER78ASSEMBLIESPATH=%X86_PROGRAMFILES%\Reference Assemblies\Microsoft\FSharp\.NETCore\3.78.%FSHARPVERSION2%.0
177

178
rem The .NET Core 3.259 assemblies path, will be created if it doesn't exist
179
set COMPILER259ASSEMBLIESPATH=%X86_PROGRAMFILES%\Reference Assemblies\Microsoft\FSharp\.NETCore\3.259.%FSHARPVERSION2%.0
180

181
rem The .NET Portable 3.47 assemblies path, will be created if it doesn't exist
182
set COMPILER47ASSEMBLIESPATH=%X86_PROGRAMFILES%\Reference Assemblies\Microsoft\FSharp\.NETPortable\3.47.%FSHARPVERSION2%.0
183

184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218
rem Try to create target and backup folders, if needed
set RESTOREBASE=%RESTOREDIR%

rem Only create backup dirs if we are backupping or restoring 
rem (in the latter case, the directories should already be there, but if not, it prevents errors later on)
if "!DEPLOY!" == "no" (
    CALL :tryCreateFolder "!RESTOREBASE!\compiler_sdk"
    CALL :tryCreateFolder "!RESTOREBASE!\main_assemblies"
    CALL :tryCreateFolder "!RESTOREBASE!\profile_7"
    CALL :tryCreateFolder "!RESTOREBASE!\profile_78"
    CALL :tryCreateFolder "!RESTOREBASE!\profile_259"
    CALL :tryCreateFolder "!RESTOREBASE!\profile_47"
)
CALL :tryCreateFolder "!COMPILERSDKPATH!"
CALL :tryCreateFolder "!COMPILERMAINASSEMBLIESPATH!"
CALL :tryCreateFolder "!COMPILER7ASSEMBLIESPATH!" & 
CALL :tryCreateFolder "!COMPILER78ASSEMBLIESPATH!"
CALL :tryCreateFolder "!COMPILER259ASSEMBLIESPATH!"
CALL :tryCreateFolder "!COMPILER47ASSEMBLIESPATH!"

rem If one or more directories could not be created, exit early with a non-zero error code
if "!CREATEFAILED!"=="true" CALL :exitFailDir & EXIT /B 1

rem Deploying main files, fsi.exe and fsc.exe and related

echo.
CALL :colorEcho 02 "[!ACTION!] Processing files for compiler_sdk" & echo.

set SOURCEDIR=%BINDIR%
set RESTOREDIR=!RESTOREBASE!\compiler_sdk
CALL :checkAvailability compiler_sdk
if "!BIN_AVAILABLE!" == "true" (
    CALL :backupAndOrCopy fsc.exe "!COMPILERSDKPATH!"
    CALL :backupAndOrCopy fsc.exe.config "%COMPILERSDKPATH%"
    CALL :backupAndOrCopy FSharp.Build.dll "%COMPILERSDKPATH%"
219
    CALL :backupAndOrCopy FSharp.Compiler.Service.dll "%COMPILERSDKPATH%"
220 221 222 223 224 225 226 227 228
    CALL :backupAndOrCopy FSharp.Compiler.Interactive.Settings.dll "%COMPILERSDKPATH%"
    CALL :backupAndOrCopy fsi.exe "%COMPILERSDKPATH%"
    CALL :backupAndOrCopy fsi.exe.config "%COMPILERSDKPATH%"
    CALL :backupAndOrCopy fsiAnyCpu.exe "%COMPILERSDKPATH%"
    CALL :backupAndOrCopy fsiAnyCpu.exe.config "%COMPILERSDKPATH%"
    CALL :backupAndOrCopy Microsoft.FSharp.Targets "%COMPILERSDKPATH%"
    CALL :backupAndOrCopy Microsoft.Portable.FSharp.Targets "%COMPILERSDKPATH%"
    CALL :backupAndOrCopy Microsoft.FSharp.NetSdk.props "%COMPILERSDKPATH%"
    CALL :backupAndOrCopy Microsoft.FSharp.NetSdk.targets "%COMPILERSDKPATH%"
229
    CALL :backupAndOrCopy Microsoft.FSharp.Overrides.NetSdk.targets "%COMPILERSDKPATH%"
230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253

    rem Special casing for SupportedRuntimes.xml, it has a different source directory, it's always there
    set SOURCEDIR="%TOPDIR%\vsintegration\src\SupportedRuntimes"
    CALL :backupAndOrCopy SupportedRuntimes.xml "%COMPILERSDKPATH%"
)



rem Deploying main assemblies

echo.
CALL :colorEcho 02 "[!ACTION!] Processing files for main_assemblies" & echo.

set SOURCEDIR=%BINDIR%
set RESTOREDIR=!RESTOREBASE!\main_assemblies
CALL :checkAvailability main_assemblies
if "!BIN_AVAILABLE!" == "true" (
    CALL :backupAndOrCopy FSharp.Core.dll "%COMPILERMAINASSEMBLIESPATH%"
    CALL :backupAndOrCopy FSharp.Core.xml "%COMPILERMAINASSEMBLIESPATH%"
)

 

REM TODO: this was already here (2017-09-28) and was already commented out, I think (AB) that these redirects aren't necessary anymore and can be permanently removed
254
REM echo ^<configuration^>^<runtime^>^<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1" appliesTo="v4.0.30319"^>^<dependentAssembly^>^<assemblyIdentity name="FSharp.Core" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" /^> ^<bindingRedirect oldVersion="2.0.0.0-4.%FSHARPVERSION%.0" newVersion="4.%FSHARPVERSION%.0"/^>^</dependentAssembly^>^</assemblyBinding^>^</runtime^>^</configuration^> > "%X86_PROGRAMFILES%\Reference Assemblies\Microsoft\FSharp\.NETFramework\v4.0\4.%FSHARPVERSION%.0\pub.config"
255

256 257 258 259 260 261 262 263 264 265 266
rem To add registry keys and to change strong-name validation requires Administrator access 

if "%DEPLOY%" == "yes" if "!ISADMIN!" == "yes" (
    echo.
    CALL :colorEcho 02 "[!ACTION!] Setting or adding registry keys for open source assemblies" & echo.
    if /I "!PROCESSOR_ARCHITECTURE!"=="AMD64" (
        REG ADD "HKLM\SOFTWARE\Wow6432Node\Microsoft\.NETFramework\v4.0.30319\AssemblyFoldersEx\F# !FSHARPVERSION! Core Assemblies (Open Source)" /ve /t REG_SZ /f /d "!X86_PROGRAMFILES!\Reference Assemblies\Microsoft\FSharp\.NETFramework\v4.0\4.!FSHARPVERSION!.0\
        REG ADD "HKLM\SOFTWARE\Wow6432Node\Microsoft\.NETFramework\v4.0.50709\AssemblyFoldersEx\F# !FSHARPVERSION! Core Assemblies (Open Source)" /ve /t REG_SZ /f /d "!X86_PROGRAMFILES!\Reference Assemblies\Microsoft\FSharp\.NETFramework\v4.0\4.!FSHARPVERSION!.0\
    )
    REG ADD "HKLM\SOFTWARE\Microsoft\.NETFramework\v4.0.30319\AssemblyFoldersEx\F# !FSHARPVERSION! Core Assemblies (Open Source)" /ve /t REG_SZ /f /d "!X86_PROGRAMFILES!\Reference Assemblies\Microsoft\FSharp\.NETFramework\v4.0\4.!FSHARPVERSION!.0\
    REG ADD "HKLM\SOFTWARE\Microsoft\.NETFramework\v4.0.50709\AssemblyFoldersEx\F# !FSHARPVERSION! Core Assemblies (Open Source)" /ve /t REG_SZ /f /d "!X86_PROGRAMFILES!\Reference Assemblies\Microsoft\FSharp\.NETFramework\v4.0\4.!FSHARPVERSION!.0\
267

268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284
    rem Disable strong-name validation for F# binaries built from open source that are signed with the microsoft key
    echo.
    CALL :colorEcho 02 "[!ACTION!] Removing strong-name validation of F# binaries" & echo.
    !SN32! -Vr FSharp.Core,b03f5f7f11d50a3a 1>NUL 2>NUL
    !SN32! -Vr FSharp.Build,b03f5f7f11d50a3a 1>NUL 2>NUL
    !SN32! -Vr FSharp.Compiler.Interactive.Settings,b03f5f7f11d50a3a 1>NUL 2>NUL
    !SN32! -Vr HostedCompilerServer,b03f5f7f11d50a3a 1>NUL 2>NUL

    !SN32! -Vr FSharp.Compiler,b03f5f7f11d50a3a 1>NUL 2>NUL
    !SN32! -Vr FSharp.Compiler.Server.Shared,b03f5f7f11d50a3a 1>NUL 2>NUL
    !SN32! -Vr FSharp.Editor,b03f5f7f11d50a3a 1>NUL 2>NUL
    !SN32! -Vr FSharp.LanguageService,b03f5f7f11d50a3a 1>NUL 2>NUL
    !SN32! -Vr FSharp.LanguageService.Base,b03f5f7f11d50a3a 1>NUL 2>NUL
    !SN32! -Vr FSharp.ProjectSystem.Base,b03f5f7f11d50a3a 1>NUL 2>NUL
    !SN32! -Vr FSharp.ProjectSystem.FSharp,b03f5f7f11d50a3a 1>NUL 2>NUL
    !SN32! -Vr FSharp.ProjectSystem.PropertyPages,b03f5f7f11d50a3a 1>NUL 2>NUL
    !SN32! -Vr FSharp.VS.FSI,b03f5f7f11d50a3a 1>NUL 2>NUL
285
    !SN32! -Vr VisualFSharp.UnitTests,b03f5f7f11d50a3a 1>NUL 2>NUL
286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303
    !SN32! -Vr VisualFSharp.Salsa,b03f5f7f11d50a3a 1>NUL 2>NUL

    REM Do this *in addition* to the above for x64 systems
    if /i "!PROCESSOR_ARCHITECTURE!"=="AMD64" (
        !SN64! -Vr FSharp.Core,b03f5f7f11d50a3a 1>NUL 2>NUL
        !SN64! -Vr FSharp.Build,b03f5f7f11d50a3a 1>NUL 2>NUL
        !SN64! -Vr FSharp.Compiler.Interactive.Settings,b03f5f7f11d50a3a 1>NUL 2>NUL
        !SN64! -Vr HostedCompilerServer,b03f5f7f11d50a3a 1>NUL 2>NUL

        !SN64! -Vr FSharp.Compiler,b03f5f7f11d50a3a 1>NUL 2>NUL
        !SN64! -Vr FSharp.Compiler.Server.Shared,b03f5f7f11d50a3a 1>NUL 2>NUL
        !SN64! -Vr FSharp.Editor,b03f5f7f11d50a3a 1>NUL 2>NUL
        !SN64! -Vr FSharp.LanguageService,b03f5f7f11d50a3a 1>NUL 2>NUL
        !SN64! -Vr FSharp.LanguageService.Base,b03f5f7f11d50a3a 1>NUL 2>NUL
        !SN64! -Vr FSharp.ProjectSystem.Base,b03f5f7f11d50a3a 1>NUL 2>NUL
        !SN64! -Vr FSharp.ProjectSystem.FSharp,b03f5f7f11d50a3a 1>NUL 2>NUL
        !SN64! -Vr FSharp.ProjectSystem.PropertyPages,b03f5f7f11d50a3a 1>NUL 2>NUL
        !SN64! -Vr FSharp.VS.FSI,b03f5f7f11d50a3a 1>NUL 2>NUL
304
        !SN64! -Vr VisualFSharp.UnitTests,b03f5f7f11d50a3a 1>NUL 2>NUL
305 306 307
        !SN64! -Vr VisualFSharp.Salsa,b03f5f7f11d50a3a 1>NUL 2>NUL
    )

308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338
    rem NGen fsc, fsi, fsiAnyCpu, and FSharp.Build.dll
    
    echo.
    CALL :colorEcho 02 "[!ACTION!] Queuing for NGEN of FSI and FSC binaries" & echo.
    echo [!ACTION!] NGEN of "!COMPILERSDKPATH!\fsc.exe"
    "!NGEN32!" install "!COMPILERSDKPATH!\fsc.exe" /queue:1 1>NUL
    echo [!ACTION!] NGEN of "!COMPILERSDKPATH!\fsi.exe"
    "!NGEN32!" install "!COMPILERSDKPATH!\fsi.exe" /queue:1 1>NUL
    echo [!ACTION!] NGEN of "!COMPILERSDKPATH!\fsiAnyCpu.exe"
    "!NGEN32!" install "!COMPILERSDKPATH!\fsiAnyCpu.exe" /queue:1 1>NUL
    echo [!ACTION!] NGEN of "!COMPILERSDKPATH!\FSharp.Build.dll"
    "!NGEN32!" install "!COMPILERSDKPATH!\FSharp.Build.dll" /queue:1 1>NUL
    
    if /i "!PROCESSOR_ARCHITECTURE!"=="AMD64" (
        echo [!ACTION!] NGEN64 of "!COMPILERSDKPATH!\fsiAnyCpu.exe"
        "!NGEN64!" install "!COMPILERSDKPATH!\fsiAnyCpu.exe" /queue:1 1>NUL
        echo [!ACTION!] NGEN64 of "!COMPILERSDKPATH!\FSharp.Build.dll"
        "!NGEN64!" install "!COMPILERSDKPATH!\FSharp.Build.dll" /queue:1 1>NUL
    )
)

if "%DEPLOY%" == "yes" if "!ISADMIN!" == "no" (
    echo.
    CALL :colorEcho 0E "[!ACTION!] SKIPPED (no admin) Setting or adding registry keys for open source assemblies" & echo.
    CALL :colorEcho 0E "[!ACTION!] SKIPPED (no admin) Removing strong-name validation of F# binaries" & echo.
    CALL :colorEcho 02 "[!ACTION!] SKIPPED (no admin) Queuing for NGEN of FSI and FSC binaries" & echo.
    SET /A WARNCOUNT+=3
)

rem Re-enable certain settings when restoring, NGEN the original files again, requires admin rights
if "%ACTION%" == "restore" if "!ISADMIN!" == "yes" (
339

340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356
    rem Re-enable strong-name validation for F# binaries that were previously installed
    echo.
    CALL :colorEcho 02 "[!ACTION!] Re-enabling strong-name validation of original F# binaries" & echo.
    !SN32! -Vu FSharp.Core,b03f5f7f11d50a3a 2>NUL 1>NUL
    !SN32! -Vu FSharp.Build,b03f5f7f11d50a3a 2>NUL 1>NUL
    !SN32! -Vu FSharp.Compiler.Interactive.Settings,b03f5f7f11d50a3a 2>NUL 1>NUL
    !SN32! -Vu HostedCompilerServer,b03f5f7f11d50a3a 2>NUL 1>NUL

    !SN32! -Vu FSharp.Compiler,b03f5f7f11d50a3a 2>NUL 1>NUL
    !SN32! -Vu FSharp.Compiler.Server.Shared,b03f5f7f11d50a3a 2>NUL 1>NUL
    !SN32! -Vu FSharp.Editor,b03f5f7f11d50a3a 2>NUL 1>NUL
    !SN32! -Vu FSharp.LanguageService,b03f5f7f11d50a3a 2>NUL 1>NUL
    !SN32! -Vu FSharp.LanguageService.Base,b03f5f7f11d50a3a 2>NUL 1>NUL
    !SN32! -Vu FSharp.ProjectSystem.Base,b03f5f7f11d50a3a 2>NUL 1>NUL
    !SN32! -Vu FSharp.ProjectSystem.FSharp,b03f5f7f11d50a3a 2>NUL 1>NUL
    !SN32! -Vu FSharp.ProjectSystem.PropertyPages,b03f5f7f11d50a3a 2>NUL 1>NUL
    !SN32! -Vu FSharp.VS.FSI,b03f5f7f11d50a3a 2>NUL 1>NUL
357
    !SN32! -Vu VisualFSharp.UnitTests,b03f5f7f11d50a3a 2>NUL 1>NUL
358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375
    !SN32! -Vu VisualFSharp.Salsa,b03f5f7f11d50a3a 2>NUL 1>NUL

    REM Do this *in addition* to the above for x64 systems
    if /i "!PROCESSOR_ARCHITECTURE!"=="AMD64" (
        !SN64! -Vu FSharp.Core,b03f5f7f11d50a3a 2>NUL 1>NUL
        !SN64! -Vu FSharp.Build,b03f5f7f11d50a3a 2>NUL 1>NUL
        !SN64! -Vu FSharp.Compiler.Interactive.Settings,b03f5f7f11d50a3a 2>NUL 1>NUL
        !SN64! -Vu HostedCompilerServer,b03f5f7f11d50a3a 2>NUL 1>NUL

        !SN64! -Vu FSharp.Compiler,b03f5f7f11d50a3a 2>NUL 1>NUL
        !SN64! -Vu FSharp.Compiler.Server.Shared,b03f5f7f11d50a3a 2>NUL 1>NUL
        !SN64! -Vu FSharp.Editor,b03f5f7f11d50a3a 2>NUL 1>NUL
        !SN64! -Vu FSharp.LanguageService,b03f5f7f11d50a3a 2>NUL 1>NUL
        !SN64! -Vu FSharp.LanguageService.Base,b03f5f7f11d50a3a 2>NUL 1>NUL
        !SN64! -Vu FSharp.ProjectSystem.Base,b03f5f7f11d50a3a 2>NUL 1>NUL
        !SN64! -Vu FSharp.ProjectSystem.FSharp,b03f5f7f11d50a3a 2>NUL 1>NUL
        !SN64! -Vu FSharp.ProjectSystem.PropertyPages,b03f5f7f11d50a3a 2>NUL 1>NUL
        !SN64! -Vu FSharp.VS.FSI,b03f5f7f11d50a3a 2>NUL 1>NUL
376
        !SN64! -Vu VisualFSharp.UnitTests,b03f5f7f11d50a3a 2>NUL 1>NUL
377 378 379
        !SN64! -Vu VisualFSharp.Salsa,b03f5f7f11d50a3a 2>NUL 1>NUL
    )

380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423
    rem NGen fsc, fsi, fsiAnyCpu, and FSharp.Build.dll
    
    echo.
    CALL :colorEcho 02 "[!ACTION!] Queuing for NGEN of FSI and FSC binaries" & echo.
    echo [!ACTION!] NGEN of "!COMPILERSDKPATH!\fsc.exe"
    "!NGEN32!" install "!COMPILERSDKPATH!\fsc.exe" /queue:1 1>NUL
    echo [!ACTION!] NGEN of "!COMPILERSDKPATH!\fsi.exe"
    "!NGEN32!" install "!COMPILERSDKPATH!\fsi.exe" /queue:1 1>NUL
    echo [!ACTION!] NGEN of "!COMPILERSDKPATH!\fsiAnyCpu.exe"
    "!NGEN32!" install "!COMPILERSDKPATH!\fsiAnyCpu.exe" /queue:1 1>NUL
    echo [!ACTION!] NGEN of "!COMPILERSDKPATH!\FSharp.Build.dll"
    "!NGEN32!" install "!COMPILERSDKPATH!\FSharp.Build.dll" /queue:1 1>NUL
    
    if /i "!PROCESSOR_ARCHITECTURE!"=="AMD64" (
        echo [!ACTION!] NGEN64 of "!COMPILERSDKPATH!\fsiAnyCpu.exe"
        "!NGEN64!" install "!COMPILERSDKPATH!\fsiAnyCpu.exe" /queue:1 1>NUL
        echo [!ACTION!] NGEN64 of "!COMPILERSDKPATH!\FSharp.Build.dll"
        "!NGEN64!" install "!COMPILERSDKPATH!\FSharp.Build.dll" /queue:1 1>NUL
    )
)

if "%ACTION%" == "restore" if "!ISADMIN!" == "no" (
    CALL :colorEcho 0E "[!ACTION!] SKIPPED (no admin) Re-enabling strong-name validation of original F# binaries" & echo.
    CALL :colorEcho 0E "[!ACTION!] SKIPPED (no admin) Queuing for NGEN of FSI and FSC binaries" & echo.
    set /A WARNCOUNT+=2
)
GOTO :summary

:checkAvailability
rem Checks whether a given source is available, issues a warning otherwise, SOURCEDIR must be set to the appropriate binaries

rem This will simultaneously remove the quotes of the original param and add the filename to it, then it is surrounded by quotes again
FOR /F "usebackq tokens=*" %%I IN ('%SOURCEDIR%')  DO set SOURCE="%%~fI\*"
if not exist !SOURCE! (
    rem For debug and release deploy it matters, but for restore and backup we don't care
    set BIN_AVAILABLE=true
    if "!DEPLOY!" == "yes" (
        echo [!ACTION!] Source bindir does not exist: !SOURCE!
        CALL :colorEcho 0E "[!ACTION!] Source binaries not found, deploy of %1 skipped" & echo. & set /A WARNCOUNT+=1
        set BIN_AVAILABLE=false
    )
    
) else (
    set BIN_AVAILABLE=true
424
)
425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607

EXIT /B

  
:backupAndOrCopy
rem Creates a backup and copies, depending on whether debug, release, restore or backup is selected

rem This will simultaneously remove the quotes of the original param and add the filename to it, then it is surrounded by quotes again
FOR /F "usebackq tokens=*" %%I IN ('%2')           DO set TARGET="%%~fI\%1"
FOR /F "usebackq tokens=*" %%I IN ('%RESTOREDIR%') DO set BACKUP="%%~fI\%1"
FOR /F "usebackq tokens=*" %%I IN ('%SOURCEDIR%')  DO set SOURCE="%%~fI\%1"

if "%ACTION%" == "backup" (
    rem When backing up, the target becomes the source
    
    if not exist !TARGET! (
        rem Remove a file from the backup location if it is not part of this SDK install
        DEL /f !BACKUP! 1>NUL 2>NUL
    ) else (
        rem Otherwise, copy over the original
        CALL :copyFile !TARGET! !BACKUP!
    )
)

if "%ACTION%" == "restore" (
    rem When restoring, the backup location becomes the source
    
    if not exist !BACKUP! (
        rem If this file didn't exist in the previous installation, we should remove it to prevent confusion of left-over bits
        DEL /f !TARGET! 1>NUL 2>NUL
    ) else (
        rem Otherwise, copy over the original
        CALL :copyFile !BACKUP! !TARGET!
    )
)

if "%DEPLOY%" == "yes" (
    rem Deploy of debug or release build, depending on selected action
    CALL :copyFile !SOURCE! !TARGET!
)


EXIT /B

rem Copies a file and logs errors in red, warnings in yellow
:copyFile 
FOR /F "usebackq tokens=*" %%I IN ('%1') DO set SOURCE="%%~fI"
FOR /F "usebackq tokens=*" %%I IN ('%2') DO set TARGET="%%~fI"

echo [%ACTION%] source: !SOURCE!
echo [%ACTION%] target: !TARGET!
if EXIST !SOURCE! (
    copy /y !SOURCE! !TARGET! 1>NUL 2>copyresult.log
    if "!errorlevel!" == "0" echo [!ACTION!] 1 file copied & set /A COPYCOUNT+=1
    if not "!errorlevel!" == "0" (
        set /p COPYRESULT=<copyresult.log 
        CALL :colorEcho 0C "[!ACTION!] !COPYRESULT!"  & echo.
        

        rem No admin right needed to *read* from program-files, but admin rights usually required to write to program-files.
        if "!ISADMIN!" == "no" (
            if not "!ACTION!" == "backup" (
                CALL :colorEcho 0C "[!ACTION!] No admin rights detected, try again with elevated permissions (run as Administrator)" & echo. & set /A ERRORCOUNT+=1
            )
        ) else (
            CALL :colorEcho 0C "[!ACTION!] Failed copying this file; make sure the file is not in use and is not read-only, system or hidden." & echo. & set /A ERRORCOUNT+=1
        )
    )
    del copyresult.log 2>nul
    set COPYRESULT=
) else (
    if "%ACTION%" == "backup"  CALL [backup] File not found, nothing to backup
    if "%ACTION%" == "restore" CALL :colorEcho 0E "[restore] File not found, not able to restore, possibly it didn't exist originally" & echo. & set /A WARNCOUNT+=1
    if "%DEPLOY%" == "yes"     CALL :colorEcho 0C "[!ACTION!] File not found, not able to deploy" & echo. & set /A ERRORCOUNT+=1
)

EXIT /B

rem Creates a folder, if it already exists, it will do nothing, if there's an access-denied, it will set %CREATEFAILED% to true
:tryCreateFolder

rem Add a backslash safely, by taking care of auxiliary quotes
FOR /F "usebackq tokens=*" %%I IN ('%1') DO set FOLDER_TO_BE_CREATED="%%~fI\"

if not exist !FOLDER_TO_BE_CREATED! (
    mkdir !FOLDER_TO_BE_CREATED! 2>NUL
    if "!errorlevel!" EQU "0" (
        echo [!ACTION!] Created directory !FOLDER_TO_BE_CREATED!
    ) else (
        set CREATEFAILED=true
        echo Failed to create %1
        CALL :colorEcho 0C "Could not create directory, check access rights or whether a file with that name exists "
        echo.
        echo.
    )
) 

EXIT /B

:summary

echo.
if not "%ACTION%" == "restore" if not "%ACTION%" == "backup" echo Finished installing F# SDK and other bits. The following directories were updated and & echo a backup is written to %RESTOREDIR%.
if "%ACTION%" == "restore" echo Finished restoring original F# SDK and other bits. The following directories were used while & echo restoring a backup from %RESTOREDIR%.
if "%ACTION%" == "backup" echo Finished creating a backup in %RESTOREBASE%.

echo.
echo Root location:         %TOPDIR%
if "!ACTION!" == "debug"    echo Debug bin location:    %TOPDIR%\debug\net40\bin
if "!ACTION!" == "release"  echo Release bin location:  %TOPDIR%\release\net40\bin
if "!DEPLOY!" == "no"       echo Backup location:       %RESTOREBASE%
echo.
echo Target locations used:
echo.
echo Win SDK tools:               %WINSDKNETFXTOOLS%
echo Compiler SDK path:           %COMPILERSDKPATH%
echo F# compiler main assemblies: %COMPILERMAINASSEMBLIESPATH%
echo Portable profile 7:          %COMPILER7ASSEMBLIESPATH%
echo Portable profile 78:         %COMPILER78ASSEMBLIESPATH%
echo Portable profile 259:        %COMPILER259ASSEMBLIESPATH%
echo Portable profile 47:         %COMPILER47ASSEMBLIESPATH%
echo.

rem Display success, warning, error counts

if "%ACTION%" == "backup"   SET VERB=backed up
if "%ACTION%" == "restore"  SET VERB=restored
if "%DEPLOY%" == "yes"      SET VERB=deployed
CALL :colorEcho 0A "A total of %COPYCOUNT% file(s) were %VERB%." & echo.

if %ERRORCOUNT% equ 1 CALL :colorEcho 0C "%ERRORCOUNT% error reported, see log" & echo.
if %ERRORCOUNT% gtr 1 CALL :colorEcho 0C "%ERRORCOUNT% errors reported, see log" & echo.
if %ERRORCOUNT% equ 0 CALL :colorEcho 0A "No errors reported" & echo.

if %WARNCOUNT% equ 1 CALL :colorEcho 0E "%WARNCOUNT% warning reported, see log" & echo.
if %WARNCOUNT% gtr 1 CALL :colorEcho 0E "%WARNCOUNT% warnings reported, see log" & echo.
if %WARNCOUNT% equ 0 CALL :colorEcho 0A "No warnings reported" & echo.

rem Return non-zero error code for use-cases where this script is called from other scripts
if %ERRORCOUNT% gtr 0 EXIT /B 1
EXIT /B 0

GOTO :EOF

:exitFailDir

echo.
CALL :colorEcho 0C "One or more directories failed to be created. No files have been copied." & echo.
echo.
echo Possible causes include:
echo - Insufficient rights to create directories in this folder
echo - A file with that name already exists
echo.
echo No error is raised if the directory exists.
echo No files were copied or backed up.
echo.

rem Return non-zero error code for use-cases where this script is called from other scripts
EXIT /B 1

:checkPrequisites
rem Whether or not we have administrator rights

SET ISADMIN=yes

rem The error level of NET SESSION is set to 2 when you don't have administrator rights, simplest hack
net sessions 1>NUL 2>NUL
if %ERRORLEVEL% GTR 0 (
    SET ISADMIN=no
    CALL :colorEcho 0E "[!ACTION!] Started without administrator access, strong-naming will not be adjusted, reg-keys not changed" & echo.    
    SET /A WARNCOUNT+=1
)

EXIT /B


rem See: https://stackoverflow.com/a/21666354/111575
rem Prevent accidentally entering the colorEcho label
GOTO :EOF
:colorEcho
<nul set /p ".=%DEL%" > "%~2"
findstr /v /a:%1 /R "^$" "%~2" nul
del "%~2" > nul 2>&1i