loresoft / msbuildtasks

The MSBuild Community Tasks Project is an open source project for MSBuild tasks.
BSD 2-Clause "Simplified" License
946 stars 272 forks source link

Unable to get correct MSBuildCommunityTasksPath when using MSBUILDTASKS from NuGet in a before.Solution.sln.targets script run on TFS build server #268

Closed lanthonyneville closed 5 years ago

lanthonyneville commented 6 years ago

I have been using MSBUILDTASKS (installed from NuGet) successfully in project-level targets files, run on TFS build server, for a long time. Now I am trying to use it in solution-level Before and After targets file (see here).

However, used this way, it seems unable to form the correct path to the MSBuild.Community.Tasks.dll as specified in the MSBuildCommunityTasksPath property in my targets file.

If I set it like this:

<MSBuildCommunityTasksPath>$(SolutionDir)\.build</MSBuildCommunityTasksPath>

then I get this error:

D:\Builds\Agents\17\DevelopmentSTP1\My.Product\src\before.My.Product.sln.targets (9): The imported project "D:\.build\MSBuild.Community.Tasks.Targets" was not found. Confirm that the path in the declaration is correct, and that the file exists on disk.

The actual path on the build server to the DLL is: D:\Builds\Agents\17\DevelopmentSTP1\My.Product\src\.build , so it looked like $(SolutionDir) was returning a blank, however that made no sense as $(SolutionDir) is used elsewhere in the script successfully.

If I set it like this:

<MSBuildCommunityTasksPath>$(SolutionDir).build</MSBuildCommunityTasksPath> (i.e. without the backslash)

then I get this error:

D:\Builds\Agents\17\DevelopmentSTP1\My.Product\src\before.My.Product.sln.targets (18): The "MSBuild.Community.Tasks.Attrib" task could not be loaded from the assembly D:\Builds\Agents\17\DevelopmentSTP1\My.Product\src\.build\.build\MSBuild.Community.Tasks.dll. Could not load file or assembly 'file:///D:\Builds\Agents\17\DevelopmentSTP1\My.Product\src\.build\.build\MSBuild.Community.Tasks.dll' or one of its dependencies. The system cannot find the file specified. Confirm that the declaration is correct, that the assembly and all its dependencies are available, and that the task contains a public class that implements Microsoft.Build.Framework.ITask.

The path is almost right now, but note the doubling of the folder name: \.build\.build

I have tried a lot of tricks to try to get it to work, like adding ..\ to try to get it to step back a folder level, but nothing works so long as I retain the $(SolutionDir) variable. The only thing that works is to hard code the physical path in, i.e.

<MSBuildCommunityTasksPath>D:\Builds\Agents\17\DevelopmentSTP1\My.Product\src\.build</MSBuildCommunityTasksPath>
VonOgre commented 6 years ago

Caveat: I know it's 4 months later, but throwing an assist out anyways :) In part, it might be an ordering thing, since the metaproj emitted by msbuild for a solution imports the before.*.sln.targets prior to defining the $(SolutionDir) property. Also, apologies on formatting; I'm not a regular on GitHub ;)

  <Import Project="D:\Projects\PublicProjects\SSRSDesktop\before.SSRSDesktop.sln.targets" Condition="exists('D:\Projects\PublicProjects\SSRSDesktop\before.SSRSDesktop.sln.targets')" />
  <PropertyGroup Condition=" '$(Configuration)' == '' ">
    <Configuration>Debug</Configuration>
  </PropertyGroup>
  <PropertyGroup Condition=" '$(Platform)' == '' ">
    <Platform>Any CPU</Platform>
  </PropertyGroup>
  <PropertyGroup Condition=" ('$(AspNetConfiguration)' == '') ">
    <AspNetConfiguration>$(Configuration)</AspNetConfiguration>
  </PropertyGroup>
  <PropertyGroup>
    <SolutionDir>D:\Projects\PublicProjects\SSRSDesktop\</SolutionDir>
    <SolutionExt>.sln</SolutionExt>
    <SolutionFileName>SSRSDesktop.sln</SolutionFileName>
    <SolutionName>SSRSDesktop</SolutionName>
    <SolutionPath>D:\Projects\PublicProjects\SSRSDesktop\SSRSDesktop.sln</SolutionPath>
  </PropertyGroup>

The before-solution targets will not yet have $(SolutionDir) available when doing their own imports, resulting in blanks but the after-solution targets would. It isn't 100% clear where/when you're setting MSBuildCommunityTasks path in the respective targets, so I can't be certain why you're getting doubling of paths and such, but it's also a good practice to end any directory property with a trailing backslash.

You might consider utilizing $(MSBuildThisFileDirectory) or $(MSBuildProjectDirectory) instead of $(SolutionDir), since those are low-level MSBuild properties. Either one would work in this case since before/after.*.sln.targets files need to be siblings to the solution file.

lanthonyneville commented 5 years ago

Hi VonOgre .... its a year later, and sorry I never noticed your post! Just wanted to say that it works (using $(MSBuildThisFileDirectory) instead of $(SolutionDir)). Thanks very much. I had given up on this issue and had hard-coded a physical path for MSBuildCommunityTasksPath (i.e. D:\Builds\Agents\17 ....) but moving to a new build server today prompted me to have another look.

VonOgre commented 5 years ago

Haha I'd long since forgotten I'd even supplied any assistance and was really confused to get an email this morning! I'm glad it helped :)