Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using Item functions on metadata values

Tags:

msbuild

Background: I manage a fairly large solution. Every so often, people add a DLL reference to a project in the solution where they should've added a project reference. I want to issue a warning in such case. I want to do it by finding all reference with 'bin\debug' in their HintPath*. I know that references are Items in ItemGroup, with metadata "HintPath".

I expected something like this to work:

<Warning Text="Reference %(Reference.Identity) should be a project reference. HintPath: %(Reference.HintPath)"
         Condition="%(Reference.HintPath).IndexOf('bin\debug') != -1"/>

However, Seems like I can't use string function IndexOf like that. I tried many permutations of the above, without success.

  • Edit: I know this check is not full-proof, but I just want to reduce honest mistakes.
like image 366
Jonathan Avatar asked Mar 01 '12 08:03

Jonathan


People also ask

What is item metadata?

An item metadata dataset contains categorical data that provides valuable context for the items in a target time-series dataset. Unlike related time-series datasets, item metadata datasets provide information that is static.

What is %( RecursiveDir?

%(Directory) Contains the directory of the item, without the root directory. For example: MyProject\Source\ %(RecursiveDir)


2 Answers

Using MSBuild 4.0 Property Functions it is possible to do string comparisons:

<Target Name="AfterBuild">

  <Message Text="Checking reference... '%(Reference.HintPath)'" Importance="high" />

  <Warning Text="Reference %(Reference.Identity) should be a project reference. HintPath: %(Reference.HintPath)"
            Condition="$([System.String]::new('%(Reference.HintPath)').Contains('\bin\$(Configuration)'))" />

</Target>
like image 95
KMoraz Avatar answered Oct 21 '22 00:10

KMoraz


First not that your syntax is not correct for invoking functions, it would need to be:

   %(Reference.HintPath.IndexOf(...))       # Note: not supported by MSBuild

However, property functions in MSBuild are not allowed on item metadata, so that is not going to help you either.

What you could work around this, by invoking a separate target which is basically called for every item.

  <Target Name="CheckProjectReferences">
    <MSBuild 
      Projects="$(MSBuildProjectFullPath)"
      Properties="Identity=%(Reference.Identity);HintPath=%(Reference.HintPath)"
      Targets="_Warn"/>
  </Target>

  <Target Name="_Warn">
    <Warning Text="Reference $(Identity) should be a project reference. HintPath: $(HintPath)"
             Condition="$(HintPath.IndexOf('bin\debug')) != -1"/>
  </Target>

Frankly, I'm not sure if that is enough to catch all "violations". For example, the above will only work for bin\debug, but not for bin\Debug or other mixed-cased variations, which are functionally equivalent. To look for them as well, you'd need to call the IndexOf(string, StringComparison) overload, however just doing:

   $(HintPath.IndexOf('bin\debug', System.StringComparison.OrdinalIgnoreCase))

Will not work, because the MSBuild overload resolution will pick IndexOf(char, Int32) and give you this error:

MSB4184: The expression ""bin\debug".IndexOf(bin\debug, System.StringComparison.OrdinalIgnoreCase)" cannot be evaluated. String must be exactly one character long.

So, you'll need to convince it by using the IndexOf(String, Int32, Int32, StringComparison) overload directly:

   $(HintPath.IndexOf('bin\debug', 0, 9, System.StringComparison.OrdinalIgnoreCase))

You may need to also check for bin\Release or other variations. I'm not sure if that is the best way to figure out a reference should be a project reference, but if you know (and to a certain extend control) your environment it might be feasible.

like image 36
Christian.K Avatar answered Oct 21 '22 02:10

Christian.K