Ant script -- split string and access via indexing - arrays

I need to write an Ant script which would load a properties file, read a single property out of it. The value (multiline) is something like:
path/to/file1a;path/to/file1b,
path/to/file2a;path/to/file2b,
..
..
I need to iterate over every line, and execute a shell command which looks like:
myCommand -param1 path/to/file1a -param2 path/to/file1b #Command inside a single iteration
I have able to figure out how to loop:
<for list="${ValueFromPropertyFile}" param="a">
<sequential>
<exec executable="myCommand">
<arg value="-param1" />
<arg value="---- split(#{a}, ";")[0] ----" />
<arg value="-param2" />
<arg value="---- split(#{a}, ";")[1] ----" />
</exec>
</sequential>
</for>
This is quite a simple task in my opinion. I tried searching, but without any success.
I would appreciate if someone could help me out with this, or point me to a relevant document.
Many thanks,
Pratik

Couple of problems with your assumptions:
The format of your input file is not a standard Java properties file, so it can't be loaded using the standard loadproperties task in ANT.
ANT is not a programming language. The "for" task you've quoted is not part of core ANT (Requires the 3rd party ant-contrib.jar)
So I'd suggest using an embedded script to solve your problem.
Example
The project is self documenting:
$ ant -p
Buildfile: /home/mark/tmp/build.xml
This is a demo project answering the following stackoverflow question:
http://stackoverflow.com/questions/14625896
First install 3rd party dependencies and generate the test files
ant bootstrap generate-test-files
Then run the build
ant
Expect the following output
parse-data-file:
[exec] build/myCommand -param1 path/to/file1a -param2 path/to/file1b
[exec] build/myCommand -param1 path/to/file2a -param2 path/to/file2b
build.xml
<project name="demo" default="parse-data-file">
<description>
This is a demo project answering the following stackoverflow question:
http://stackoverflow.com/questions/14625896
First install 3rd party dependencies and generate the test files
ant bootstrap generate-test-files
Then run the build
ant
Expect the following output
parse-data-file:
[exec] build/myCommand -param1 path/to/file1a -param2 path/to/file1b
[exec] build/myCommand -param1 path/to/file2a -param2 path/to/file2b
</description>
<target name="bootstrap" description="Install 3rd party dependencies">
<mkdir dir="${user.home}/.ant/lib"/>
<get dest="${user.home}/.ant/lib/groovy-all.jar" src="http://search.maven.org/remotecontent?filepath=org/codehaus/groovy/groovy-all/2.1.0/groovy-all-2.1.0.jar"/>
</target>
<target name="generate-test-files" description="Generate the input data and sample script">
<echo file="build/input.txt">path/to/file1a;path/to/file1b,
path/to/file2a;path/to/file2b,</echo>
<echo file="build/myCommand"> #!/bin/bash
echo $0 $*</echo>
<chmod file="build/myCommand" perm="755"/>
</target>
<target name="parse-data-file" description="Parse data file">
<taskdef name="groovy" classname="org.codehaus.groovy.ant.Groovy"/>
<groovy>
new File("build/input.txt").eachLine { line ->
def fields = line.split(/[;,]/)
ant.exec(executable:"build/myCommand") {
arg(value:"-param1")
arg(value:fields[0])
arg(value:"-param2")
arg(value:fields[1])
}
}
</groovy>
</target>
<target name="clean" description="Cleanup build files">
<delete dir="build"/>
</target>
</project>

Related

Making Intellisense see resources generated by custom MSBuild target (WPF)

