dotnet / msbuild

The Microsoft Build Engine (MSBuild) is the build platform for .NET and Visual Studio.
https://docs.microsoft.com/visualstudio/msbuild/msbuild
MIT License
5.23k stars 1.35k forks source link

Using tools (exe, ps1) from nuget package - package path property #1857

Closed kukjevov closed 7 years ago

kukjevov commented 7 years ago

Is it currently possible to get path to some package, since i want to use executable in my target?

Lets imagine situation where i have custom targets. I want to install package NuGet.CommandLine which contains nuget.exe and i want to use it from my custom target from <exec> element. How can i get path to this exe which is set as dependency for my project.

Thank you

jeffkl commented 7 years ago

There is currently no built in way to do this. NuGet does generate an project.assets.json file which provides a hint path of where packages are located.

{
  "libraries": {
    "NuGet.CommandLine/3.5.0": {
      "sha512": "hXv/6hCKfdvzvuD+ww9uOhHBb2YerRvswtfPNBzY0MdxZLXB3M8z9LvlYhCVJYt+OBmtbwof+cg6TlZ8kmFXfg==",
      "type": "package",
      "path": "nuget.commandline/3.5.0",
      "files": [
        "nuget.commandline.3.5.0.nupkg.sha512",
        "nuget.commandline.nuspec",
        "tools/NuGet.exe"
      ]
    }
  },
  "packageFolders": {
    "C:\\Users\\UserA\\.nuget\\packages": {}
  }
}

We could possibly add a method to ToolLocationHelper that would locate the package and return its path. It would still be up to the target author to provide the rest of the path like tools\NuGet.exe. We don't currently have a way to parse JSON so we'd need to reference and ship something to do it.

Perhaps the NuGet folks should provide a task:

<Target Name="RunMyTool">
  <GetNuGetToolPath PackageId="NuGet.CommandLine">
      <Output TaskParameter="ToolPath" PropertyName="MyToolPath" />
  </GetNuGetToolPath>

  <Exec Command="$(MyToolPath)" />
</Target>

This would rely on NuGet shipping a <GetNuGetToolPath /> task in their SDK. @rrelyea does NuGet have any potential plans here?

The DotNet CLI was working on functionality like this, @NTaylorMullen might know more, or at least who would. I think it would only work if your build is running under dotnet.exe.

dasMulli commented 7 years ago

The NuGet package path is available as $(NuGetPackageFolders) and could be used to determine the location of a tool - provided you know package name and version as well as the tool's file name (as long as NuGet's package cache folder structure doesn't change):

<Exec Command="$(NuGetPackageFolders)nuget.commandline\3.5.0\tools\NuGet.exe" />

Note that the package folder name is lowercase - which is another implementation detail of nuget you'd have to know about.

dsplaisted commented 7 years ago

For packages that are intended to be used like this, I would suggest that they include a .props file that sets a property with the appropriate path. The package can use $(MSBuildThisFileDirectory) to set the property to the correct full path.

Of course, this only helps if you can make the change to the package you are trying to consume.

kukjevov commented 7 years ago

Thank you for all your answers. I discovered (using MSBuild Structured Log tool) that $(NuGetPackageFolders) you mentioned, and i had exactly same thought to use it.

But i can see there also $(NuGetPackageRoot) which points to same path. What is difference between these 2? I expect that these two properties are set only in MSBuild 15.0 and higher, is that correct?

Another question is about that $(MSBuildThisFileDirectory), because in MSBuild Structured Log tool i can`t see that property set. Does it still exists and can be used in MSBuild 15.0?

Thank you

rainersigwald commented 7 years ago

$(MSBuildThisFileDirectory) is a reserved property, so it may not get logged but is available for use.

I don't know the distinction between $(NuGetPackageFolders) and $(NuGetPackageRoot). I think the best place to ask for clarification there is in a new issue at https://github.com/nuget/home.

Closing this since it's clarification around NuGet behaviors, not core MSBuild. If you still have questions, please open a NuGet issue.

JVimes commented 2 years ago

Regarding NuGetPackageFolders vs NuGetPackageRoot, they are different values for me.

NuGetPackageFolders:

C:\Users\FooUser\.nuget\packages\;C:\Program Files (x86)\Microsoft Visual Studio\Shared\NuGetPackages

NuGetPackageRoot:

C:\Users\FooUser\.nuget\packages\
rainersigwald commented 2 years ago

There is now a nice solution to this issue: NuGet's GeneratePathProperty functionality.