Monday, August 4, 2014

One-Click Builds

A clean source code repository can build itself with a single double-click. MSBuild can be configured to clean and build your entire repository, but there is still the hassle of actually locating and invoking MSBuild.exe. Being the purist that I am, I adopted this StackOverflow question to create a batch file that fill search your system for MSBuild and use it to call the specified project with the specified parameters:

invokemsbuild.bat

@echo off
setlocal
set RegistryKey=HKLM\SOFTWARE\Microsoft\MSBuild\ToolsVersions\4.0

if NOT DEFINED MSBuildOptions goto MSBuildOptionsUnset
if NOT DEFINED BuildScript goto BuildScriptUnset

reg query %RegistryKey% /v MSBuildToolsPath > NUL
if ERRORLEVEL 1 goto MissingRegKey

for /f "skip=2 tokens=3" %%A in ('reg query %RegistryKey% /v MSBuildToolsPath') do set MSBuildExe=%%AMSBuild.exe
if NOT EXIST "%MSBuildExe%" goto MissingMSBuild

"%MSBuildExe%" "%BuildScript%" %MSBuildOptions%
if ERRORLEVEL 1 goto BuildFailed

goto Return

:MSBuildOptionsUnset
echo Variable 'MSBuildOptions' is unset.
pause
goto Return

:BuildScriptUnset
echo Variable 'BuildScript' is unset.
pause
goto Return

:MissingRegKey
echo Missing MSBuuild tools registry key "%RegistryKey%".
pause
goto Return

:MissingMSBuild
echo pause Unable to locate MSBuild at "%MSBuildExe%".
pause
goto Return

:BuildFailed
pause
goto Return

:Return
endlocal

Having this batch file, I can then create another one to run a particular target in my build script:

fullbuild.bat

@echo off
setlocal
set BuildScript=%~dp0..\build.proj
set MSBuildOptions=/t:FullBuild
call "%~dp0invokemsbuild.bat"
endlocal

A few things to note in the above scripts:

  • They can be invoked from anywhere. A good batch file is not sensitive to the current working directory of the command prompt. The fullbuild.bat file uses '%~dp0', which is command-prompt-ese for 'give me the directory of the currently executing batch file' to locate the build script and invokemsbuild.bat.
  • They do not modify the environment variables of the calling command prompt. Shell programming basically only has global state, so good batch files will clean up after themselves. The setlocal and endlocal commands can be used to push environment variable frames on a stack and pop them to achieve this end.
  • They do not modify the current working directory of the calling command prompt. Similar to above, a good batch script doesn't alter global state. These particular scripts don't actually change the directory directly, but if you use the cd command in your scripts, you can use pushd and popd in a similar fashion to setlocal and endlocal.
  • They use the pause command on error conditions. This way, the batch files can be invoked from Windows Explorer, and the prompt stays open if anything goes wrong. If all is well, they will close automatically.
  • Extraneous output is suppressed. The script uses the redirect operator to the null file - '> NUL' - to gobble up a command's output so that it is not displayed, and the @echo off command makes it so that the commands in the batch file are not echoed to the command prompt.

An incredibly helpful command processor reference can be found here.

No comments:

Post a Comment