NAnt has directory::get-last-write-time and file::get-last-write-time, but I am looking for a way to get the time of the most recent write of any file in a directory (recursively) or fileset.
directory::get-last-write-time might seem useful, but it only gets updated if a file directly in the directory gets written to, not for a file within a sub-directory.
Is there any way to do this with stock NAnt or would I have to write something that recurses over all the contents of a directory/fileset and finds the most recent write time?
You can do this with NAnt using a plain old <foreach> loop. A little bit awkward but it works:
<target name="go">
<fileset
id="paths"
basedir="C:\foo">
<include name="**/*" />
</fileset>
<!-- preset with Unix epoch -->
<property
name="most.recent"
value="1970-01-01T00:00:00Z" />
<foreach item="File" property="path">
<in>
<items refid="paths" />
</in>
<do>
<property
name="current"
value="${file::get-last-write-time(path)}" />
<property
name="most.recent"
value="${current}"
if="${datetime::parse(current) > datetime::parse(most.recent)}" />
</do>
</foreach>
<echo message="${most.recent}" />
</target>
Related
I'm struggling to figure out this task in Ant. There are not many examples in the documentation and I can;t seem to find a solid answer online.
I need to scan a directory that contains several sub-directories eg
Root
TargetFolder
Folder A
Folder B
Folder C
...
Folder Z
I need to run the build.xml from Root, and with a task scan all sub-directories of TargetFolder (so Folder A, B, C etc) and if the directory contains a file, foo.txt, run an <apply> task for that directory.
I'm able to do a <dirset> and get the list of sub-directories. And I can do a separate <fileset> to scan TargetFolder and get all occurences of foo.txt. But, I have no clue how to combine these things, or how to go about doing a simple file check attached to the <apply> task.
Here is one way. Use a dirset as you say, with the <present> selector:
<dirset id="dirs" dir="Root">
<present targetdir="Root">
<mapper type="glob" from="*" to="*/foo.txt" />
</present>
</dirset>
<apply executable="ls">
<arg value="-alF" />
<dirset refid="dirs" />
</apply>
You could merge both into one task:
<apply executable="ls">
<arg value="-alF" />
<dirset id="dirs" dir="Root">
<present targetdir="Root">
<mapper type="glob" from="*" to="*/foo.txt" />
</present>
</dirset>
</apply>
I'm having several outputs of a program that I need to compare with a "expected" ouput folder. But my problem is that the output files always have a different filename.
How can I rename all files in a folder to the same filenames in another folder. Here the example - the expected file structure (can of course change):
expected/folder1/file1.txt
expected/folder1/file2.txt
expected/folder2/file1.txt
expected/folder3/file1.txt
And my output looks like this (number of files and position is always equal):
result/folder1/fileOtherName1.txt
result/folder1/fileOtherName2.txt
result/folder2/fileOtherName1.txt
result/folder3/fileOtherName1.txt
I tried using ANT (because I know that), but was stuck, because I cannot select a file by the index (sorted alphabetically).
Here my pseudocode in ANT (but don't know how to continue):
<target name="foo">
<foreach>
<fileset dir="result" casesensitive="yes">
<include name="**/*.txt"/>
</fileset>
<antcall target="rename">
</antcall>
</foreach>
</target>
<target name="rename">
<!-- how can I access another fileset and take the correct file? -->
<!-- Here I got stuck -->
<echo message="foreach.file is ${foreach.file}" />
<echo message="foreach.dir is ${foreach.dir}" />
<echo message="foreach.name.ext is ${foreach.name.ext}" />
<echo message="foreach.name is ${foreach.name}" />
</target>
Thanks for any help, it must not be in ANT only - a BASH script or similar could do the job too.
How about
#!/bin/bash
IN_DIR="expected/folder1"
OUT_DIR="result/folder2"
IN_FILES=($IN_DIR/*)
OUT_FILES=($OUT_DIR/*)
for ((i=0; i<${#IN_FILES[#]}; i++)); do
mv ${OUT_FILES[i]} $OUT_DIR/$(basename ${IN_FILES[i]})
done
Tested it on some test dirs, and it works OK.
Note that if any of your file names contains a space, it does not work.
I personally don't know ANT, so I'll give it a shot in bash.
for i in *; do
k=1;
for j in $i/*; do
mv "$j" $i/file$k.txt;
k=$[$k+1];
done;
done
This iterates through the folders and increments a counter for every file in the folder. When we proceed to the next folder, the counter is reset.
I created a test directory structure like yours and it worked for me.
I currently have this command:
copy /b *.txt newfile.txt
But I want to include all files with folders as well.
How can I do this? Is it possible to add this to Apache Ant as well?
I also consider doing this to minify JS files.
Im using windows and would like a command to run or batch file but having issues.
Is there anyway to remove lines as well?
Is there a better command to use than the one I am currently using?
UPDATE:
<target name="concatenate" description="Concatenate all js files">
<concat destfile="build/application.js">
<fileset dir="js" includes="*.js" />
</concat>
</target>
<target name="compress" depends="concatenate" description="Compress application.js to application-min.js">
<apply executable="java" parallel="false">
<filelist dir="build" files="application.js" />
<arg line="-jar" />
<arg path="C:\yuicompressor-2.4.7\build\yuicompressor-2.4.7.jar" />
<srcfile />
<arg line="-o" />
<mapper type="glob" from="*.js" to="build/*-min.js" />
<targetfile />
</apply>
Now i am using the above code but cant get it to include files within folders
As oers pointed out in the comment, Ant patterns use ** to recursively match directories. Here is the relevant Patterns section from the Ant manual:
To make things a bit more flexible, we add one extra feature, which makes it possible to match multiple directory levels. This can be used to match a complete directory tree, or a file anywhere in the directory tree. To do this, ** must be used as the name of a directory. When ** is used as the name of a directory in the pattern, it matches zero or more directories. For example: /test/** matches all files/directories under /test/, such as /test/x.java, or /test/foo/bar/xyz.html, but not /xyz.xml.
There is one "shorthand": if a pattern ends with / or \, then ** is appended. For example, mypackage/test/ is interpreted as if it were mypackage/test/**.
The "concatenate" target above would be:
<target name="concatenate" description="Concatenate all js files">
<concat destfile="build/application.js">
<fileset dir="js" includes="**/*.js" excludes="**/*.min.js" />
</concat>
</target>
How do I diff two files in MSBuild? I cannot find any specific task to do it.
If possible, is it also possible to exclude certain rows, or patterns in the files eg.
2009-12-09T10:03:07.6888125+02:00
You're gonna have to write your own MSBuild task which wraps some difftool commandline app. For commandline apps, you can inherit from the ToolTask class, which provides quite a bit of command line plumbing.
<Target Name="CheckFileSyncStatus" BeforeTargets="Build" Inputs="#(FilesToSync -> '..\..\..\folder1\folder2\%(Filename)%(Extension)')" Outputs="#(FilesToSync)">
<Exec Command="FC "%(FilesToSync.Filename)%(FilesToSync.Extension)" "..\..\..\folder1\folder2\%(FilesToSync.Filename)%(FilesToSync.Extension)"">
<Output TaskParameter="ExitCode" PropertyName="FCExitCode" />
</Exec>
<Error Text="[HP.OneDriver.Win10S.DriverProperties]:Files out of sync from source: %(FilesToSync.Filename)%(FilesToSync.Extension)" Condition="FCExitCode == 1" />
What is the simplest way to move everything out of a target directory?
I have this basedir/parentdir/<subdir>. I have many different <subdir>. I need to move them out into the same level as parentdir so that it becomes basedir/<subdir>. Now, each <subdir> contains a deep tree of many other subdirectories and files, including empty subdirectories.
I've tried the following:
<move todir="basedir">
<fileset dir="parentdir">
<include name="**/*.*" />
</fileset>
</move>
That failed to move the empty directories - meaning after the move, all the <subdir> are missing their empty subdirectories. "move" supposedly copies emptysubdirectories by default, so I tried the following next:
<move todir="basedir">
<fileset dir="parentdir">
<include name="**/*" />
<include name="**/*.*" />
</fileset>
</move>
While I did manage to move the empty subdirectories, the strange thing is that all the immediate subdirectories of all the <subdir> gets copied into basedir. Every <subdir> has src, test, and build. These are now sitting in basedir as well as in their original moved <subdir>.
I'm positive I'm doing something wrong but I don't know what. Am I approaching things the wrong way?
Try this
<project name="moveproject" basedir="." default="moveDirs">
<target name="moveDirs">
<move todir="${basedir}" includeEmptyDirs="yes" verbose="true">
<fileset dir="parentdir" >
<include name="**/*" />
</fileset>
</move>
</target>
</project>