Bugs item #1033631, was opened at 2004-09-24 05:18 Message generated for change (Comment added) made by ianm74 You can respond by visiting: https://sourceforge.net/tracker/?func=detail&atid=402868&aid=1033631&group_id=31650
Category: Tasks Group: 0.85 Status: Open Resolution: None Priority: 5 Submitted By: thomas strauss (tstrauss) Assigned to: Nobody/Anonymous (nobody) Summary: <touch> works not on FAT32 Initial Comment: The <touch> works not on FAT32 partitions. The test TouchTaskTest.Test_File_Millis and its friend working with the fileset are failing. I've checked this behaviour on a Win2000 and WinXP system. The reason is in the FAT32 filesystem the time begins to count in the 1980 when the first dos like OS was developed. Therefor in the test the millisseconds should be chosen after that date. After fixing this i discovered a bug in the TouchTask itself. The milliseconds should be parsed as an Int64 value to prevent an overflow. The description of the <touch> task states it behaves like the unix touch command. But there the resolution is something like 1 sec and then Int32 reaches to the year 2037 or so. I've attached the files which solves the issues. Cheers Thomas Strauss TouchTaskTest.cs --------------------- // NAnt - A .NET build tool // Copyright (C) 2001-2002 Gerry Shaw // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // Jay Turpin ([EMAIL PROTECTED]) // Gerry Shaw ([EMAIL PROTECTED]) using System; using System.Collections.Specialized; using System.IO; using System.Globalization; using NUnit.Framework; using NAnt.Core.Tasks; using Tests.NAnt.Core.Util; namespace Tests.NAnt.Core.Tasks { [TestFixture] public class TouchTaskTest : BuildTestBase { const string _format = @"<?xml version='1.0' ?> <project> <touch {0}>{1}</touch> </project>"; private static long TICKS_PER_MILLISECOND = TimeSpan.FromMilliseconds(1).Ticks; StringCollection _fileList = new StringCollection(); /// <summary>Create the text fixture.</summary> [SetUp] protected override void SetUp() { base.SetUp(); // add 3 directories Directory.CreateDirectory(Path.Combine(TempDirName, "dir1")); Directory.CreateDirectory(Path.Combine(TempDirName, "dir2")); Directory.CreateDirectory(Path.Combine(TempDirName, "dir3")); // add file names _fileList.Add(Path.Combine(TempDirName, "file1.txt")); _fileList.Add(Path.Combine(TempDirName, "file2.txt")); _fileList.Add(Path.Combine(TempDirName, Path.Combine("dir1" ,"file3.tab"))); _fileList.Add(Path.Combine(TempDirName, Path.Combine("dir1" ,"file4.txt"))); _fileList.Add(Path.Combine(TempDirName, Path.Combine("dir2" ,"file5.tab"))); _fileList.Add(Path.Combine(TempDirName, Path.Combine("dir2" ,"file6.txt"))); // add some text to each file, just for fun ;) for (int i = 0; i < _fileList.Count; i++) { TempFile.Create(_fileList[i]); } } [Test] public void Test_File_DateTime() { DateTime newTouchDate = DateTime.Parse("01/01/1980"); string fileName = _fileList[0]; RunBuild(FormatBuildFile("file='" + fileName + "' datetime='" + newTouchDate.ToString(CultureInfo.InvariantCulture) + "'")); FileInfo file = new FileInfo(fileName); DateTime lastTouchDate = file.LastWriteTime; Assert.IsTrue(newTouchDate.Equals(lastTouchDate), "File not touched"); // Make sure another file is NOT touched fileName = _fileList[1]; file = new FileInfo(fileName); lastTouchDate = file.LastWriteTime; Assert.IsFalse(newTouchDate.Equals(lastTouchDate), "Wrong file was touched"); } [Test] public void Test_File_Millis() { // <touch file='myfile' millis='1000000000'/> string fileName = _fileList[0]; long milliSeconds = ((DateTime.Parse("01/01/1980").Ticks - DateTime.Parse("01/01/1970").Ticks) / TICKS_PER_MILLISECOND); DateTime newTouchDate = DateTime.Parse("01/01/1970").Add(TimeSpan.FromMilliseconds(milliSeconds)); RunBuild(FormatBuildFile("file='" + fileName + "' millis='" + milliSeconds.ToString() + "'")); FileInfo file = new FileInfo(fileName); DateTime lastTouchDate = file.LastWriteTime; Assert.IsTrue(newTouchDate.Equals(lastTouchDate), "Wrong touch date"); // Make sure another file is NOT touched fileName = _fileList[1]; file = new FileInfo(fileName); lastTouchDate = file.LastWriteTime; Assert.IsFalse(newTouchDate.Equals(lastTouchDate), "Wrong file touched"); } [Test] public void Test_File_Default() { // avoid test failure on fast machines and linux System.Threading.Thread.Sleep(1000); string fileName = _fileList[0]; DateTime newTouchDate = DateTime.Now; // avoid test failure on fast machines and linux System.Threading.Thread.Sleep(1000); RunBuild(FormatBuildFile("file='" + fileName + "'")); FileInfo file = new FileInfo(fileName); DateTime lastTouchDate = file.LastWriteTime; // Can only ensure that Now() is greater or equal to the file date Assert.IsTrue(lastTouchDate.CompareTo(newTouchDate) >= 0, "Touch date incorrect"); // Make sure another file is NOT touched fileName = _fileList[1]; file = new FileInfo(fileName); lastTouchDate = file.LastWriteTime; Assert.IsFalse(newTouchDate.Equals(lastTouchDate), "Wrong file touched"); } [Test] public void Test_Same_File_Twice() { // <touch file='myfile' /> // <touch file='myfile' /> // Old code used to lock the file - shouldn't now, allowing us to mess with it between runs string fileName = _fileList[0]; // Get rid of the file first File.Delete(fileName); RunBuild(FormatBuildFile("file='" + fileName + "'")); Assert.IsTrue(File.Exists(fileName), "File doesn't exist!"); File.Delete(fileName); RunBuild(FormatBuildFile("file='" + fileName + "'")); Assert.IsTrue(File.Exists(fileName), "File doesn't exist!"); File.Delete(fileName); } [Test] public void Test_FileSet_DateTime() { // <touch datetime="01/01/1980 00:00"> // <fileset dir="src_dir"/> // </touch> DateTime newTouchDate = DateTime.Parse("01/01/1980"); RunBuild(FormatBuildFile("datetime='" + newTouchDate.ToString(CultureInfo.InvariantCulture) + "'","<fileset basedir='" + TempDirName + "'><include name='**' /></fileset>")); for (int i = 0; i < _fileList.Count; i++) { FileInfo file = new FileInfo(_fileList[i]); DateTime lastTouchDate = file.LastWriteTime; Assert.IsTrue(newTouchDate.Equals(lastTouchDate), "Touch: fileset, datetime, " + _fileList[i]); } } [Test] public void Test_FileSet_Millis() { // <touch millis="100000"> // <fileset dir="src_dir"/> //</touch> long milliSeconds = ((DateTime.Parse("01/01/1980").Ticks - DateTime.Parse("01/01/1970").Ticks) / TICKS_PER_MILLISECOND); DateTime newTouchDate = DateTime.Parse("01/01/1970").Add(TimeSpan.FromMilliseconds(milliSeconds)); RunBuild(FormatBuildFile("millis='" + milliSeconds.ToString(CultureInfo.InvariantCulture) + "'","<fileset basedir='" + TempDirName + "'><include name='**' /></fileset>")); for (int i = 0; i < _fileList.Count; i++) { FileInfo file = new FileInfo(_fileList[i]); DateTime lastTouchDate = file.LastWriteTime; Assert.IsTrue(newTouchDate.Equals(lastTouchDate), "Touch: fileset, millis, " + _fileList[i]); } } [Test] public void Test_FileSet_Default() { DateTime newTouchDate = DateTime.Now; // avoid test failure on linux System.Threading.Thread.Sleep(1000); RunBuild(FormatBuildFile("","<fileset basedir='" + TempDirName + "'><include name='**' /></fileset>")); for (int i = 0; i < _fileList.Count; i++) { FileInfo file = new FileInfo(_fileList[i]); DateTime lastTouchDate = file.LastWriteTime; Assert.IsTrue(lastTouchDate.CompareTo(newTouchDate) >= 0, "Touch: fileset ONLY, " + _fileList[i]); } } private string FormatBuildFile(string options) { return FormatBuildFile(options, ""); } private string FormatBuildFile(string options, string nestedElements) { return String.Format(CultureInfo.InvariantCulture, _format, options, nestedElements); } } } --------------------- TouchTest.cs --------------------- // NAnt - A .NET build tool // Copyright (C) 2001-2002 Gerry Shaw // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // Jay Turpin ([EMAIL PROTECTED]) // Gerry Shaw ([EMAIL PROTECTED]) using System; using System.IO; using System.Globalization; using NAnt.Core.Attributes; using NAnt.Core.Types; using NAnt.Core.Util; namespace NAnt.Core.Tasks { /// <summary> /// Touches a file or set of files -- corresponds to the Unix touch command. /// </summary> /// <remarks> /// <para> /// If the file specified in the single-file case does not exist, the task /// will create it. /// </para> /// </remarks> /// <example> /// <para>Touch the <c>Main.cs</c> file. The current time is used.</para> /// <code> /// <![CDATA[ /// <touch file="Main.cs" /> /// ]]> /// </code> /// </example> /// <example> /// <para>Touch all executable files in the current directory and its subdirectories.</para> /// <code> /// <![CDATA[ /// <touch> /// <fileset> /// <include name="**/*.exe" /> /// <include name="**/*.dll" /> /// </fileset> /// </touch> /// ]]> /// </code> /// </example> [TaskName("touch")] public class TouchTask : Task { #region Private Instance Fields private static long TICKS_PER_MILLISECOND = TimeSpan.FromMilliseconds(1).Ticks; private FileInfo _file; private string _millis; private string _datetime; private FileSet _fileset = new FileSet(); #endregion Private Instance Fields #region Public Instance Properties /// <summary> /// The file to touch. /// </summary> [TaskAttribute("file")] public FileInfo File { get { return _file; } set { _file = value; } } /// <summary> /// Specifies the new modification time of the file(s) in milliseconds /// since midnight Jan 1 1970. /// </summary> [TaskAttribute("millis")] public string Millis { get { return _millis; } set { _millis = value; } } /// <summary> /// Specifies the new modification time of the file in the format /// MM/DD/YYYY HH:MM AM_or_PM. /// </summary> [TaskAttribute("datetime")] public string Datetime { get { return _datetime; } set { _datetime = value; } } /// <summary> /// Used to select files that should be touched. /// </summary> [BuildElement("fileset")] public FileSet TouchFileSet { get { return _fileset; } set { _fileset = value; } } #endregion Public Instance Properties #region Override implementation of Task /// <summary> /// Ensures the supplied attributes are valid. /// </summary> /// <param name="taskNode">Xml node used to define this task instance.</param> protected override void InitializeTask(System.Xml.XmlNode taskNode) { // limit task to either millis or a date string if (Millis != null && Datetime != null) { throw new BuildException("Cannot specify 'millis' and 'datetime' in the same touch task.", Location); } // limit task to touching either a file or fileset if (File != null && TouchFileSet.Includes.Count != 0) { throw new BuildException("Cannot specify both 'file' attribute" + " and use <fileset> in the same <touch> task.", Location); } } protected override void ExecuteTask() { DateTime touchDateTime = DateTime.Now; // ensure base directory is set, even if fileset was not initialized // from XML if (TouchFileSet.BaseDirectory == null) { TouchFileSet.BaseDirectory = new DirectoryInfo(Project.BaseDirectory); } if (Millis != null) { touchDateTime = GetDateTime(Convert.ToInt64(Millis, CultureInfo.InvariantCulture)); } else if (Datetime != null) { touchDateTime = GetDateTime(Datetime); } // try to touch specified file if (File != null) { // touch file TouchFile(File.FullName, touchDateTime); } else { // touch files in fileset // only use the file set if file attribute has NOT been set foreach (string path in TouchFileSet.FileNames) { TouchFile(path, touchDateTime); } } } #endregion Override implementation of Task #region Private Instance Methods private void TouchFile(string path, DateTime touchDateTime) { try { if (System.IO.File.Exists(path)) { Log(Level.Verbose, "Touching file '{0}' with '{1}'.", path, touchDateTime.ToString(CultureInfo.InvariantCulture)); } else { Log(Level.Verbose, "Creating file '{0}' with '{1}'.", path, touchDateTime.ToString(CultureInfo.InvariantCulture)); // create the file (and ensure stream is closed) using (FileStream fs = System.IO.File.Create(path)) { } } System.IO.File.SetLastWriteTime(path, touchDateTime); } catch (Exception ex) { string msg = string.Format(CultureInfo.InvariantCulture, "Cannot touch file '{0}'.", path); if (FailOnError) { throw new BuildException(msg, Location, ex); } // swallow any errors and move on Log(Level.Verbose, msg + " " + ex.Message); } } private DateTime GetDateTime(string dateText){ DateTime touchDateTime = new DateTime(); if (!StringUtils.IsNullOrEmpty(dateText)) { touchDateTime = DateTime.Parse(dateText, CultureInfo.InvariantCulture); } else { touchDateTime = DateTime.Now; } return touchDateTime; } private DateTime GetDateTime(long milliSeconds) { DateTime touchDateTime = DateTime.Parse("01/01/1970 00:00:00", CultureInfo.InvariantCulture). Add(TimeSpan.FromMilliseconds(milliSeconds)); return touchDateTime; } #endregion Private Instance Methods } } --------------------- ---------------------------------------------------------------------- >Comment By: Ian MacLean (ianm74) Date: 2004-09-28 15:46 Message: Logged In: YES user_id=321872 Thanks for the bug report Thomas, I'd be happy to look at this but would you first be able to attach the files rather than pasting their contents inline ? It makes it much easier to apply the difference to current cvs if the formatting has been preserved. ---------------------------------------------------------------------- Comment By: thomas strauss (tstrauss) Date: 2004-09-28 06:15 Message: Logged In: YES user_id=1067181 Hello out there, does any body feels responsible for the bug-entry. I've provided also a possible solution. This was quite some effort to puzzle out waht was going wrong. Cheere Thomas ---------------------------------------------------------------------- You can respond by visiting: https://sourceforge.net/tracker/?func=detail&atid=402868&aid=1033631&group_id=31650 ------------------------------------------------------- This SF.Net email is sponsored by: YOU BE THE JUDGE. Be one of 170 Project Admins to receive an Apple iPod Mini FREE for your judgement on who ports your project to Linux PPC the best. Sponsored by IBM. Deadline: Sept. 24. Go here: http://sf.net/ppc_contest.php _______________________________________________ nant-developers mailing list [EMAIL PROTECTED] https://lists.sourceforge.net/lists/listinfo/nant-developers