Ant xslt task output to stdout - ant

Using the <xslt> task in ant, how do I get the output to generate to stdout?
My XSLT is generating multiple files through xsl:result-document and the normal output is just status information that I'd like to show up with normal Ant output. Ant seems to force me to supply a destdir= or an out= parameter.
Ant 1.8.2 with Saxon 9

Yes ant does this. However XSLT has the element which you can use to get output on the stdout :)
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="xml" indent="yes"/>
<xsl:key name="types" match="a" use="text()"/>
<xsl:template match="/">
<result>
<xsl:message terminate="no">I am a message from xslt!</xsl:message>
</result>
</xsl:template>
</xsl:stylesheet>
Output :
build:
[xslt] Processing C:\Users\Stefanos\Documents\Visual Studio 2010\Projects\stackOverflow\stackOverflow\test.xml to C:\Users\Stefanos\Documents\Vis
ual Studio 2010\Projects\stackOverflow\stackOverflow\out.xml
[xslt] Loading stylesheet C:\Users\Stefanos\Documents\Visual Studio 2010\Projects\stackOverflow\stackOverflow\test.xslt
[xslt] I am a message from xslt!
BUILD SUCCESSFUL
Total time: 0 seconds
Hope it helps!

I recently had a similar scenario; an Ant script with an XSLT task where the style sheet transform generated multiple files using <xsl:result-document>. Since the Ant XSLT task requires the destdir attribute (unless the out attribute has been specified), I used known temp file(s) for the out destination and then implemented a “cleanup” task which deleted the temp file(s).
<target name="removeTemporaryFiles" description="remove temporary files">
<delete file="${workspace}/temp.xhtml"></delete>
…
</target>

Related

Parameter values for saxon not getting in the xslt

I am not getting the parameter value (var in this case) into the XSLT when I tried to convert an XML document with saxon.
I got the following error in the terminal:
XPST0008: XPath syntax error at char 4 on line 8 in {$var}:
Variable $var has not been declared
Failed to compile stylesheet. 1 error detected.
I tried the following in the terminal (Ubuntu 14.04):
java -jar saxon-9.1.0.8.jar -s:x.xml -xsl:x.xsl -o:x.txt var="name"
My XSL stylesheet (x.xsl) is:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="2.0">
<xsl:output method="text"/>
<xsl:template match="//files">
<xsl:value-of select="."/>
<xsl:value-of select="$var"/>
</xsl:template>
</xsl:stylesheet>
The XML (x.xml) is:
<files>
Var =
</files>

Parallel compilation of delphi projects through MSBuild