In my net4.8 WPF project I have an Art folder which contains .svg files.
I have created an MSBuild target which:
Invokes inkscape to convert .svg files to .xaml, placing the generated files in the project's intermediate output directory.
Includes the generated .xaml files into the target binary as resources.
Then, in the XAML of my application, I have <Frame> elements that reference the .xaml resources to display the images.
So far, so good; all this works.
The problem is that when I do this, intellisense knows nothing of my generated resource files. I would like intellisense to know those files, and give me suggestions, because the application is bound to have lots of them, so using blind binding-by-name is soon going to be problematic.
Steps to reproduce the problem:
STEP 1: make sure you have a relatively recent version of inkscape installed and accessible via your path.
STEP 2: Create a new C# Windows Desktop "WPF App (.NET Framework)" application project (+solution) targeting .Net Framework 4.8.
STEP 3: Add a XamlFromSvg.targets file with the following content:
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<!-- Ensure Visual Studio puts the XamlFromSvg item in the Build Action dropdown -->
<ItemGroup>
<AvailableItemName Include="XamlFromSvg"/>
</ItemGroup>
<!-- Instruct MsBuild to include our "Compile" and "Resource" targets in the Build -->
<PropertyGroup>
<BuildDependsOn>
XamlFromSvgCompile;
XamlFromSvgResource;
$(BuildDependsOn);
</BuildDependsOn>
</PropertyGroup>
<!-- Convert ("compile") .svg to .svg.xaml -->
<Target Name="XamlFromSvgCompile" Condition="#(XamlFromSvg)!=''" BeforeTargets="BeforeBuild;BeforeRebuild"
Inputs="#(XamlFromSvg)"
Outputs="$(IntermediateOutputPath)X\%(XamlFromSvg.Identity).xaml">
<Message Importance="High" Text="XamlFromSvgCompile: %(XamlFromSvg.Identity) -> $(IntermediateOutputPath)X\%(XamlFromSvg.Identity).xaml"/>
<MakeDir Directories="$(IntermediateOutputPath)X\%(XamlFromSvg.RelativeDir)" Condition="!Exists('$(IntermediateOutputPath)X\%(XamlFromSvg.RelativeDir)')"/>
<Exec Command="cmd /c inkscape "%(XamlFromSvg.Identity)" --export-filename="$(IntermediateOutputPath)X\%(XamlFromSvg.Identity).xaml""
Outputs="$(IntermediateOutputPath)X\%(XamlFromSvg.Identity).xaml">
</Exec>
</Target>
<!-- Add .svg.xaml as resource -->
<Target Name="XamlFromSvgResource" Condition="#(XamlFromSvg)!=''">
<ItemGroup>
<GeneratedXamlFromSvg Include="$(IntermediateOutputPath)X\%(XamlFromSvg.Identity).xaml"/>
</ItemGroup>
<Message Importance="High" Text="XamlFromSvgResource: $(IntermediateOutputPath)X\#(XamlFromSvg.Identity).xaml -> %(GeneratedXamlFromSvg.Identity)"/>
<CreateItem Include="%(GeneratedXamlFromSvg.Identity)">
<Output TaskParameter="Include" ItemName="Resource"/>
</CreateItem>
</Target>
<!--This is here just to prevent "unknown item group" warnings. -->
<ItemGroup>
<XamlFromSvg Include="foo" Condition="False"/>
</ItemGroup>
</Project>
STEP 4: Near the end of WpfApp1.csproj, after the <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> line, add the following line:
<Import Project="XamlFromSvg.targets" />
STEP 5: Add an /Art folder with an .svg file (Say, Misc.HamburgerMenu.svg.) You can use the following sample .svg file:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" id="svg8" width="500" height="500" viewBox="0 0 500 500">
<g id="g6" transform="matrix(27.777778,0,0,27.777778,-83.333334,-81.333336)">
<path d="M 3,6 H 21 V 8 H 3 V 6 m 0,5 h 18 v 2 H 3 v -2 m 0,5 h 18 v 2 H 3 Z" id="path4" />
</g>
</svg>
STEP 6: From within Solution Explorer, right-click on the .svg file and select "Include in project".
STEP 7: Right-click on the .svg file again, select "Properties", and set the Build Action to XamlFromSvg.
STEP 8: In App.xaml insert the following:
<Frame x:Shared="false" x:Key="Icon.Misc.HamburgerMenu" Source="/X/Art/Misc.HamburgerMenu.svg.xaml" />
STEP 9: In MainWindow.xaml, replace <Grid></Grid> with the following:
<ContentControl Content="{StaticResource Icon.Misc.HamburgerMenu}" Margin="50"/>
STEP 10: Build and run; You should see a window displaying your .svg file.
STEP 11: Now go back to App.xaml. If you place the cursor on /X/ and hit Ctrl+Space.
Intellisense will suggest anything but /X/Art/Misc.HamburgerMenu.svg.xaml. Intellisense knows nothing of this resource.
And ideas how to solve this problem or achieve the same result by other means would be welcome.
(However, any ideas aiming to achieve the same result by other means must actually achieve the same result, which is to begin with .svg files and to have these files displayed in a net4.8 WPF application without the need to perform any manual steps whatsoever.)
Note: I know netcore supports .svg files, but I am sticking with net4.8 for now, which does not. And I have heard of 'XAML Islands', it seems like a clunky additional moving part held together by shoestrings, so I do not want to try it.
Also, any suggestions on how to improve XamlFromSvg.targets would be welcome. (I just compiled it from samples, I hardly know what I am doing.)

