I have a text file. I need to read the content of the file from the reverse order (from EOF). Please let me know how I can achieve it using Nant script.
Thanks,
Priya.R
You could write it in C# inside your NAnt script like this:
<target name="read">
<script language="C#" prefix="myprefix" >
<code>
<![CDATA[
[Function("reverse-lines")]
public static string ReverseLines( string s )
{
string[] lines = s.Split(new char[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries);
string result = "";
foreach (string line in lines)
{
result = line + "\r\n" + result;
}
return result;
}
]]>
</code>
</script>
<loadfile file="myfile.txt" property="contents" />
<echo message="File contents in correct order:" />
<echo message="${contents}" />
<echo message="File contents in reverse order:" />
<echo message="${myprefix::reverse-lines(contents)}" />
</target>
You could use the Windows program sort /R to create a sorted copy of the file.
Related
I am trying for first time to parse a XML file and I am using SWXMLHash.
My xml file is:
<weatherdata xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://api.met.no/weatherapi/locationforecast/1.9/schema" created="2018-02-13T18:12:31Z">
<meta>
<model name="LOCAL" termin="2018-02-13T12:00:00Z" runended="2018-02-13T14:27:32Z" nextrun="2018-02-13T22:00:00Z" from="2018-02-13T19:00:00Z" to="2018-02-16T06:00:00Z" />
<model name="EPS" termin="2018-02-13T00:00:00Z" runended="2018-02-13T09:03:05Z" nextrun="2018-02-13T22:00:00Z" from="2018-02-16T12:00:00Z" to="2018-02-22T18:00:00Z" />
</meta>
<product class="pointData">
<time datatype="forecast" from="2018-02-13T19:00:00Z" to="2018-02-13T19:00:00Z">
<location altitude="0" latitude="" longitude="">
<temperature id="TTT" unit="celsius" value="3.5"/>
<windDirection id="dd" deg="158.8" name="S"/>
<windSpeed id="ff" mps="8.8" beaufort="5" name="Frisk bris"/>
<windGust id="ff_gust" mps="15.0"/>
<areaMaxWindSpeed mps="13.8"/>
<humidity value="82.1" unit="percent"/>
<pressure id="pr" unit="hPa" value="1002.5"/>
<cloudiness id="NN" percent="99.3"/>
<fog id="FOG" percent="0.0"/>
<lowClouds id="LOW" percent="73.2"/>
<mediumClouds id="MEDIUM" percent="0.0"/>
<highClouds id="HIGH" percent="91.0"/>
<dewpointTemperature id="TD" unit="celsius" value="0.6"/>
</location>
</time>
The <time> </time> repeates.
Having made a let parsedResultXML = SWXMLHash.parse(data)
I am trying to parse with a for in loop
for node in parsedResultXML["weatherdata"]["product"]["time"].all{
print(node)
}
I get results
<time to="2018-02-14T01:00:00Z" from="2018-02-14T01:00:00Z" datatype="forecast">
<location latitude="" longitude="" altitude="0">
<temperature id="TTT" unit="celsius" value="3.4"></temperature>
<windDirection id="dd" name="S" deg="158.7"></windDirection>
<windSpeed name="Liten kuling" mps="11.1" id="ff" beaufort="6"></windSpeed>
<windGust id="ff_gust" mps="19.0"></windGust>
<areaMaxWindSpeed mps="17.5"></areaMaxWindSpeed>
<humidity unit="percent" value="88.3"></humidity>
<pressure id="pr" unit="hPa" value="1002.5"></pressure>
<cloudiness id="NN" percent="99.3"></cloudiness>
<fog id="FOG" percent="0.1"></fog>
<lowClouds id="LOW" percent="98.6"></lowClouds>
<mediumClouds id="MEDIUM" percent="93.4"></mediumClouds>
<highClouds id="HIGH" percent="57.8"></highClouds>
<dewpointTemperature id="TD" unit="celsius" value="1.5"></dewpointTemperature>
</location>
</time>
But I can't access the elements.
Using
for node in parsedResultXML["weatherdata"]["product"]["time"].all{
node["time"].element?.attribute(by: "from")?.text
}
I don't get any results back.
Any idea??
Thanks
You're close... as #rmaddy commented, node is already indexed to "time". So instead of:
for node in parsedResultXML["weatherdata"]["product"]["time"].all {
node["time"].element?.attribute(by: "from")?.text
}
Do this instead:
for node in parsedResultXML["weatherdata"]["product"]["time"].all {
node.element?.attribute(by: "from")?.text
}
I am including a .properties file, which has a list of properties:
configuration.files = file1, file2
configuration.files.file1.source = config/filename1
configuration.files.file2.source = config/filename2
Now I need the paths for each file changed to something like this:
vendor/project/config/filename1
vendor/project/config/filename2
To achieve that, I tried to foreach this list and prepend that suffix and overriding the existing property:
<foreach list="${configuration.files}" target="_prepend-vendor-path" param="file" >
<property name="configuration.files.${file}.source" value="/vendor/project/${configuration.files.${file}.source}" override="true"/>
</foreach>
<target name="_prepend-vendor-path" >
<echo msg="${configuration.files.${file}.source}" />
</target>
This doesn't work and I can't figure out why. Is it even possible to use target names like ${suffix}.name ? If not, how could I achive my goal here?
I just did some workaround for this, writing out the properties and their values to a file and readin them after the loop has finished with override = true:
<target name="_prepend-vendor-path" >
<exec dir="${project.basedir}" command="echo configuration.files.${file}.source = /vendor/project/${configuration.files.${file}.source} >> ${project.temp.config}" passthru="true" checkreturn="true" />
</target>
and after the foreach simply:
<property file="${project.temp.config}" override="true"/>
For some reason the properties won't be overridden in the foreach and I just can't figgure out why, but this little trick made it for me.
You can suffix your property values from your file with the property task using a filterchain and a regular expression replacement:
<?xml version="1.0"?>
<project name="Phing Build Tests" default="append-custom-path" basedir=".">
<target name="append-custom-path">
<property file="prop.properties">
<filterchain>
<replaceregexp>
<regexp pattern="^(.*)" replace="vendor/project/$1"/>
</replaceregexp>
</filterchain>
</property>
<echo>${configuration.files.file1.source}</echo>
<echo>${configuration.files.file2.source}</echo>
</target>
</project>
I have created a scenario by creating a myScenario.sdl in my local config folder /atg/registry/data/scenarios/myScenario.sdl
myScenario.sdl
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE process SYSTEM "dynamosystemresource:/atg/dtds/pdl/pdl_1.0.dtd">
<process author="admin" creation-time="1413804041263" enabled="false" last-modified-by="admin" modification-time="1413804191188">
<segment migrate-subjects="true">
<segment-name>ItemAddedToOrder</segment-name>
<!--================================-->
<!--== Item added to order Quantity with fraction is defined -->
<!--================================-->
<event id="1">
<event-name>atg.commerce.order.ItemAddedToOrder</event-name>
<filter construct="event-property-filter" operator="isNotNull">
<event-property construct="event-property">
<property-name>quantityWithFraction</property-name>
</event-property>
</filter>
</event>
<!--================================-->
<!--== Log a message message: Quantity With Fraction is Defines logTriggeringEvent: true -->
<!--================================-->
<action id="2">
<action-name>Log a message</action-name>
<action-param name="message">
<constant>Quantity With Fraction is Defines</constant>
</action-param>
<action-param name="logTriggeringEvent">
<constant type="java.lang.Boolean">true</constant>
</action-param>
</action>
</segment>
</process>
And enabled the scenario:
Registry scenarioRegistry = scenarioManager.getScenarioRegistry();
byte[] data = (byte[]) scenarioRegistry.getItem(pScenarioPath);
String xml = null;
if (data != null) {
xml = new String(data, "UTF-8");
} else {
Assert.fail("No scenario is existed to enable/disable");
}
String updatedXml;
if (scenarioState && xml != null) {
updatedXml = xml.replaceAll("enabled=\"false\"", "enabled=\"true\"");
} else {
updatedXml = xml.replaceAll("enabled=\"true\"", "enabled=\"false\"");
}
scenarioRegistry.putItem(pScenarioPath, updatedXml.getBytes("UTF-8"));
Now with this above written code, I can both disable or enable the scenario by changing the state as false and true respectively. But I want to delete the scenario(please remember, my requirement is DELETE not DISABLE SCENARIO). I know using scenarioManager.updateScenario() deleted the scenario. Is my understanding right?
One more thing, I know I can delete the scenario directly from ACC. But I need to code via code not manually from ACC.
Please share your thoughts!
Did you try scenarioRegistry.removeItem(path);
I need to include all xml files inside a directory (I dont know the name, and count of files) in my current build.xml using ImportTask.
This is my build.xml file:
<?xml version="1.0" encoding="utf-8"?>
<project name="New Project" basedir="." default="myimport">
<target name="myimport" description="dummy to import other build files">
<if>
<isset property="file" />
<then>
<echo msg="Importing ${file}" />
<import file="${file}" />
</then>
</if>
</target>
<if>
<not>
<isset property="dummy.property" />
</not>
<then>
<echo msg="Now include all files in ./dev/build directory" />
<property name="dummy.property" value="true" />
<foreach param="msg" absparam="file" target="myimport">
<fileset dir="./dev/build/">
<include name="*.xml"/>
</fileset>
</foreach>
</then>
</if>
</project>
and an example file in target directory:
<?xml version="1.0" encoding="utf-8"?>
<project name="test" basedir="." default="dummy">
<target name="dummy" description="Dummy task">
<echo msg="Dummy task, just for test" />
</target>
<echo msg="Imported!" />
</project>
when I run phing -l the result is:
Buildfile: /home/f0rud/workspace/s/build.xml
[echo] Now include all files in ./dev/build directory
[foreach] Calling Buildfile '/home/f0rud/workspace/s/build.xml' with target 'myimport'
New Project > myimport:
[echo] Importing ./dev/build/test.xml
[echo] Imported!
Default target:
----------------------------------------------------------------------------
myimport dummy to import other build files
Main targets:
----------------------------------------------------------------------------
myimport dummy to import other build files
But there is no dummy (or test.dummy) target, why?
Note : There is a funny bug, if I remove the if part, I get Maximum function nesting level of '100' reached, aborting! error but thats not my problem (the if solve that problem.)
The problem is import work on global context.
When I call it inside a target, its not available in global context.
So I've written a simple Phing task to load all files of a fileset like so:
class ImportDirTask extends Task {
/** Array of filesets */
private $filesets = array();
/**
* Nested creator, adds a set of files (nested fileset attribute).
*/
function createFileSet() {
$num = array_push($this->filesets, new FileSet());
return $this->filesets[$num-1];
}
/**
* Parse a Phing build file and copy the properties, tasks, data types and
* targets it defines into the current project.
*
* #return void
*/
public function main () {
// filesets
foreach ($this->filesets as $fs) {
$ds = $fs->getDirectoryScanner($this->project);
$srcFiles = $ds->getIncludedFiles();
$srcDirs = $ds->getIncludedDirectories();
foreach ($srcFiles as $f)
{
$task = new ImportTask();
$task->setProject($this->project);
$task->init();
$task->setFile($this->file = $fs->getDir($this->project) . FileSystem::getFileSystem()->getSeparator() . $f);
$task->main();
}
}
} //end main
} //end ImportDirTask
It just work.
I am calling a target by means of phingcall command.
I want to pass back a status variable from the called target or at least change the existing value from the calling target.
Goal: I want to branch in my main target controlling logic if the sub target fails which I indicate with a property.
The code below does not work. Any idea how to make it work or an altertive approach for my goal?
Thanks,
Juergen
<target name="main">
<echo>target a</echo>
<echo>${bOk}</echo>
<exec command="echo 1" outputProperty="bOk" />
<echo>bOk is 1: ${bOk}</echo>
<phingcall inheritRefs="true" target="sub">
</phingcall>
<echo>bOk should now be 0: ${bOk}</echo>
</target>
<target name="sub">
<echo>target b</echo>
<echo>bOk is 1: ${bOk}</echo>
<exec command="echo 0" outputProperty="bOk" />
<echo>bOk now is 0: ${bOk}</echo>
</target>
The problem here is that
<echo>bOk should now be 0: ${bOk}</echo>
echos
bOk should now be 0: 1
Even with the great help of #phing IRC I couldn't solve the problem.
I decided to write a custom task to account for data passing between targets:
<?php
require_once "phing/Task.php";
class rvGlobalTask extends Task {
private static $bOk = 1;
private $sMode = null;
private $bValue = null;
private $outputProperty = null;
public function setSMode( $sMode ) {
$this->sMode = $sMode;
}
public function setBValue( $bValue ) {
$this->bValue = $bValue;
}
public function setOutputProperty( $outputProperty ) {
$this->outputProperty = $outputProperty;
}
public function main() {
if ( $this->sMode == "set" ) {
rvGlobalTask::$bOk = $this->bValue;
} else {
$this->project->setProperty(
$this->outputProperty,
rvGlobalTask::$bOk
);
}
}
}
?>
This works fine for my problem. Perhaps someone else finds this useful as well.
Here's how you use an ExecTask to capture output.
<?xml version="1.0" encoding="UTF-8"?>
<project name="example" default="check-composer">
<!-- set a property to contain the output -->
<property name="whichComposer" value="" />
<!-- check if composer (getcomposer.org) is installed globally -->
<target name="check-composer">
<!-- put the output of "which" in our property -->
<exec command="which composer" outputProperty="whichComposer" />
<!-- act on what we found out -->
<if>
<contains string="${whichComposer}" substring="composer" />
<then>
<echo>Composer installed at ${whichComposer}</echo>
</then>
<else>
<echo message="better install composer. ${whichComposer}"/>
</else>
</if>
</target>
</project>