I have a script that compile all the projects (around 50) of my solution like following
msbuild "myProjName.dproj" /t:build /p:config="Release" /fileLogger /flp:ErrorsOnly /nologo
This works just fine but takes forever to compile. In order to make it faster to build i've been trying to leverage all the potential of our modern multi-core machines using the '/maxcpucount' switch explained here : http://msdn.microsoft.com/library/bb651793.aspx
I get about the same compilation time on my 4-core CPU dev machine. No perf gains.
Apparently this can only work when projects need dependencies to be built. The others "workers" would then build these dependencies projects in parallel as the main proj.
So i tried to build a project group in delphi and adding all my projects to it and than run the msbuild command on this .groupproj but it is still as slow as it has always been.
Did any of you achieved to build multiple projets at the same time with msbuild?
If yes can you provide me an explanation?
Thanks!
The following applies to RAD Studio XE4, but it may also apply to earlier or later versions. Also, the dependencies defined in the .groupproj will not be honored with this method. The .groupproj I was trying to parallelize had no inter-project dependencies, so I didn't figure out how to handle this.
When you build a .groupproj file with MSBuild using the Build, Clean or Make target, the build doesn't run in parallel because these targets use the CallTarget task to execute other targets, but CallTarget doesn't execute its targets in parallel.
In order to build separate projects in parallel, the MSBuild project must use a single MSBuild task to build multiple projects at once. The targets must be defined like this:
<Target Name="Build">
<MSBuild Projects="#(Projects)" BuildInParallel="true"/>
</Target>
<Target Name="Clean">
<MSBuild Targets="Clean" Projects="#(Projects)" BuildInParallel="true"/>
</Target>
<Target Name="Make">
<MSBuild Targets="Make" Projects="#(Projects)" BuildInParallel="true"/>
</Target>
Add these to the .groupproj, then remove the other <Target> directives as well as the <Import> directive. (CodeGear.Group.Targets defines some targets to build the projects in the proper order and to build dependencies when you ask to build only a subset of the projects, but it overrides the Build, Clean and Make targets defined in the .groupproj.) Note that this only allows you to build all projects, not just a subset.
BuildInParallel was added in MSBuild 3.5. However, since .groupproj files don't specify the ToolsVersion attribute, MSBuild will use the MSBuild task as defined in version 2.0, which didn't support BuildInParallel. There are two options to fix this:
Add ToolsVersion="3.5" (or a later version) to the root <Project> element of your .groupproj file.
Run MSBuild with the /toolsversion:3.5 (or /tv:3.5 for short) command-line parameter (/toolsversion overrides the ToolsVersion specified in all project files.)
After doing this, run MSBuild with the /maxcpucount (or /m) argument and your projects should build in parallel. However, RAD Studio doesn't handle this transformed project group correctly, so you may want to give the file a different extension to make it clear that it's not a standard RAD Studio project group (any extension that ends in proj will do).
The following XSLT stylesheet performs the transformation described above:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0"
exclude-result-prefixes="msbuild"
xmlns="http://schemas.microsoft.com/developer/msbuild/2003"
xmlns:msbuild="http://schemas.microsoft.com/developer/msbuild/2003"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="//msbuild:Project">
<xsl:copy>
<xsl:attribute name="ToolsVersion">3.5</xsl:attribute>
<xsl:apply-templates select="#* | node()"/>
<Target Name="Build">
<MSBuild Projects="#(Projects)" BuildInParallel="true"/>
</Target>
<Target Name="Clean">
<MSBuild Targets="Clean" Projects="#(Projects)" BuildInParallel="true"/>
</Target>
<Target Name="Make">
<MSBuild Targets="Make" Projects="#(Projects)" BuildInParallel="true"/>
</Target>
</xsl:copy>
</xsl:template>
<xsl:template match="//msbuild:Target">
<!-- Do not copy -->
</xsl:template>
<xsl:template match="//msbuild:Import">
<!-- Do not copy -->
</xsl:template>
<xsl:template match="#* | node()">
<xsl:copy>
<xsl:apply-templates select="#* | node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
You can apply this stylesheet with MSBuild (4.0 or later: XslTransformation was added in MSBuild 4.0) using this project file (where groupproj2parallel.xslt is the XSLT file above):
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Target Name="Build" Inputs="$(InputPaths)" Outputs="$(OutputPaths)">
<XslTransformation
XmlInputPaths="$(InputPaths)"
XslInputPath="groupproj2parallel.xslt"
OutputPaths="$(OutputPaths)" />
</Target>
</Project>
You need to specify InputPaths and OutputPaths explicitly on the command line with /p:InputPaths="..." /p:OutputPaths="...", or by specifying them on the Properties parameter of an MSBuild task. (Alternatively, you can just hardcode the file names in the project file.)
The target definitions provided with MSBuild for C# and Visual Basic projects handle dependencies by using the <ProjectReference> items defined in project files, instead of defining dependencies in the solution file. Delphi .dproj files and C++ Builder .cbproj files don't support this, as the underlying CodeGear.Common.Targets doesn't reuse the machinery defined in Microsoft.Common.Targets for <ProjectReference>.
There are two ways to build a Delphi projects: MSBuild or DCC32.exe. MSBuild is recommended as the project files (dproj and groupproj) encapsulate all configuration settings.
However, there are extra over head using MSBuild compare to plain old DCC32.exe. Furthermore, using MSBuild to build Delphi Project Group (.groupproj) doesn't bring any benefifs for multi-core CPUs. The build performance is same as single core CPU.
Here are my statistics to build a 290 dproj files in one single groupproj:
MSBuild a `groupproj` contains 290 `dproj` on 2C/4T CPU: ~100s
MSBuild a `groupproj` contains 290 `dproj` on 4C/8T CPU: ~100s
MSBuild 290 `dproj` run in multi-threads on 2C/4T CPU: ~121s
MSBuild 290 `dproj` run in multi-threads on 4C/8T CPU: ~50s
DCC 290 `dproj` run in multi-threads on 2C/4T CPU: ~37s
DCC 290 `dproj` run in multi-threads on 4C/8T CPU: ~24s
From the reading, we can conclude that MSBuild introduce extra overhead compare to DCC32. To fully utilize CPU cores and threads available, DCC32 is the way to go by sacrifice the convenient of project configuration encapsulation design for .DPROJ.
A msbuild script to build Delphi groupproj in parallel is available at https://github.com/ccy/msbuild.delphi.parallel
Little bit off-topic: you could try the fastdcc part of the IDE fix pack to get faster builds:
http://andy.jgknet.de/blog/ide-tools/ide-fix-pack/
For example, I got a build time of 1 minute going down to 22s!

JarJar with Ant - how to use a Rule file