Problems while using ANT for creating HTML (junit style) report

I am trying to generate an HTML/Junit Style report for the jMeter tests by using ANT. I have created a build file for this and have done all the pre-requisites like:
set the required variables like java home, ant home, path variables; put the ant build file and the required .jmx file (for jmeter execution) in a folder and calling "ant" command pointing at the same folder.
I tried calling the ant build file by giving commands as ant and ant -Dtest="Sample Workload Script".
The issue i get is that when i run this commands it reaches to the point of executing the test plan and then gives a java platform error (as shown in attached image) and stops the build. Any pointers to what might be causing this?
Java Platform Error when running the ANT Build file
I read somewhere that the ANT version may not be compatible with java 1.8. Speaking of which i am using Ant 1.9.7 and java 1.8.73
My build file:
<?xml version="1.0"?>
<!--
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<project name="ant-jmeter" default="all">
<description>
Sample build file for use with ant-jmeter.jar
See http://www.programmerplanet.org/pages/projects/jmeter-ant-task.php
To run a test and create the output report:
ant -Dtest=script
To run a test only:
ant -Dtest=script run
To run report on existing test output
ant -Dtest=script report
The "script" parameter is the name of the script without the .jmx suffix.
Additional options:
-Dshow-data=y - include response data in Failure Details
-Dtestpath=xyz - path to test file(s) (default user.dir).
N.B. Ant interprets relative paths against the build file
-Djmeter.home=.. - path to JMeter home directory (defaults to parent of this build file)
-Dreport.title="My Report" - title for html report (default is 'Load Test Results')
Deprecated:
-Dformat=2.0 - use version 2.0 JTL files rather than 2.1
</description>
<property name="testpath" value="${user.dir}"/> <!--<property name="testpath" value="${user.dir}"/>-->
<property name="jmeter.home" value="C:\apache-jmeter-3.0"/>
<property name="report.title" value="Load Test Results"/>
<!-- Name of test (without .jmx) -->
<property name="test" value="Test"/>
<!-- Should report include response data for failures? -->
<property name="show-data" value="n"/>
<property name="format" value="2.1"/>
<condition property="style_version" value="">
<equals arg1="${format}" arg2="2.0"/>
</condition>
<condition property="style_version" value="_21">
<equals arg1="${format}" arg2="2.1"/>
</condition>
<condition property="funcMode">
<equals arg1="${show-data}" arg2="y"/>
</condition>
<condition property="funcMode" value="false">
<not>
<equals arg1="${show-data}" arg2="y"/>
</not>
</condition>
<!-- Allow jar to be picked up locally -->
<path id="jmeter.classpath">
<fileset dir="${basedir}">
<include name="ant-jmeter*.jar"/>
</fileset>
</path>
<taskdef
name="jmeter"
classname="org.programmerplanet.ant.taskdefs.jmeter.JMeterTask"/>
<!--classpathref="jmeter.classpath"-->
<!--classpathref="C:\apache-jmeter-3.0\extras"-->
<target name="all" depends="run,report"/>
<target name="run">
<echo>funcMode = ${funcMode}</echo>
<delete file="${testpath}/${test}.html"/>
<jmeter
jmeterhome="${jmeter.home}"
testplan ="${basedir}/${test}.jmx"
resultlog="${basedir}/${test}.jtl">
<!--
<jvmarg value="-Xincgc"/>
<jvmarg value="-Xmx128m"/>
<jvmarg value="-Dproperty=value"/>
<jmeterarg value="-qextra.properties"/>
-->
<!-- Force suitable defaults -->
<property name="jmeter.save.saveservice.output_format" value="xml"/>
<property name="jmeter.save.saveservice.assertion_results" value="all"/>
<property name="jmeter.save.saveservice.bytes" value="true"/>
<property name="file_format.testlog" value="${format}"/>
<property name="jmeter.save.saveservice.response_data.on_error" value="${funcMode}"/>
</jmeter>
</target>
<property name="lib.dir" value="${jmeter.home}/lib"/>
<!-- Use xalan copy from JMeter lib directory to ensure consistent processing with Java 1.4+ -->
<path id="xslt.classpath">
<fileset dir="${lib.dir}" includes="xalan*.jar"/>
<fileset dir="${lib.dir}" includes="serializer*.jar"/>
</path>
<target name="report" depends="xslt-report,copy-images">
<echo>Report generated at ${report.datestamp}</echo>
</target>
<target name="xslt-report" depends="_message_xalan">
<tstamp><format property="report.datestamp" pattern="yyyy/MM/dd HH:mm"/></tstamp>
<xslt
classpathref="xslt.classpath"
force="true"
in="${basedir}/${test}.jtl"
out="${basedir}/${test}.html"
style="${basedir}/jmeter-results-detail-report${style_version}.xsl">
<param name="showData" expression="${show-data}"/>
<param name="titleReport" expression="${report.title}"/>
<param name="dateReport" expression="${report.datestamp}"/>
</xslt>
</target>
<!-- Copy report images if needed -->
<target name="copy-images" depends="verify-images" unless="samepath">
<copy file="${basedir}/expand.png" tofile="${testpath}/expand.png"/>
<copy file="${basedir}/collapse.png" tofile="${testpath}/collapse.png"/>
</target>
<target name="verify-images">
<condition property="samepath">
<equals arg1="${testpath}" arg2="${basedir}" />
</condition>
</target>
<!-- Check that the xalan libraries are present -->
<condition property="xalan.present">
<and>
<!-- No need to check all jars; just check a few -->
<available classpathref="xslt.classpath" classname="org.apache.xalan.processor.TransformerFactoryImpl"/>
<available classpathref="xslt.classpath" classname="org.apache.xml.serializer.ExtendedContentHandler"/>
</and>
</condition>
<target name="_message_xalan" unless="xalan.present">
<echo>Cannot find all xalan and/or serialiser jars</echo>
<echo>The XSLT formatting may not work correctly.</echo>
<echo>Check you have xalan and serializer jars in ${lib.dir}</echo>
</target>
</project>
Update "jmeter" section of your build.xml file as follows:
<jmeter
jmeterhome="${jmeter.home}"
testplan ="${basedir}/${test}.jmx"
resultlog="${basedir}/${test}.jtl"
jmeterlogfile="${basedir}/jmeter.log"> <!-- add this line to enabled logging-->
Re-run your test and look into jmeter.log file under your C:\workspace\CPT folder - it should contain enough troubleshooting information so you will be able to find out the cause. If you have problems interpreting the log file - add it to your question.
References:
JMeter Ant Task
Five Ways To Launch a JMeter Test without Using the JMeter GUI

