How to use a tool installed by Nuget in your build scripts

My last post covered tips for people creating Nuget packages. This one is important for people consuming Nuget packages.

Some Nuget packages include executables in their tools folder. It is very easy to use these tools within Visual Studio because Nuget makes them available in the path of the Package Manager Console. However, they are very difficult to use outside of Visual Studio, especially in a build script. The problem is the name of the folder containing the installed package includes the version number of the package. If you install NUnit 2.5.1, the nunit-console.exe will be in packages\NUnit.2.5.1\tools. However, if you later upgrade to NUnit.2.5.2, the path to nunit-console.exe will change to packages\NUnit.2.5.2\tools. You will need to change your build scripts every time you upgrade your version of NUnit. That is unacceptable.

The solution is to create a helper that can figure out where the tool lives. If you are using rake for build automation, it is fairly straightforward:

# Usage: nunit_path = tool "NUnit", "nunit-console.exe"

def tool(package, tool)
  File.join(Dir.glob(File.join(package_root,"#{package}.*")).sort.last, "tools", tool)
end

If not, you may want to create a batch file in the root of your project that calls your tool. You can create a tool specific batch file:

@ECHO OFF
SETLOCAL
REM You might prefer specific scripts for each tool. Makes the usage a bit easier. This is an example for NUnit.

FOR /R %~dp0\source\packages %%G IN (nunit-console.exe) DO (
  IF EXIST %%G (
    SET TOOLPATH=%%G
    GOTO FOUND
  )
)
IF '%TOOLPATH%'=='' GOTO NOTFOUND

:FOUND
%TOOLPATH% %*
GOTO :EOF

:NOTFOUND
ECHO nunit-console not found.
EXIT /B 1

Or, if you have lots of tools from different packages, you might just want a generic batch file that allows you to specify the executable name:

@ECHO OFF
SETLOCAL
REM This can be used for any .exe installed by a nuget package
REM Example usage: nuget_tool.bat nunit-console.exe myproject.tests.dll
SET TOOL=%1
FOR /R %~dp0\source\packages %%G IN (%TOOL%) DO (
  IF EXIST %%G (
    SET TOOLPATH=%%G
    GOTO FOUND
  )
)
IF '%TOOLPATH%'=='' GOTO NOTFOUND

:FOUND
%TOOLPATH% %2 %3 %4 %5 %6 %7 %8 %9
GOTO :EOF

:NOTFOUND
ECHO %TOOL% not found.
EXIT /B 1

Related Articles:

This entry was posted in Uncategorized. Bookmark the permalink. Follow any comments here with the RSS feed for this post.
  • http://twitter.com/rayoneill Ray O’Neill

    top-of-my-head powershell version, save as nunit.ps1 in root directory
    $filename = $args[0]$scriptDir = [System.IO.Path]::GetDirectoryName($myInvocation.MyCommand.Definition)$packagesDir = Join-Path $scriptDir “sourcepackages”$exePath = dir $packagesDir -recurse | where { $_.PSIsContainer -eq $false -and $_.Name -eq $filename } | foreach { $_.FullName } | sort -descending | select -first 1$argString = “”for($count = 1; $count -lt $args.Length; $count++){    $argString = $argString + $args[$count]}$cmdline = $exePath + ” ” + $argStringInvoke-Expression $cmdline

    Then your build can call powershell.exe full-path-to-nunit.ps1 nunit-console.exe arg1 arg2 arg3 ‘`”arg with spaces`”‘
    Probably a billion ways to do this. Thanks for occupying my Sunday morning :)

  • Mark

    I found an easier fix. Apparently ‘CD” does work with wildcards. So in your build event you do:
    CD “$(SolutionDir)packagesMyAwesomeTool*tools”
    CALL MyAwesomeTool.cmd