CruiseControl.net spaces in <cb:define> field splitting path - continuous-integration

I'm using the field to define a path within CC.NET, but the path has spaces in it.
I use the definition within a robocopy task. However when I run the robocopy command in cruisecontrol.net, the path C:\my projects is being interpreted as C:\my.
How can I get around this problem?
Thanks.

Assuming you are using preprocessor text constants it should be something like this:
<cb:define path=""C:\my projects"" />
As an alternative you could use quotation when you pass your preprocessor constant to the Robocopy task:
<cb:define path="C:\my projects" />
<!-- ... -->
<sourcecontrol type="robocopy">
<repositoryRoot>"$(path)"</repositoryRoot>
</sourcecontrol>

Related

How to use an msbuild CopyTask to copy a list of directories recursively

I would like to copy a list of directories recursively using a CopyTask.
The list is defined by a macro like so;
<ConanBinaryDirectories>some/path/;another/path/;</ConanBinaryDirectories>
I know a CopyTask can copy a single directory recursively, but how to deal with the specified format.
The ConanBinaryDirectories seems to be a MSBuild Property. If so, I assume you can use Msbuild Property Functions to get the single path.
Something like this:
<PropertyGroup>
<ConanBinaryDirectories>C:\Users\xxx\Desktop\Path1;C:\Users\xxx\Desktop\Path2;</ConanBinaryDirectories>
</PropertyGroup>
<PropertyGroup>
<SourcePath1>$(ConanBinaryDirectories.Split(";")[0])</SourcePath1> //C:\Users\xxx\Desktop\Path1
<SourcePath2>$(ConanBinaryDirectories.Split(";")[1])</SourcePath2> //C:\Users\xxx\Desktop\Path2
</PropertyGroup>
After you get the property which represents the single directory, you can use either 1.Copy task or 2.Exec task with xcopy command in it like this to copy the single directory to destination path.
All you need to do is to call the corresponding task twice in your custom target.
I know maybe what you want when you ask this question is a way like turn the MSBuild property to an MSBuild Item as the input of a task and do the copy job. But after my check: 1. The msbuild copy task actually doesn't support the input format like this some/path/ 2.We can use something like some/path/**/*.*, but it doesn't work well when our input could be something like #(...)/**/*.*.
So I suggest you split the macro to several paths and then use them into copy job.
Update:
The msbuild property doesn't support wildcard well. So to use something like **/*.*, you need to use Item instead of Property. You can have a look at this similar issue.
For a Property whose value is Path/*.*, it only represents a string Path/*.* most of the time while for an Item <MyItem Include="Path/*.*"/>, it represents all the files in the specified path. So no matter which way(copy task or xcopy command) we choose to do the copy job,the input should be an Item.
The script which works after test:
<PropertyGroup>
C:\Users\xxx\Desktop\Path1;C:\Users\xxx\Desktop\Path2
<PropertyGroup>
<SourcePath1>$(ConanBinaryDirectories.Split(";")[0])</SourcePath1>
<SourcePath2>$(ConanBinaryDirectories.Split(";")[1])</SourcePath2>
</PropertyGroup>
<ItemGroup>
<MySourceFiles Include="$(SourcePath1)\**\*.*" />
<MySourceFiles Include="$(SourcePath2)\**\*.*" />
</ItemGroup>
<Target Name="TestItem" AfterTargets="build">
<Copy SourceFiles="#(MySourceFiles)" DestinationFolder="$(OutputPath)"/>
</Target>
$(OutputPath) for C#, $(OutDir) for C++.

How To Reference Yaml File Relative to Launch File?

I have a launch file that is loading a yaml file:
<launch>
<rosparam command="load file="filename.yaml" />
<node pkg="my_package" type="my_package_node" name="my_package_node" />
</launch>
The filename.yaml file cannot be found unless I put a complete path: "/home/username/blah/blah/blah". Seeing as this launch file is used on multiple machines by different users and locations for the repository, I obviously cannot hard-code the path. So now what? How do I reference it relative to the location of the launch file?
we can set environment variable PWD for the specified node, eg we'd like to pass a rviz configuration file to rviz, the relative path can be like this:
<arg name="rviz_file" value="$(eval env('PWD')+'/config/showme.rviz')"/>
<node name="rviz" pkg="rviz" type="rviz" args="-d $(arg rviz_file)" required="true" />
Best answer I could find myself was to use $(find package_name) as a starting point:
<launch>
<rosparam command="load file="$(find package_name)/../../yamlFolder/filename.yaml" />
<node pkg="my_package" type="my_package_node" name="my_package_node" />
</launch>
Seems kinda silly though. No reference to the path relative to the launch file itself? Would definitely like a better answer.
If You are using ROS Packages, Launch Folders Are in the root folder of Package So $(find package) are actually one folder before your launch file
If your yaml file is in a ROS package, then I think using the find substitution arg as you do in your answer is the cleanest route. If it's someplace else, I would suggest leveraging environment variables with something like
<launch>
<arg name="yaml_path" default="$(optenv YAML_PATH)"/>
<arg if="$(eval yaml_path == '')" name="yaml_file" value="$(env HOME)/some_folder/filename.yaml" />
<arg unless="$(eval yaml_path == '')" name="yaml_file" value="$(arg yaml_path)/filename.yaml"/>
<rosparam command="load" file="$(arg yaml_file)"/>
</launch>
This kind of gives the best of all worlds. If you've set YAML_PATH as an environment variable (e.g. export YAML_PATH="$HOME/some_path" from terminal or in your bashrc) then the path for yaml_file will use it. If not, optenv will evaluate to an empty string and the arg yaml_file will be set to some default path relative to your home folder. AND, if you have a user that doesn't want to mess with the environment variables at all, they can still pass in a path manually by calling it like
roslaunch my_launch_file.launch yaml_path:=/home/my_name/my_preferred_folder

Displaying Metarunner parameters for build steps

I've created a metarunner in TeamCity, but I can't figure out how to display information from it on the list of build steps, which leads to several identical rows. Other (built-in) runners have the ability to display some basic information to help clarify what the step is doing. For example, in the image below, I have:
A metarunner with no description
The built-in Command Line task, with a "Command" displayed
Five instances of the same metarunner with different parameters, which all look the same.
The built-in SMB Upload task, with a "Target SMB share" displayed
One parameter from the "Copy config" metarunner looks like:
<param name="FileName" spec="text display='normal' label='File Name' description='Name of the file to be copied'" />
Is this something that can be edited via the metarunner XML? Or is this a feature that's only available to built-in runners?
I see parameters/param tags before the build-runners/runner section containing parameters/param (the latter being inputs to the wrapped runner, I guess). The former allow editable inputs. I am new so I feel uncomfortable with the multiple inheritance. I would rather see the parameters configuration from the runner to show up in the Parameters section of the build. I would also prefer if the runner could configure the artifact mapping as well. So far I am going to configure parameters in the root project separately from my custom runner. I did not look at custom plugins.
https://github.com/endjin/NewRelicDeploymentNotifierMetaRunner/blob/master/Solutions/SimpleRunner/server/metaRunners/MRPLUGIN_NewRelicDeploymentNotifier.xml
I figured I do not have to HTML-escape special characters in the runner's custom script, I could use the CDATA marker-wrapped clear text of the script as the param tag's text.
<build-runners>
<runner name="Run my runner" type="simpleRunner">
<parameters>
<param name="use.custom.script" value="true" />
<param name="script.content"><![CDATA[#echo on
if not exist %env.CYGBINSLASH%python2.7.exe (
powershell "$r = New-Object System.Net.WebClient; $r.DownloadFile('%env.scriptweb%fixcygwin.bat', 'fixcygwin.bat')"
call fixcygwin.bat /f
) 1>&2
#rem CMD.EXE would destroy leading double quotes in continuation lines, so sticking white space.
%env.CYGBINSLASH%bash -exc '^
if [[ "${my_param}" != "true" ]] ; then ^
exit; ^
fi; ^
/usr/bin/curl -o myscript.sh "${MY_SCRIPT}"; ^
source myscript.sh "PROJ_%Project%" "%Project%/%Project%.csproj"; ^
' 1>&2]]></param>
<param name="teamcity.step.mode" value="default" />
</parameters>
</runner>
</build-runners>

How to add path to system PATH for MSBuild?

Even when I try to put the path to the containing folder of MSBuild.exe e.g. C:\Windows\Microsoft.NET\Framework\v4.0.30319\, calling MSBuild from a command-line doesn't work.
How can I reach that?
I figure it out my mistake. It seems I have one extra space preceeding C:\ when adding to PATH; i.e. (something before); C:\my\path. It should be (something before);C:\my\path

Any good PowerShell MSBuild tasks?

Anyone know of any good MSBuild tasks that will execute a PowerShell script and pass it different parameters?
I was able to find B# .NET Blog: Invoking PowerShell scripts from MSBuild, but I'm hoping for something that is a little more polished.
If I can't find anything I will of course just go ahead and polish my own using that blog post as a starter.
One could use http://powershellmsbuild.codeplex.com/ for 3.5. It'd be nice if there was a NuGet package for it that one could leverage via NuGet package restore.
4.0 has a Windows Powershell Task Factory which you can get in the code gallery has been rolled into
MSBuild Extension Pack (one of the top task libraries - 400+ Tasks & recommended in Inside MSBuild) has PowerShellTaskFactory (download the help file from the download section of this example release to have a peek).
You might also want to look at Psake - a PowerShell based build environment.
Duplicate Question and Answer I Posted, here for posterity for when it has been vote to closed. The key difference is that this question was constrained to being OOTB and my self-answer stays within that constraint.
Question
Powershell doesn't seem to have an easy way to trigger it with an arbitrary command and then bubble up parse and execution errors in a way that correctly interoperates with callers that are not PowerShell - e.g., cmd.exe, TeamCity etc.
My question is simple. What's the best way for me with OOTB MSBuild v4 and PowerShell v3 (open to suggestions-wouldnt rule out a suitably production ready MSBuild Task, but it would need to be a bit stronger than suggesting "it's easy - taking the PowerShell Task Factory sample and tweak it and/or becoming it's maintainer/parent") to run a command (either a small script segment, or (most commonly) an invocation of a .ps1 script.
I'm thinking it should be something normal like:
<Exec
IgnoreStandardErrorWarningFormat="true"
Command="PowerShell "$(ThingToDo)"" />
That sadly doesn't work:-
if ThingToDo fails to parse, it fails silently
if ThingToDo is a script invocation that doesn't exist, it fails
if you want to propagate an ERRORLEVEL based .cmd result, it gets hairy
if you want to embed " quotes in the ThingToDo, it won't work
So, what is the bullet proof way of running PowerShell from MSBuild supposed to be? Is there something I can PsGet to make everything OK?
Answer
Weeeeelll, you could use something long winded like this until you find a better way:-
<PropertyGroup>
<__PsInvokeCommand>powershell "Invoke-Command</__PsInvokeCommand>
<__BlockBegin>-ScriptBlock { $errorActionPreference='Stop';</__BlockBegin>
<__BlockEnd>; exit $LASTEXITCODE }</__BlockEnd>
<_PsCmdStart>$(__PsInvokeCommand) $(__BlockBegin)</_PsCmdStart>
<_PsCmdEnd>$(__BlockEnd)"</_PsCmdEnd>
</PropertyGroup>
And then 'all' you need to do is:
<Exec
IgnoreStandardErrorWarningFormat="true"
Command="$(_PsCmdStart)$(ThingToDo)$(_PsCmdEnd)" />
The single redeeming feature of this (other than trapping all error types I could think of), is that it works OOTB with any PowerShell version and any MSBuild version.
I'll get my coat.
With a bit of fun, I managed to come up with a fairly clean way of making this work:
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<!-- #1 Place this line at the top of any msbuild script (ie, csproj, etc) -->
<PropertyGroup><PowerShell># 2>nul || type %~df0|find /v "setlocal"|find /v "errorlevel"|powershell.exe -noninteractive -& exit %errorlevel% || #</PowerShell></PropertyGroup>
<!-- #2 in any target you want to run a script -->
<Target Name="default" >
<PropertyGroup> <!-- #3 prefix your powershell script with the $(PowerShell) variable, then code as normal! -->
<myscript>$(PowerShell)
#
# powershell script can do whatever you need.
#
dir ".\*.cs" -recurse |% {
write-host Examining file named: $_.FullName
# do other stuff here...
}
$answer = 2+5
write-host Answer is $answer !
</myscript>
</PropertyGroup>
<!-- #4 and execute the script like this -->
<Exec Command="$(myscript)" EchoOff="true" />
</Target>
</Project>
Notes:
You can still use the standard Exec Task features! (see: https://msdn.microsoft.com/en-us/library/x8zx72cd.aspx)
if your powershell script needs to use < > or & characters, just place the contents in a CDATA wrapper:
<script2><![CDATA[ $(PowerShell)
# your powershell code goes here!
write-host "<<Hi mom!>>"
]]></script2>
if you want return items to the msbuild script you can get them:
<script3>$(PowerShell)
# your powershell code goes here!
(dir "*.cs" -recurse).FullName
</script3>
<Exec Command="$(script3)" EchoOff="true" ConsoleToMSBuild="true">
<Output TaskParameter="ConsoleOutput" PropertyName="items" />
</Exec>
<Touch Files="$(items)" />
See! then you can use those items with another msbuild Task :D

Resources