Check whether a file exists in an Ant FileSet

I am using FileSet in an Ant build file that is being read as an input from external source. How can I check if a specific file exists in the FileSet?
For example, if the FileSet being read is **/src/*.java, I should be able to find MyClass.java in it. However, if the FileSet is **/src/AClass.java, **/src/BClass.java, then MyClass.java is not in it.
Even if there is a way I can expand the FileSet and do a string contains check, then that should work.
There are plenty of ways to create selectors within a FileSet, but there is nothing I could find that tells how to find/select a File in a given FileSet. So I can't back it up with an example that I could try. Any help will be very appreciated.
Using the restrict resource collection to include only the named file:
<project ... xmlns:rsel="antlib:org.apache.tools.ant.types.resources.selectors">
...
<restrict id="filtered.fileset">
<fileset refid="source.fileset"/>
<rsel:name name="MyClass.java"/>
</restrict>
<condition property="file.found" value="yes">
<resourcecount when="greater" count="0" refid="filtered.fileset" />
</condition>
I implemented that by doing an intersection of the complete Fileset with the Fileset containing just this one file that I am looking, and verifying that if the count equals 1. The other conditions can be easily AND-ed or OR-ed.
<target name="checkSomething">
<condition property="something.present">
<and>
<available file="/src/theFile"/>
<resourcecount when="equal" count="1">
<intersect>
<fileset dir="${src.dir}" includes="*"/>
<fileset dir="${src.dir}" includes="**/src/something.java"/>
</intersect>
</resourcecount>
</and>
</condition>
<echo message="Something present: ${something.present}"/>
</target>