I would like to know how to run JarJar with Ant, passing the rules in with an external Rules file.
1) I know I can pass the rules in one by one as below:
<jarjar destfile="B.jar" >
<zipfileset src="A.jar" />
<rule pattern="com.a.**" result="test.b.#1" />
</jarjar>
2) I know I can pass the rules in a file if I run it from the command line:
java -jar jarjar.jar process <rulesFile> <inJar> <outJar>
3) I can use the above command line in an Ant <exec> task. (best workaround)
4) I found some reference to using a <rulesFile> tag in Maven.
The above options are not ideal for what I would like to do.
I want to run JarJar from an Ant task, passing in a rules file.
I have been unable to get any information about this, from any forum, or by mailing the developers of JarJar, so I have decided to answer this question with a workaround that I am using:
Use the DOCTYPE & ENTITY xml entities (as per suggestion on Ant website)
As an example, the below build.xml file includes the contents of another test.txt file inline. I import the text file using the tag include_this (this is my name - you can use any name here):
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE project [
<!ENTITY include_this SYSTEM "test.txt">
]>
<project name="Test" default="build" >
<target name="build" >
&include_this;
</target>
</project>
In this simple example, the contents of the test.txt file is:
<echo>This is a test.</echo>
So I've been using this workaround to replace the rules in the jarjar call. Putting the rules in the test.txt file:
<rule pattern="com.**" result="${project.output}.com.#1" />
<rule pattern="org.**" result="${project.output}.org.#1" />
My jarjar call then becomes:
<!-- jarjar uses the same syntax as the jar task -->
<jarjar destfile="${jarjar.output.dir}/${project.output}.jar" >
<!-- source files -->
<zipfileset src="${jar.output.dir}/${project.output}.jar" />
<!-- refactoring rules -->
&include_this;
</jarjar>

Is there an ant command which lists all targets in a file and there depends?

Is there an ant command which lists all targets in a file and there depends?
Right now I just use a little power shell script to match lines that contain <target but its not really a good solution. Is there any sort of built in command?
The closest is ant -p (or ant -p -v to get more information). This won't list the target dependencies, but I don't see it as a problem: dependencies are not important for the end user (they just tell how the target works).
What's important is what the target does, which is what should be in its description:
<target name="foo" depends="bar" description="Does the foo operation">
...
</target>
I what you really want is the target dependencies, then reading the xml file is the best you can do.
No there isn't but you can do it like this :
<target name="list.targets">
<xslt in="${basedir}\{build.file}"
out="tmp"
style="${display.targets.xsl}">
</xslt>
<delete file="tmp"/>
</target>
Where ${display.targets.xsl} points to the following .xsl file :
<xsl:stylesheet version = '1.0' xmlns:xsl='http://www.w3.org/1999/XSL/Transform'>
<xsl:output method='text'/>
<xsl:template match="/">
<xsl:for-each select="//target">
<xsl:sort data-type="text" select="#name"/>
<xsl:message terminate="no">
Target : <xsl:value-of select="#name"/><xsl:if test="#depends"> depends on : <xsl:value-of select="#depends"/>
</xsl:if>
<xsl:if test="#description">
Description : <xsl:value-of select="#description"/>
</xsl:if>
</xsl:message>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
And ${basedir}{build.file} points to your current build.xml file. The output will be something like this :
[xslt] Loading stylesheet D:\Tools\StackOverFlow\test.xslt
[xslt]
[xslt] Target : build
[xslt]
[xslt] Target : modify.trs
[xslt] Description : Modifies .trs file targets
[xslt]
[xslt] Target : regex depends on : modify.trs
Depending on your build.xml of course.
If you search for "ant dependency graph", you'll find some suggestions on how to produce a .dot file from your build file which can be rendered into a visual graph by GraphViz.

How can I turn the structure of an XML file into a folder structure using ANT

I would like to be able to pass an XML file to an ANT build script and have it create a folder structure mimicking the nodal structure of the XML, using the build files parent directory as the root.
For Example using:
<root>
<folder1>
<folder1-1/>
</folder1>
<folder2/>
<folder3>
<folder3-1/>
</folder3>
</root>
ant would create:
folder1
-folder1-1
folder2
folder3
-folder3-1
I know how to create a directory, but i'm not sure how to have ANT parse the XML.
One option would be to use the xslt task to do the heavy lifting. For example, generate a second ant script and invoke it.
build.xml:
<project default="mkdirs">
<target name="mkdirs">
<xslt style="mkdir.xslt" in="dirs.xml" out="mkdir.build.xml"/>
<ant antfile="mkdir.build.xml"/>
</target>
</project>
Place mkdir.xslt in the same directory as build.xml:
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:template match="text()"/>
<xsl:template match="root">
<project><xsl:text>
</xsl:text>
<xsl:apply-templates/>
</project>
</xsl:template>
<xsl:template match="*">
<mkdir>
<xsl:attribute name="dir">
<xsl:for-each select="ancestor::*">
<xsl:if test="position() != 1">
<xsl:value-of select="name()"/>
<xsl:text>/</xsl:text>
</xsl:if>
</xsl:for-each>
<xsl:value-of select="name()"/>
</xsl:attribute>
</mkdir><xsl:text>
</xsl:text>
<xsl:apply-templates/>
</xsl:template>
</xsl:transform>
Example mkdir.build.xml output from the xslt task:
<?xml version="1.0" encoding="UTF-8"?><project>
<mkdir dir="folder1"/>
<mkdir dir="folder1/folder1-1"/>
<mkdir dir="folder2"/>
<mkdir dir="folder3"/>
<mkdir dir="folder3/folder3-1"/>
</project>
I'm not fluent in XSLT, so it might be possible to improve on the for-each loop.

Resources