MSBuild GetPathOfFileAbove() returning empty - msbuild

I am trying to refactor the code below to use GetPathOfFileAbove() instead.
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory),global.json))\eng\Configurations.props" />
when i tried the below code, an error was thrown, file not found
<Import Project="$([MSBuild]::GetPathOfFileAbove('global.json','$(MSBuildThisFileDirectory)'))\eng\Configurations.props" />
The path of the above code result in,where "global.json" shouldn't have been here:
"C:\dotnetruntime\runtime\global.json\eng\Configurations.props"
Expected path:
"C:\dotnetruntime\runtime\eng\Configurations.props"
I having a hard time finding documentation to figured out the configuration am missing here. Can you guys give me some pointers

The correct path to use was
"<Import Project="$([MSBuild]::GetPathOfFileAbove(Configurations.props,$(MSBuildThisFileDirectory)))../../../../../eng/Configurations.props" />"
The use of "../" allows the file be searched one directory above.

Related

MSBuild Select partial RecursiveDir

I have a project that looks something like this:
src\ModuleA\code\somepath\test.js
src\ModuleA\code\ignorethis.txt
src\ModuleB\code\awesome.js
src\ModuleB\code\testing\file.js
And I would like to grab all these js files from the modules using an ItemGroup like this:
<ItemGroup>
<_Scripts Include="..\..\..\src\**\code\**\*.js"/>
</ItemGroup>
But when I copy them into the output I would like to strip the Module and code paths. If I use a Copy like this
<Copy SourceFiles="#(_Scripts)" DestinationFiles="#(Scripts->'..\tmp\Test\%(RecursiveDir)%(Filename)%(Extension)')"/>
The result looks like this (because the RecursiveDir contains the whole path starting at the first **)
tmp\Test\ModuleA\code\somepath\test.js
tmp\Test\ModuleB\code\awesome.js
tmp\Test\ModuleB\code\testing\file.js
However I'm trying to get a result like this:
tmp\Test\somepath\test.js
tmp\Test\awesome.js
tmp\Test\testing\file.js
I have tried by adding Metadata with functions but I can't seem to find the proper escaping needed to make this work. My last attempt was like this (if I can strip at least 1 level of folder, I assumed stripping the second level would be a simple repetition in yet another Meta element...)
<Scripts Include="#(_Scripts)">
<NewDir>$("%(_Scripts.RecursiveDir)".Substring(0, "%(_Scripts.RecursiveDir)".IndexOf("\")))</NewDir>
</Scripts>
Which yields a Error MSB4184: The expression <cut for brevity> cannot be evaluated.
If there is a simpler method or anyone can tell me what the right escape sequence is to get this working?
After struggling around with escaping and getting the values parsed and processed I managed to resolve it using the following:
<_ScriptsFiles Include="..\..\..\src\*\code\**\*.js"/>
<_Scripts Include="#(_ScriptsFiles)">
<FirstSlash>$([System.String]::new('%(_ScriptsFiles.RecursiveDir)').IndexOf('\'))</FirstSlash>
<DirMinusOne>$([System.String]::new('%(_ScriptsFiles.RecursiveDir)').Substring(%(_Scripts.FirstSlash)))</DirMinusOne>
<SecondSlash>$([System.String]::new('%(_Scripts.DirMinusOne)').IndexOf('\', 1))</SecondSlash>
<DirMinusTwo>$([System.String]::new('%(_Scripts.DirMinusOne)').Substring(%(_Scripts.SecondSlash)))</DirMinusTwo>
</_Scripts>
<Copy SourceFiles="#(_Scripts)" DestinationFiles="#(_Scripts->'..\..\..\tmp\%(DirMinusTwo)\%(Filename)%(Extension)')"/>

Format to use Exists Condition in MSBuild props file

I need to check whether the given folder is available in the given path or not. If that folder is not available in the given path,then it has to take alternative folder mentioned.
So to check the existence of the given folder, i tried
I got error as error MSB4092: An unexpected token "$(D:\DK)" was found at character position 11 in condition "'(Exists('$(D:\DK)')' "
What is the correct format to use this Exists condition?
This is quite basic though it can be confusing apparently..
$(<name>) is used to refer to the property named <name> but you don't seem to have a property, just a string.
So either
<Message Condition="Exists('d:\dk')" Text="It Exists" />
or
<PropertyGroup>
<Dk>d:\dk</Dk>
</PropertyGroup>
<Message Condition="Exists($(Dk))" Text="It Exists" />
I tried the Exists condition with the following scenario and it works fine for me.
<ROOT Condition="Exists('D:\DK')">D:\DK</ROOT>
<ROOT Condition="'$(ROOT)'==''">D:\New\DK</ROOT>

In MSBuild, why isn't Item Metadata, within a property, being resolved?

Below is a portion of a MSBuild file that I'm working on:
<ItemGroup>
<Tests Include="$(SolutionDir)\**\bin\$(TestPlatform)\$(Configuration)\*.Tests.dll" />
</ItemGroup>
<PropertyGroup>
<TestProperties>/testcontainer:%(Tests.FullPath)</TestProperties>
</PropertyGroup>
I want to have a property that holds a command line switch. However, when I try to use $(TestProperties) in an Exec Command string, %(Tests.FullPath) is never resolved to the absolute path of the Tests item. Instead, it's always processed literally, as "%(Tests.FullPath)".
Am I doing something wrong or is this a standard MSBuild behavior? If the latter, is there a way for me to workaround this?
Thanks
P.S. - I realize I probably don't need to access the FullPath property since my Include value is an absolute path. However, I'd still like to understand the issue, along with how to handle it.
You have a syntax error. Item lists are referenced via the # character and item meta data is referenced via %. Reference the MSBuild Special Character Reference for details. To access the well known item metadata, you need to apply a transform inside the Property itself.
<ItemGroup>
<Tests Include="MyFile.txt" />
</ItemGroup>
<PropertyGroup>
<TestProperties>/testcontainer:#(Tests->'%(FullPath)')</TestProperties>
</PropertyGroup>
You can find more help here

MSBuild exclude syntax not working

I have a test file in MSBuild to create a ZIP. I need exclude certain folders. I have the following working.
<PropertyGroup>
<TestZipPath>C:\path\to\my\folder\</TestZipPath>
<ExcludeList>$(TestZipPath)\**\_svn\**;$(TestZipPath)\**\.svn\**;$(TestZipPath)\**\obj\**;$(TestZipPath)\**\*.config</ExcludeList>
</PropertyGroup>
<ItemGroup>
<ZipFiles Include="$(TestZipPath)\**\*.*" Exclude="$(ExcludeList)" />
</ItemGroup>
<Message Text="%(ZipFiles.FullPath)"/>
That seems hideously verbose to me. Ideally I would want the ExcludeList to be formatted like this:
<ExcludeList>**\_svn\**;**\.svn\**;**\obj\**;**\*.config</ExcludeList>
But it doesn't seem to work. Why do I need to include $(TestZipPath) before every exclude pattern? Is ** not intended to be used at the beginning of a path? Is there a better way to do this?
I figured out the problem. The issue is that I am trying to include files that are not relative to the msbuild file that I'm executing. MSBuild assumes that file paths are relative to this location and gives you no way to change that. Because of this, all of my paths have to be absolute and can't be relative.
Try to add '.\' before every include pattern. Like this:
'.\**\obj\**'

Error using MSBuild tokens in PropertyGroup

I am trying to setup some properties that I use multiple times in my MSBuild script. I have the following property section:
<PropertyGroup>
<BuildDependsOn>$(BuildDependsOn); MyAfterBuild </BuildDependsOn>
<SubstitutionsFilePath>$(ProjectDir)app.config.substitutions.xml </SubstitutionsFilePath>
<AppConfig>$(TargetPath).config</AppConfig>
<HostConfig>$(TargetDir)$(TargetName).vshost.exe.config</HostConfig>
</PropertyGroup>
When I run this I get the following error:
The expression "#(TargetPath).config" cannot be used in this context. Item lists cannot be concatenated with other strings where an item list is expected. Use a semicolon to separate multiple item lists.
I don't understand this error, as the use of the $(BuildDependsOn) and $(ProjectDir) work fine. And I know the $(TargetXXX) values generate properly as when I put them directly into the Tasks section below, they work fine.
The reason for this problem is that TargetDir is defined as an item list, not a property; presumably to cater to the scenario where your outputs are distributed amongst several output directories?
I came up against this same problem and managed to work around it by using the $(OutDir) property instead of $(TargetDir).
(The OutDir property is defined in Microsoft.Common.Targets (lines 100-102) as a normalised version of the OutputPath defined in your project file.)
First try running your build with the /v:diag option, which will output a lot more information and give you a clue as to what part of the build is failing.
A clue might be in the Microsoft.Common.targets file (located in %SystemRoot%\Microsoft.NET\Framework\v2.0.50727) in the PrepareForBuild target:
<!--
These CreateProperty calls are required because TargetDir and TargetPath are defined
to contain an item list. We want that item list to be expanded so that it can be used
as a regular property value and not as an item-list-with-transform.
-->
<CreateProperty Value="$(TargetDir)">
<Output TaskParameter="Value" PropertyName="TargetDir" />
</CreateProperty>
<CreateProperty Value="$(TargetPath)">
<Output TaskParameter="Value" PropertyName="TargetPath" />
</CreateProperty>
To me this looks like a bug, you can report it at https://connect.microsoft.com/feedback/Search.aspx?SiteID=210.