How do I test for empty properties set on the command line?

Given the following project I would always expect to get an output of Test = Test. However, if you run it with /p:Test = you will find that you get an output of Test =. Somehow '$(Test)' == '' is neither true nor false.

How do I trap this condition or is it a bug in MSBuild

<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" DefaultTarget="Build">
<PropertyGroup>
<Test Condition = " ('$(Test)' == '') or (! '$(Test)' == '') ">Test</Test>
</PropertyGroup>
<Target Name = "Build">
<Message Text = "Test = $(Test)"/>
</Target>
</Project>




Answer this question

How do I test for empty properties set on the command line?

  • addexm

    Your ps gave me an idea. The bug only appears to apply to setting that property. Given a script of

    <Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" DefaultTarget="Build">
    <PropertyGroup>
    <Test Condition = "'$(Test)' == '' or '$(Test)' != '' ">release</Test>
    <Test2 Condition = "'$(Test)' == '' or '$(Test)' != '' ">release</Test2>
    </PropertyGroup>

    <Target Name = "Build">
    <Message Text = "Test = $(Test)"/>
    <Message Text = "Test2 = $(Test2)"/>
    </Target>
    </Project>

    The command line of "msbuild y.csproj /p:Test=" displays:

    Test =

    Test2 = release

    So all I need to do is use Test2 everywhere instead of Test and at the top of my project do

    <Test2 Condition = "'$(Test)' == ''">release</Test2>
    <Test2 Condition = "'$(Test)' != ''">$(Test)</Test2>

    p.s. I would not call this a missing feature. It is a bug that the condition evaluates to true in one case and false in a different one



  • elmoubi

    Here is a solution for you. It uses the CreateProperty task with a condition on it to override this behavior. See comments below for explanation.

    <Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" InitialTargets="FixCommandParam" DefaultTargets="Build">

    <Target Name="FixCommandParam">
    <!--
    For every property that you have to validate do it like the following.
    By using the condition it will not override properties which have a value set
    from the command line.
    Since FixCommandParam is in the InitialTargets list you know this will execute
    before any other targets.
    -->
    <CreateProperty Condition="'$(Test)'==''" Value="Test NOT SET">
    <Output PropertyName="Test" Condition="'$(Test)'==''" TaskParameter="Value"/>
    </CreateProperty>
    </Target>

    <Target Name = "Build">
    <Message Text = "Test = $(Test)" Importance="high"/>
    </Target>
    </Project>

    Hope this helps.

    Sayed Ibrahim Hashimi
    www.sedodream.com


  • Stampede2

    Scott,

    I think I understand what you want to do now. How about this:

    <Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" DefaultTarget="Build">

    <PropertyGroup>
    <Foo Condition="'$(Foo)'==''">defaultvalue</Foo>
    </PropertyGroup>

    <Target Name="t">

    <Message Text="foo: $(Foo)"/>

    </Target>
    </Project>

    Now if I do

    msbuild y.csproj /p:foo=somevalue

    I get

    foo: somevalue

    and if I do

    msbuild y.csproj

    I get

    foo: defaultvalue.

    In summary, there's nothing you can do (before targets start to execute anyway) to avoid command line properties "winning". But in your case, you want them to win - if they are set to something - so that's okay.

    Am I understanding correctly Let me know if I'm not.

    Dan

    PS If empty string is actually a valid value and the default is something else, you have a problem, because you don't know if the property was set (to empty) or not set. In that case you have to invent a 2nd property to work around this: perhaps in a future version of MSBuild we will have a way to detect the difference between a property that was not set, and one that was set to blank.

    "This posting provided AS IS with no warranties"



  • HotQQ

    I cannot call the property something else. The whole point of this was to detect if the user had set the property on the command line, if they haven't then I was setting a default value. The only trouble is that you cannot detect if they have set an empty value because doing

    Condition = " '$(Test) == '' or '$(Test) != '' " will return false if the property is set to blank on the command line.



  • Iyyengar

    Last night I finally understood what you where saying. The problem is with my understanding of the order of operations. I was forgetting that command line arguments take precedence over property settings. So what is actually happening in my example is first the PropertyGroup is evaluated

    <PropertyGroup>
    <Test Condition = "'$(Test)' == '' or '$(Test)' != '' ">release</Test>
    <Test2 Condition = "'$(Test)' == '' or '$(Test)' != '' ">release</Test2>
    </PropertyGroup>

    So at this stage Test = release and Test2 = release

    Then the command line parameter of /p:Test= is applied so now Test = and Test2 = release.

    Then tasks are executed. So that is why when I use CreateProperty and test for '${Test}'=='' I get success.

    So in conclussion, if you want to make sure a parameter has been entered on the command line you must use CreateProperty



  • javad hosseiny

    Hi Scott,

    This is because properties supplied at the command line always override properties set in the project. If you called your property inside the project something different, you'd be able to set it okay.

    (BTW, perhaps you meant to write

    '$(Test)' != ''

    instead of

    !'$(Test)' == ''

    In the latter case, you are negating the property before testing equality. So if $(Test) was "true" it would compare false with empty string.)

    Dan



  • Wayne Clements

    I see, sorry I couldn't help you with that.

    Sayed Ibrahim Hashimi
    www.sedodream.com

  • sud

    Hi Sayed,

    Thanks for the workaround. I should have posted in my original message that I had already come up with that work around.

    I was using it until I needed to set an Item based on the property. It seemed increadibly cumbersome to have to the use CreateItem to create the item rather than normal Item syntax. That was when I decided to see if anyone knew how to detect a blank command line property in properties.



  • How do I test for empty properties set on the command line?