Use Ant to find file with latest version number

I want to use ant to find the file with the latest version number. For example, I have a file directory named tomcat with the following files:
apache-tomcat-6.0.37.zip
apache-tomcat-6.0.38.zip
apache-tomcat-6.0.39.zip
I want ant to determine that apache-tomcat-6.0.39.zip is the latest file. Is there a way to do this?
Thanks!
Use resource collections, see last and sort. f.e. :
<project>
<path id="foo">
<last>
<sort>
<fileset dir="C:/some/path" includes="**/apache-tomcat-*.zip"/>
</sort>
</last>
</path>
<echo>$${foo} => ${toString:foo}</echo>
</project>
output :
[echo] ${foo} => C:\some\path\apache-tomcat-6.0.39.zip
use <pathconvert>to get file names from the relevant <fileset>.
use <sortlist> to sort the filenames in natural String order.
pick the last filename from the list.
try this:
<fileset dir="${your.base.dir}" id="one">
<include name="**/apache-tomcat-.*.zip"/>
</fileset>
<pathconvert property="orig.list" refid="one" pathsep=","/>
<sortlist property="sorted.list" value="${orig.list}" delimiter="," />
<propertyregex property="result" input="${sorted.list}" regexp=",?([^,]+?)$" select="\1"/>
inputList: <property name="one" value="a.b-2,a.b-5,a.b-1,a.b-3,a.b-4"/>
outputList: [echo] a.b-5

Ant: How do I interate over all subfolders and perform a task in ant

Currently I do
<foreach list="${myfolders}" target="bundle"
param="worksheet" inheritall="true"/>
to execute the target "bundle" on a list of folders. However the problem is I need to set this list. How do I use Ant to just loop through all the folders given the parent directory?
If there is a way to do this and also exclude specific folders that would be even better. Thanks.
You can provide a <dirset> for the <foreach> task to operate on:
<foreach target="bundle" param="worksheet" inheritall="true">
<path>
<dirset dir="${subDir}">
<include name="*"/>
</dirset>
</path>
</foreach>
Notice that the list parameter isn't used when I do it this way.
You can't use <dirset> directly under the <foreach> as you can with <fileset>. However, you can put the <dirset> under the <path> as shown above. The <include name="*"/> prevents recursing down the directory tree.
You can do this with subant
Example:
<?xml version="1.0" encoding="UTF-8"?>
<project name="subant" default="subant1">
<target name="subant1">
<subant target="">
<dirset dir="." includes="*"/>
<target name="release" />
</subant>
</target>
</project>
I use the foreach task from ant-contrib for a similar job. This will call a specified target for each entry in a list, passing the entry as a parameter each time.

Resources