You can subscribe to this list here.
2001 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
(35) |
Nov
(7) |
Dec
(26) |
---|---|---|---|---|---|---|---|---|---|---|---|---|
2002 |
Jan
(73) |
Feb
(87) |
Mar
(96) |
Apr
(69) |
May
(36) |
Jun
(68) |
Jul
(55) |
Aug
(76) |
Sep
(8) |
Oct
(79) |
Nov
(8) |
Dec
(21) |
2003 |
Jan
(43) |
Feb
(82) |
Mar
(163) |
Apr
(294) |
May
(233) |
Jun
(159) |
Jul
(181) |
Aug
(214) |
Sep
(224) |
Oct
(226) |
Nov
(138) |
Dec
(312) |
2004 |
Jan
(48) |
Feb
(195) |
Mar
(112) |
Apr
(136) |
May
(182) |
Jun
(78) |
Jul
(288) |
Aug
(327) |
Sep
(156) |
Oct
(62) |
Nov
(241) |
Dec
(167) |
2005 |
Jan
(202) |
Feb
(109) |
Mar
(148) |
Apr
(113) |
May
(104) |
Jun
(130) |
Jul
(27) |
Aug
(4) |
Sep
(9) |
Oct
(36) |
Nov
(19) |
Dec
(11) |
2006 |
Jan
(1) |
Feb
(2) |
Mar
(58) |
Apr
(34) |
May
(15) |
Jun
(19) |
Jul
(19) |
Aug
(10) |
Sep
(26) |
Oct
(38) |
Nov
(19) |
Dec
(54) |
2007 |
Jan
(74) |
Feb
(39) |
Mar
(36) |
Apr
(48) |
May
(8) |
Jun
(16) |
Jul
(25) |
Aug
(59) |
Sep
(25) |
Oct
(38) |
Nov
(52) |
Dec
(82) |
2008 |
Jan
(16) |
Feb
(32) |
Mar
(51) |
Apr
(30) |
May
(21) |
Jun
(44) |
Jul
(41) |
Aug
(36) |
Sep
(22) |
Oct
(20) |
Nov
(67) |
Dec
(46) |
2009 |
Jan
(50) |
Feb
(25) |
Mar
(54) |
Apr
(70) |
May
(145) |
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
(1) |
Dec
|
2010 |
Jan
|
Feb
(39) |
Mar
(24) |
Apr
(81) |
May
(65) |
Jun
(2) |
Jul
(1) |
Aug
(5) |
Sep
(2) |
Oct
(13) |
Nov
(2) |
Dec
(5) |
2011 |
Jan
|
Feb
|
Mar
|
Apr
(8) |
May
(8) |
Jun
(3) |
Jul
(2) |
Aug
(4) |
Sep
(6) |
Oct
(17) |
Nov
(1) |
Dec
(4) |
2012 |
Jan
(10) |
Feb
(6) |
Mar
(22) |
Apr
(35) |
May
(18) |
Jun
(2) |
Jul
(3) |
Aug
(6) |
Sep
(2) |
Oct
(2) |
Nov
|
Dec
|
2013 |
Jan
|
Feb
|
Mar
(9) |
Apr
(8) |
May
|
Jun
|
Jul
|
Aug
|
Sep
(3) |
Oct
(4) |
Nov
|
Dec
|
2014 |
Jan
|
Feb
|
Mar
|
Apr
(1) |
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
(53) |
2015 |
Jan
(17) |
Feb
(16) |
Mar
(1) |
Apr
(11) |
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
From: <nan...@na...> - 2014-12-22 03:40:10
|
From: Ryan Boggs <rm...@gm...> --- doc/releasenotes.html | 11 +++++++++++ 1 files changed, 11 insertions(+), 0 deletions(-) diff --git a/doc/releasenotes.html b/doc/releasenotes.html index 0bc2568..448bc3a 100644 --- a/doc/releasenotes.html +++ b/doc/releasenotes.html @@ -55,6 +55,17 @@ <h3>Bug Fixes</h3> <h4>Tasks</h4> <div style="margin-left: 20px;"> + <h5><a class="heading" href="help/tasks/copy.html">Copy</a></h5> + <div style="margin-left: 20px;"> + <p> + Fixed issues related to copying subdirectories that were introduced in NAnt 0.92. + (Issues <a href="https://github.com/nant/nant/issues/64">#64</a>, + <a href="https://github.com/nant/nant/issues/85">#85</a>, and + <a href="https://github.com/nant/nant/issues/88">#88</a>) + </p> + </div> + </div> + <div style="margin-left: 20px;"> <h5><a class="heading" href="help/tasks/csc.html">Csc</a></h5> <div style="margin-left: 20px;"> <p> -- 1.7.7 |
From: <nan...@na...> - 2014-12-21 17:10:26
|
From: Ryan Boggs <rm...@gm...> --- tests/NAnt.Core/Tasks/CopyTest.cs | 68 ++++++++++++++++++++++++++++++++++++- 1 files changed, 67 insertions(+), 1 deletions(-) diff --git a/tests/NAnt.Core/Tasks/CopyTest.cs b/tests/NAnt.Core/Tasks/CopyTest.cs index a9617f4..1749924 100644 --- a/tests/NAnt.Core/Tasks/CopyTest.cs +++ b/tests/NAnt.Core/Tasks/CopyTest.cs @@ -88,6 +88,17 @@ namespace Tests.NAnt.Core.Tasks { </project> "; + const string _xmlProjectTemplate6 = @" + <project basedir='{0}'> + <mkdir dir='{1}' /> + <copy verbose='true' todir='{1}'> + <fileset> + <include name='{2}'/> + <include name='{3}'/> + </fileset> + </copy> + </project>"; + string tempFile1, tempFile2, tempFile3, tempFile4, tempFile5, tempFile6, tempFile7; string tempDir1, tempDir2, tempDir3, tempDir4, tempDir5; @@ -163,6 +174,61 @@ namespace Tests.NAnt.Core.Tasks { } /// <summary> + /// Checks to make sure that only specified subdirectories are copied when specified + /// in the include statement. Addresses Issue 85. + /// </summary> + [Test] + public void Test_Copy_Only_SubDirectory() + { + string dest = CreateTempDir("a.85"); + string destDir = GetPath(dest, tempDir1); + string instructions = String.Format(CultureInfo.InvariantCulture, _xmlProjectTemplate5, destDir, tempDir1, "goo"); + RunBuild(instructions); + + Assert.IsFalse(File.Exists(GetPath(dest,tempDir1,tempFile1)), "File should not have been created:" + tempFile1); + Assert.IsFalse(File.Exists(GetPath(dest,tempDir1,tempFile2)), "File should not have been created:" + tempFile2); + Assert.IsFalse(File.Exists(GetPath(dest,tempDir1,tempDir2,tempFile3)), "File should not have been created:" + tempFile3); + Assert.IsTrue(File.Exists(GetPath(dest,tempDir1,tempDir3,tempDir4,tempFile4)), "File should have been created:" + tempFile4); + Assert.IsTrue(File.Exists(GetPath(dest,tempDir1,tempDir3,tempFile5)), "File should have been created:" + tempFile5); + Assert.IsTrue(File.Exists(GetPath(dest,tempDir1,tempDir3,tempFile6)), "File should have been created:" + tempFile6); + Assert.IsTrue(File.Exists(GetPath(dest,tempDir1,tempDir3,tempFile7)), "File should have been created:" + tempFile7); + + Assert.IsTrue(Directory.Exists(GetPath(dest,tempDir1)), "Dir should have been created:" + tempDir1); + Assert.IsFalse(Directory.Exists(GetPath(dest,tempDir1,tempDir2)), "Dir should not have been created:" + tempDir2); + Assert.IsTrue(Directory.Exists(GetPath(dest,tempDir1,tempDir3)), "Dir should have been created:" + tempDir3); + Assert.IsTrue(Directory.Exists(GetPath(dest,tempDir1,tempDir3,tempDir4)), "Dir should have been created:" + tempDir4); + Assert.IsFalse(Directory.Exists(GetPath(dest,tempDir1,tempDir5)), "Dir should not have been created:" + tempDir5); + } + + /// <summary> + /// Test to make sure that the copy task copies relative file paths when the basedir of the fileset + /// is not specified. Addresses Issue 88. + /// </summary> + [Test] + public void Test_Copy_Unspecified_Fileset_Basedir() + { + string dest = CreateTempDir("a.88"); + string destDir = GetPath(dest, tempDir1, tempDir3); + string instructions = String.Format(CultureInfo.InvariantCulture, _xmlProjectTemplate6, tempDir2, destDir, + "../goo/ha.he", "../goo/ha.he2"); + RunBuild(instructions); + + Assert.IsFalse(File.Exists(GetPath(dest,tempDir1,tempFile1)), "File should not have been created:" + tempFile1); + Assert.IsFalse(File.Exists(GetPath(dest,tempDir1,tempFile2)), "File should not have been created:" + tempFile2); + Assert.IsFalse(File.Exists(GetPath(dest,tempDir1,tempDir2,tempFile3)), "File should not have been created:" + tempFile3); + Assert.IsFalse(File.Exists(GetPath(dest,tempDir1,tempDir3,tempDir4,tempFile4)), "File should not have been created:" + tempFile4); + Assert.IsTrue(File.Exists(GetPath(dest,tempDir1,tempDir3,tempFile5)), "File should have been created:" + tempFile5); + Assert.IsTrue(File.Exists(GetPath(dest,tempDir1,tempDir3,tempFile6)), "File should have been created:" + tempFile6); + Assert.IsFalse(File.Exists(GetPath(dest,tempDir1,tempDir3,tempFile7)), "File should not have been created:" + tempFile7); + + Assert.IsTrue(Directory.Exists(GetPath(dest,tempDir1)), "Dir should have been created:" + tempDir1); + Assert.IsFalse(Directory.Exists(GetPath(dest,tempDir1,tempDir2)), "Dir should not have been created:" + tempDir2); + Assert.IsTrue(Directory.Exists(GetPath(dest,tempDir1,tempDir3)), "Dir should have been created:" + tempDir3); + Assert.IsFalse(Directory.Exists(GetPath(dest,tempDir1,tempDir3,tempDir4)), "Dir should have been created:" + tempDir4); + Assert.IsFalse(Directory.Exists(GetPath(dest,tempDir1,tempDir5)), "Dir should not have been created:" + tempDir5); + } + + /// <summary> /// Ensure that an invalid path for destination directory causes a /// <see cref="BuildException" /> to be thrown. /// </summary> @@ -185,7 +251,7 @@ namespace Tests.NAnt.Core.Tasks { /// ensure it exists. /// </summary> [Test] - public void Test_Copy_Structure() { + public void Test_Copy_Structure() { string dest = CreateTempDir("a.xx"); RunBuild(string.Format(CultureInfo.InvariantCulture, _xmlProjectTemplate, dest, tempDir1 + "\\**\\*", string.Empty)); -- 1.7.7 |
From: Ryan Boggs <rm...@gm...> --- src/NAnt.Core/Filters/Support/FilterChain.cs | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/src/NAnt.Core/Filters/Support/FilterChain.cs b/src/NAnt.Core/Filters/Support/FilterChain.cs index a72a6b2..22434a1 100644 --- a/src/NAnt.Core/Filters/Support/FilterChain.cs +++ b/src/NAnt.Core/Filters/Support/FilterChain.cs @@ -189,7 +189,7 @@ namespace NAnt.Core.Filters { /// </param> internal static bool IsNullOrEmpty(FilterChain filterChain) { - return (filterChain == null) || filterChain.Filters.Count <= 0; + return (filterChain == null || filterChain.Filters.Count <= 0); } #endregion Internal Static Methods -- 1.7.7 |
From: <nan...@na...> - 2014-12-21 17:10:25
|
From: Ryan Boggs <rm...@gm...> --- src/NAnt.Core/Tasks/CopyTask.cs | 2 +- src/NAnt.Core/Types/FileSet.cs | 34 +++++++++++++++++----------------- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/src/NAnt.Core/Tasks/CopyTask.cs b/src/NAnt.Core/Tasks/CopyTask.cs index ac20e41..ed891c9 100644 --- a/src/NAnt.Core/Tasks/CopyTask.cs +++ b/src/NAnt.Core/Tasks/CopyTask.cs @@ -362,7 +362,7 @@ namespace NAnt.Core.Tasks { } // Clear previous copied files - _fileCopyMap.Clear(); + _fileCopyMap.Clear(); // if the source file is specified, check to see whether it is a file or directory before proceeding if (SourceFile != null) diff --git a/src/NAnt.Core/Types/FileSet.cs b/src/NAnt.Core/Types/FileSet.cs index 0f4e261..b91f90e 100644 --- a/src/NAnt.Core/Types/FileSet.cs +++ b/src/NAnt.Core/Types/FileSet.cs @@ -430,12 +430,12 @@ namespace NAnt.Core.Types { } } - /// <summary> - /// Gets a value indicating whether this instance retrieved all - /// files/directories scanned and nothing was excluded. - /// </summary> - public bool IsEverythingIncluded - { + /// <summary> + /// Gets a value indicating whether this instance retrieved all + /// files/directories scanned and nothing was excluded. + /// </summary> + public bool IsEverythingIncluded + { get { if (!_hasScanned) @@ -444,22 +444,22 @@ namespace NAnt.Core.Types { } return _scanner.IsEverythingIncluded; } - } - - /// <summary> - /// Gets a value indicating whether this instance contains empty directories. - /// </summary> - public bool HasEmptyDirectories - { - get - { + } + + /// <summary> + /// Gets a value indicating whether this instance contains empty directories. + /// </summary> + public bool HasEmptyDirectories + { + get + { if (!_hasScanned) { Scan(); } return _scanner.HasEmptyDirectories; - } - } + } + } /// <summary> /// The items to include in the fileset. -- 1.7.7 |
From: <nan...@na...> - 2014-12-21 17:10:25
|
From: Dmitry Kostenko <bis...@gm...> --- tests/NAnt.Core/ConcurrencyTest.cs | 53 +++++++++++++++++++++++++++++++++--- 1 files changed, 49 insertions(+), 4 deletions(-) diff --git a/tests/NAnt.Core/ConcurrencyTest.cs b/tests/NAnt.Core/ConcurrencyTest.cs index bb31fb0..6767ef4 100644 --- a/tests/NAnt.Core/ConcurrencyTest.cs +++ b/tests/NAnt.Core/ConcurrencyTest.cs @@ -31,7 +31,7 @@ namespace Tests.NAnt.Core { public class ConcurrencyTest : BuildTestBase { #region Private Static Fields - private const string TwoConcurrentTargets = @" + private const string TwoIndependentTargets = @" <project default='Target1'> <target name='Target1' depends='Target2 Target3' /> <target name='Target2'> @@ -42,17 +42,28 @@ namespace Tests.NAnt.Core { </target> </project>"; + private const string DependentTargets = @" + <project default='Target1'> + <target name='Target1' depends='Target2 Target3' /> + <target name='Target2' depends='Target3'> + <sleep seconds='1' /> + </target> + <target name='Target3'> + <sleep seconds='1' /> + </target> + </project>"; + #endregion Private Static Fields #region Public Instance Methods [Test] - public void Test_Concurrency() { + public void IndependentTargetsExecuteInParallel() { // create new listener that allows us to track build events TestBuildListener listener = new TestBuildListener(); // run the build - Project project = CreateFilebasedProject(TwoConcurrentTargets, Level.Info); + Project project = CreateFilebasedProject(TwoIndependentTargets, Level.Info); project.RunTargetsInParallel = true; @@ -63,10 +74,44 @@ namespace Tests.NAnt.Core { // execute the project ExecuteProject(project); + DateTime target2startTime = listener.GetTargetStartTime("Target2"); DateTime target2finishTime = listener.GetTargetFinishTime("Target2"); DateTime target3startTime = listener.GetTargetStartTime("Target3"); + DateTime target3finishTime = listener.GetTargetFinishTime("Target3"); + + Assert.IsTrue(target2startTime <= target2finishTime, "Target2 start time is after finish time"); + Assert.IsTrue(target3startTime <= target3finishTime, "Target3 start time is after finish time"); + + Assert.IsTrue(target3startTime <= target2finishTime, "Target3 was not started until Target2 was finished"); + Assert.IsTrue(target2startTime <= target3finishTime, "Target2 was not started until Target3 was finished"); + } + + [Test] + public void DependentTargetsExecuteSequentially() { + // create new listener that allows us to track build events + TestBuildListener listener = new TestBuildListener(); + + // run the build + Project project = CreateFilebasedProject(DependentTargets, Level.Info); + project.RunTargetsInParallel = true; + + + //use Project.AttachBuildListeners to attach. + IBuildListener[] listeners = {listener}; + project.AttachBuildListeners(new BuildListenerCollection(listeners)); + + // execute the project + ExecuteProject(project); + + DateTime target2startTime = listener.GetTargetStartTime("Target2"); + DateTime target2finishTime = listener.GetTargetFinishTime("Target2"); + DateTime target3startTime = listener.GetTargetStartTime("Target3"); + DateTime target3finishTime = listener.GetTargetFinishTime("Target3"); + + Assert.IsTrue(target2startTime <= target2finishTime, "Target2 start time is after finish time"); + Assert.IsTrue(target3startTime <= target3finishTime, "Target3 start time is after finish time"); - Assert.IsTrue(target3startTime < target2finishTime, "Target3 was not started until Target2 was finished"); + Assert.IsTrue(target3finishTime <= target2startTime, "Target2 was started before Target3 was finished"); } #endregion Public Instance Methods -- 1.7.7 |
From: <nan...@na...> - 2014-12-21 17:10:25
|
From: Ryan Boggs <rm...@gm...> --- src/NAnt.Core/DirectoryScanner.cs | 1 + src/NAnt.Core/Tasks/CopyTask.cs | 1 + src/NAnt.Core/Tasks/MoveTask.cs | 1 + 3 files changed, 3 insertions(+), 0 deletions(-) diff --git a/src/NAnt.Core/DirectoryScanner.cs b/src/NAnt.Core/DirectoryScanner.cs index 8232dc9..8a81b90 100644 --- a/src/NAnt.Core/DirectoryScanner.cs +++ b/src/NAnt.Core/DirectoryScanner.cs @@ -17,6 +17,7 @@ // // Gerry Shaw (ger...@ya...) // Kevin Dente (kev...@ya...) +// Ryan Boggs (rm...@us...) // This is useful for debugging where filesets are scanned from - scanning is one // of the most intensive activities for NAnt diff --git a/src/NAnt.Core/Tasks/CopyTask.cs b/src/NAnt.Core/Tasks/CopyTask.cs index af11cf7..ac20e41 100644 --- a/src/NAnt.Core/Tasks/CopyTask.cs +++ b/src/NAnt.Core/Tasks/CopyTask.cs @@ -17,6 +17,7 @@ // // Gerry Shaw (ger...@ya...) // Ian MacLean (ima...@gm...) +// Ryan Boggs (rm...@us...) using System; using System.Collections; diff --git a/src/NAnt.Core/Tasks/MoveTask.cs b/src/NAnt.Core/Tasks/MoveTask.cs index 47175d8..3edcbfe 100644 --- a/src/NAnt.Core/Tasks/MoveTask.cs +++ b/src/NAnt.Core/Tasks/MoveTask.cs @@ -17,6 +17,7 @@ // // Gerry Shaw (ger...@ya...) // Ian MacLean (ima...@gm...) +// Ryan Boggs (rm...@us...) using System; using System.Collections; -- 1.7.7 |
From: <nan...@na...> - 2014-12-21 17:10:23
|
From: Dmitry Kostenko <bis...@gm...> --- Makefile | 2 +- NAnt.build | 30 +++++++++++++++++++++++++++++- 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 7e1dc47..3bf051f 100644 --- a/Makefile +++ b/Makefile @@ -67,7 +67,7 @@ endif # Assign remaining vars TARGET_FRAMEWORK = -t:$(TARGET) -NANT = $(MONO) bootstrap/NAnt.exe $(NANT_DEBUG) +NANT = $(MONO) bootstrap/NAnt.exe -j $(NANT_DEBUG) all: bootstrap build-nant diff --git a/NAnt.build b/NAnt.build index 116b801..599137f 100644 --- a/NAnt.build +++ b/NAnt.build @@ -125,7 +125,7 @@ <delete dir="build" if="${directory::exists('build')}" /> </target> - <target name="build" depends="init, create-common-assemblyinfo" description="Builds current configuration"> + <target name="build.common" depends="init, create-common-assemblyinfo"> <echo message="Build Directory is ${build.dir}" /> <!-- ensure bin directory exists --> <mkdir dir="${build.dir}/bin" /> @@ -153,28 +153,56 @@ <exclude name="common/neutral/scvs.exe" /> </fileset> </copy> + </target> + + <target name="build.core" depends="build.common"> <!-- build NAnt.Core assembly --> <nant buildfile="src/NAnt.Core/NAnt.Core.build" target="build" /> + </target> + + <target name="build.console" depends="build.common,build.core"> <!-- build NAnt.Console assembly --> <nant buildfile="src/NAnt.Console/NAnt.Console.build" target="build" /> + </target> + + <target name="build.ext" depends="build.core"> <!-- build extension assemblies --> <nant target="build"> <buildfiles refid="ext.core" /> </nant> + </target> + + <target name="build.msbuild" depends="build.core,build.ext"> <!-- build NAnt.MSBuild assembly --> <nant buildfile="src/NAnt.MSBuild/NAnt.MSBuild.build" target="build" /> + </target> + + <target name="build.ndoc" depends="build.core,build.ext"> <!-- build NDoc.Documenter.NAnt assembly --> <nant buildfile="src/NDoc.Documenter.NAnt/NDoc.Documenter.NAnt.build" target="build" /> + </target> + + <target name="build.tests.core" depends="build.core"> <!-- build NAnt.Core.Tests assembly --> <nant buildfile="tests/NAnt.Core/NAnt.Core.build" target="build" /> + </target> + + <target name="build.tests.console" depends="build.console, build.tests.core"> <!-- build NAnt.Console.Tests assembly --> <nant buildfile="tests/NAnt.Console/NAnt.Console.build" target="build" /> + </target> + + <target name="build.tests.ext" depends="build.ext"> <!-- build tests for extension assemblies --> <nant target="build"> <buildfiles refid="ext.core.tests"/> </nant> </target> + <target name="build" + depends="build.core,build.console,build.ext,build.msbuild,build.ndoc,build.tests.core,build.tests.console,build.tests.ext" + description="Builds current configuration"/> + <!-- test the newly built NAnt --> <target name="test" depends="build" description="Tests current configuration"> <echo message="Running unit tests with just built version of NAnt." /> -- 1.7.7 |
From: <nan...@na...> - 2014-12-21 17:10:23
|
From: Dmitry Kostenko <bis...@gm...> --- src/NAnt.Core/CommandLineOptions.cs | 7 ++ src/NAnt.Core/ConsoleDriver.cs | 3 + src/NAnt.Core/Project.cs | 132 +++++++++++++++++++--------------- 3 files changed, 84 insertions(+), 58 deletions(-) diff --git a/src/NAnt.Core/CommandLineOptions.cs b/src/NAnt.Core/CommandLineOptions.cs index 6516d0f..67d734c 100644 --- a/src/NAnt.Core/CommandLineOptions.cs +++ b/src/NAnt.Core/CommandLineOptions.cs @@ -297,6 +297,12 @@ namespace NAnt.Core { get { return _targets; } } + [CommandLineArgument(CommandLineArgumentTypes.AtMostOnce, Name = "jobs", ShortName = "j", Description = "Starts targets as parallel jobs")] + public bool UseJobs { + get { return _useJobs; } + set { _useJobs = value; } + } + #endregion Public Instance Properties #region Private Instance Fields @@ -319,6 +325,7 @@ namespace NAnt.Core { private StringCollection _targets = new StringCollection(); private bool _showProjectHelp; private bool _pause; + private bool _useJobs; #endregion Private Instance Fields } diff --git a/src/NAnt.Core/ConsoleDriver.cs b/src/NAnt.Core/ConsoleDriver.cs index 2d1a6d9..c06efa9 100755 --- a/src/NAnt.Core/ConsoleDriver.cs +++ b/src/NAnt.Core/ConsoleDriver.cs @@ -184,6 +184,9 @@ namespace NAnt.Core { } } + // Enable parallel execution of targets + project.RunTargetsInParallel = cmdlineOptions.UseJobs; + if (cmdlineOptions.ShowProjectHelp) { Console.WriteLine(); ConsoleDriver.ShowProjectHelp(project.Document); diff --git a/src/NAnt.Core/Project.cs b/src/NAnt.Core/Project.cs index 5ea0262..a03ed58 100644 --- a/src/NAnt.Core/Project.cs +++ b/src/NAnt.Core/Project.cs @@ -138,6 +138,7 @@ namespace NAnt.Core { private PropertyDictionary _properties; private PropertyDictionary _frameworkNeutralProperties; private Target _currentTarget; + private bool _runTargetsInParallel; // info about frameworks private FrameworkInfoDictionary _frameworks = new FrameworkInfoDictionary(); @@ -655,6 +656,19 @@ namespace NAnt.Core { } /// <summary> + /// Gets or sets a value indicating whether independent targets should be executed + /// in parallel execution threads. + /// </summary> + /// <value> + /// <see langword="true" /> if targets should be executed in parallel + /// otherwise, <see langword="false" />. + /// </value> + public bool RunTargetsInParallel { + get { return _runTargetsInParallel; } + set { _runTargetsInParallel = value; } + } + + /// <summary> /// The list of targets to build. /// </summary> /// <remarks> @@ -1005,80 +1019,82 @@ namespace NAnt.Core { /// Global tasks are not executed. /// </remarks> public void Execute(string targetName, bool forceDependencies) { -#if FALSE - // sort the dependency tree, and run everything from the - // beginning until we hit our targetName. - // - // sorting checks if all the targets (and dependencies) - // exist, and if there is any cycle in the dependency - // graph. - TargetCollection sortedTargets = TopologicalTargetSort(targetName, Targets); - int currentIndex = 0; - Target currentTarget; + bool singleThreaded = !RunTargetsInParallel; + if (singleThreaded) { + // sort the dependency tree, and run everything from the + // beginning until we hit our targetName. + // + // sorting checks if all the targets (and dependencies) + // exist, and if there is any cycle in the dependency + // graph. + TargetCollection sortedTargets = TopologicalTargetSort(targetName, Targets); + int currentIndex = 0; + Target currentTarget; - // store calling target - Target callingTarget = _currentTarget; - - do { - // determine target that should be executed - currentTarget = (Target) sortedTargets[currentIndex++]; + // store calling target + Target callingTarget = _currentTarget; - // store target that will be executed - _currentTarget = currentTarget; + do { + // determine target that should be executed + currentTarget = (Target) sortedTargets[currentIndex++]; - // only execute targets that have not been executed already, if - // we are not forcing. - if (forceDependencies || !currentTarget.Executed || currentTarget.Name == targetName) { - currentTarget.Execute(); - } - } while (currentTarget.Name != targetName); + // store target that will be executed + _currentTarget = currentTarget; - // restore calling target, as a <call> task might have caused the - // current target to be executed and when finished executing this - // target, the target that contained the <call> task should be - // considered the current target again - _currentTarget = callingTarget; -#else - // sorting checks if all the targets (and dependencies) - // exist, and if there is any cycle in the dependency - // graph. - TopologicalTargetSort (targetName, Targets); + // only execute targets that have not been executed already, if + // we are not forcing. + if (forceDependencies || !currentTarget.Executed || currentTarget.Name == targetName) { + currentTarget.Execute(); + } + } while (currentTarget.Name != targetName); - // Dictionary is faster than implementation in TargetCollection.Find - System.Collections.Generic.Dictionary<string, Target> targets = new System.Collections.Generic.Dictionary<string, Target>(); - foreach (Target target in Targets) { - targets [target.Name] = target; + // restore calling target, as a <call> task might have caused the + // current target to be executed and when finished executing this + // target, the target that contained the <call> task should be + // considered the current target again + _currentTarget = callingTarget; } + else { + // sorting checks if all the targets (and dependencies) + // exist, and if there is any cycle in the dependency + // graph. + TopologicalTargetSort (targetName, Targets); + + // Dictionary is faster than implementation in TargetCollection.Find + System.Collections.Generic.Dictionary<string, Target> targets = new System.Collections.Generic.Dictionary<string, Target>(); + foreach (Target target in Targets) { + targets [target.Name] = target; + } - // Use execution graph to run targets in parallel - using (ExecutionGraph graph = new ExecutionGraph()) { + // Use execution graph to run targets in parallel + using (ExecutionGraph graph = new ExecutionGraph()) { - PopulateExecutionGraph(targetName, Targets, graph); - graph.WalkThrough(delegate(string currentTargetName) { + PopulateExecutionGraph(targetName, Targets, graph); + graph.WalkThrough(delegate(string currentTargetName) { - Target currentTarget; - if (!targets.TryGetValue(currentTargetName, out currentTarget)) { - Target wildcardTarget = targets [WildTarget]; - currentTarget = wildcardTarget.Clone (); - currentTarget.Name = targetName; - } + Target currentTarget; + if (!targets.TryGetValue(currentTargetName, out currentTarget)) { + Target wildcardTarget = targets [WildTarget]; + currentTarget = wildcardTarget.Clone (); + currentTarget.Name = targetName; + } - Target savedTarget = _currentTarget; - _currentTarget = currentTarget; + Target savedTarget = _currentTarget; + _currentTarget = currentTarget; - try { - lock (currentTarget) { - if (forceDependencies || !currentTarget.Executed || currentTarget.Name == targetName) { - currentTarget.Execute (); + try { + lock (currentTarget) { + if (forceDependencies || !currentTarget.Executed || currentTarget.Name == targetName) { + currentTarget.Execute (); + } } + } finally { + _currentTarget = savedTarget; } - } finally { - _currentTarget = savedTarget; } + ); } - ); } -#endif } /// <summary> -- 1.7.7 |
From: <nan...@na...> - 2014-12-21 17:10:21
|
From: Dmitry Kostenko <cod...@gm...> --- src/NAnt.Core/Log.cs | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/src/NAnt.Core/Log.cs b/src/NAnt.Core/Log.cs index 3af121e..65aab67 100644 --- a/src/NAnt.Core/Log.cs +++ b/src/NAnt.Core/Log.cs @@ -685,7 +685,7 @@ namespace NAnt.Core { string label = String.Empty; if (e.Task != null && !EmacsMode) { - label = "[" + e.Task.Name + "] "; + label = "[" + (e.Target == null ? string.Empty : e.Target.Name + " ") + e.Task.Name + "] "; label = label.PadLeft(e.Project.IndentationSize); } -- 1.7.7 |
From: <nan...@na...> - 2014-12-21 17:10:21
|
From: Ryan Boggs <rm...@gm...> --- src/NAnt.Core/Types/FileSet.cs | 10 ++++++++++ 1 files changed, 10 insertions(+), 0 deletions(-) diff --git a/src/NAnt.Core/Types/FileSet.cs b/src/NAnt.Core/Types/FileSet.cs index b91f90e..f0ef177 100644 --- a/src/NAnt.Core/Types/FileSet.cs +++ b/src/NAnt.Core/Types/FileSet.cs @@ -124,6 +124,11 @@ namespace NAnt.Core.Types { /// <item><description>**/CVS</description></item> /// <item><description>**/CVS/**</description></item> /// <item><description>**/.cvsignore</description></item> + /// <item><description>**/._*</description></item> + /// <item><description>**/.bzr</description></item> + /// <item><description>**/.bzr/**</description></item> + /// <item><description>**/.bzr* (eg. .bzrignore)</description></item> + /// <item><description>**/.DS_Store</description></item> /// </list> /// <para> /// If you do not want these default excludes applied, you may disable them @@ -651,6 +656,11 @@ namespace NAnt.Core.Types { Excludes.Add("**/CVS"); Excludes.Add("**/CVS/**"); Excludes.Add("**/.cvsignore"); + Excludes.Add("**/._*"); + Excludes.Add("**/.bzr"); + Excludes.Add("**/.bzr/**"); + Excludes.Add("**/.bzr*"); + Excludes.Add("**/.DS_Store"); } } -- 1.7.7 |
From: <nan...@na...> - 2014-12-21 17:10:21
|
From: Bartosz Szczesny <bs...@bs...> --- src/NAnt.NUnit/NUnit2/NUnit2Task.cs | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/src/NAnt.NUnit/NUnit2/NUnit2Task.cs b/src/NAnt.NUnit/NUnit2/NUnit2Task.cs index 817d8e6..ccb53ca 100644 --- a/src/NAnt.NUnit/NUnit2/NUnit2Task.cs +++ b/src/NAnt.NUnit/NUnit2/NUnit2Task.cs @@ -307,7 +307,7 @@ namespace NAnt.NUnit2.Tasks { Version nunitVersion = typeof(TestResult).Assembly.GetName().Version; throw new BuildException(string.Format(CultureInfo.InvariantCulture, - "Failure executing test(s). If you assembly is not built using" + "Failure executing test(s). If your assembly is not built using" + " NUnit version {0}, then ensure you have redirected assembly" + " bindings. Consult the documentation of the <nunit2> task" + " for more information.", nunitVersion), Location, ex); -- 1.7.7 |
From: <nan...@na...> - 2014-12-21 17:10:20
|
From: Ryan Boggs <rm...@gm...> --- src/NAnt.Core/Util/FileUtils.cs | 6 ++---- 1 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/NAnt.Core/Util/FileUtils.cs b/src/NAnt.Core/Util/FileUtils.cs index afc404a..656750e 100644 --- a/src/NAnt.Core/Util/FileUtils.cs +++ b/src/NAnt.Core/Util/FileUtils.cs @@ -30,10 +30,8 @@ namespace NAnt.Core.Util { /// Provides modified version for Copy and Move from the File class that /// allow for filter chain processing. /// </summary> - public sealed class FileUtils { - private FileUtils() { - } - + public static class FileUtils + { #region Public Static Methods /// <summary> -- 1.7.7 |
From: <nan...@na...> - 2014-12-21 17:10:20
|
From: Ryan Boggs <rm...@gm...> --- src/NAnt.Core/Tasks/CopyTask.cs | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/src/NAnt.Core/Tasks/CopyTask.cs b/src/NAnt.Core/Tasks/CopyTask.cs index ed891c9..dd50c81 100644 --- a/src/NAnt.Core/Tasks/CopyTask.cs +++ b/src/NAnt.Core/Tasks/CopyTask.cs @@ -577,7 +577,7 @@ namespace NAnt.Core.Tasks { } } - // do all the actual co:py operations now + // do all the actual copy operations now DoFileOperations(); } -- 1.7.7 |
From: <nan...@na...> - 2014-12-21 17:10:20
|
From: Dmitry Kostenko <bis...@gm...> --- Makefile.nmake | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Makefile.nmake b/Makefile.nmake index aeeeef2..dc7b363 100644 --- a/Makefile.nmake +++ b/Makefile.nmake @@ -26,7 +26,7 @@ NANT_DEBUG = -debug+ !endif TARGET_FRAMEWORK = -t:$(TARGET) -NANT = $(MONO) bootstrap\NAnt.exe $(NANT_DEBUG) +NANT = $(MONO) bootstrap\NAnt.exe -j $(NANT_DEBUG) all: bootstrap build-nant -- 1.7.7 |
From: <nan...@na...> - 2014-12-21 17:10:20
|
From: Dmitry Kostenko <bis...@gm...> --- src/NAnt.Core/ExecutionGraph.cs | 208 +++++++++++++++++++++++++++++++++++++++ src/NAnt.Core/ExecutionNode.cs | 122 +++++++++++++++++++++++ src/NAnt.Core/NAnt.Core.csproj | 4 +- src/NAnt.Core/Project.cs | 66 ++++++++++++ 4 files changed, 399 insertions(+), 1 deletions(-) create mode 100644 src/NAnt.Core/ExecutionGraph.cs create mode 100644 src/NAnt.Core/ExecutionNode.cs diff --git a/src/NAnt.Core/ExecutionGraph.cs b/src/NAnt.Core/ExecutionGraph.cs new file mode 100644 index 0000000..e03c549 --- /dev/null +++ b/src/NAnt.Core/ExecutionGraph.cs @@ -0,0 +1,208 @@ +// NAnt - A .NET build tool +// Copyright (C) 2013 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 +// +// Dmitry Kostenko (cod...@gm...) + +using System; +using System.Collections.Generic; +using System.Collections; +using System.Threading; + +namespace NAnt.Core { + + /// <summary> + /// Represents the graph of execution of the project targets. + /// </summary> + internal class ExecutionGraph : IDisposable { + /// <summary> + /// The dictionary of graph's nodes, by name. + /// </summary> + private Dictionary<string, ExecutionNode> _nodes = new Dictionary<string, ExecutionNode>(); + + /// <summary> + /// The list of "leaves", i.e. nodes without any prerequisites. + /// </summary> + private List<ExecutionNode> _leaves = new List<ExecutionNode>(); + + /// <summary> + /// The number of currently active nodes (tasks being scheduled). + /// </summary> + private int _activeNodes = 0; + + /// <summary> + /// The collection of exceptions that occured during execution. + /// </summary> + private List<Exception> _exceptions = new List<Exception>(); + + /// <summary> + /// An event object that is raised when the run is finished (the last task has been executed, and there are no more tasks to be scheduled). + /// </summary> + private AutoResetEvent _finished = new AutoResetEvent(false); + + /// <summary> + /// The action to execute for each node in the graph (e.g. execute the project's target). + /// </summary> + private Action<string> _visitor; + + + /// <summary> + /// Initializes a new instance of the <see cref="NAnt.Core.ExecutionGraph"/> class. + /// </summary> + public ExecutionGraph() { + this._visitor = this.VisitNode; + } + + /// <summary> + /// Releases all resource used by the <see cref="NAnt.Core.ExecutionGraph"/> object. + /// </summary> + /// <remarks> + /// Call <see cref="Dispose"/> when you are finished using the <see cref="NAnt.Core.ExecutionGraph"/>. The + /// <see cref="Dispose"/> method leaves the <see cref="NAnt.Core.ExecutionGraph"/> in an unusable state. After + /// calling <see cref="Dispose"/>, you must release all references to the <see cref="NAnt.Core.ExecutionGraph"/> + /// so the garbage collector can reclaim the memory that the <see cref="NAnt.Core.ExecutionGraph"/> was occupying. + /// </remarks> + public void Dispose() { + this._finished.Close(); + } + + /// <summary> + /// Schedules a node for execution in the thread pool. + /// </summary> + /// <param name='node'>Node of the graph to put into execution.</param> + private void ScheduleForExecution(ExecutionNode node) { + Interlocked.Increment(ref _activeNodes); + + StartTask(() => { + try { + this.VisitNode(node.Name); + + foreach (var dependantNode in node.DependantNodes) { + if (dependantNode.ResolvePrerequisite()) { + this.ScheduleForExecution(dependantNode); + } + } + } + catch (Exception e) { + lock (this._exceptions) { + this._exceptions.Add(e); + } + } + + if (Interlocked.Decrement(ref _activeNodes) == 0) { + this._finished.Set(); + } + }); + } + + /// <summary> + /// Executes actions associated with visiting a node. + /// </summary> + /// <param name='nodeName'> + /// Name of the node that is being visited. + /// </param> + private void VisitNode(string nodeName) { + if (this._visitor == null) { + throw new ArgumentNullException("visitor"); + } + + this._visitor(nodeName); + } + + /// <summary> + /// Starts a new asynchronous task for the specified action. + /// </summary> + /// <param name='action'> + /// Action to be executed in the task. + /// </param> + private void StartTask(Action action) { + ThreadPool.QueueUserWorkItem(delegate { action(); }); + } + + /// <summary> + /// Gets the node with the given name. Creates a new node, if there is no node with the given name in the graph. + /// </summary> + /// <returns> + /// An instance of <see cref="ExecutionNode"/> class. + /// </returns> + /// <param name='name'> + /// Name of the node to return. + /// </param> + public ExecutionNode GetNode(string name) { + ExecutionNode result; + + if (this._nodes.TryGetValue(name, out result)) { + return result; + } + + result = new ExecutionNode(name); + this._nodes[name] = result; + + return result; + } + + /// <summary> + /// Registers a node as a leaf node (no prerequisites). + /// </summary> + /// <param name='node'>Node to be registered as a leaf.</param> + public void RegisterLeafNode(ExecutionNode node) { + if (!this._leaves.Contains(node)) { + this._leaves.Add(node); + } + } + + /// <summary> + /// Walks through the graph executing provided action for each node in the graph in dependency order. + /// </summary> + /// <param name='visitor'>An action to be executed for each node in the graph.</param> + public void WalkThrough(Action<string> visitor) { + this._visitor = visitor; + Run(); + } + + /// <summary> + /// Initiates execution of the tree and waits for completion. + /// </summary> + private void Run () { + foreach (var node in this._nodes.Values) { + node.PrepareForRun (); + } + + if (this._leaves.Count == 0) { + return; + } + + Interlocked.Increment (ref _activeNodes); + + foreach (var node in this._leaves) { + this.ScheduleForExecution (node); + } + + if (Interlocked.Decrement (ref _activeNodes) > 0) { + this._finished.WaitOne (); + } + + if (this._exceptions.Count > 0) { + Exception firstException = this._exceptions[0]; + Location location = Location.UnknownLocation; + if (firstException is BuildException) { + location = (firstException as BuildException).Location; + } + throw new BuildException("At least one of the tasks has failed: " + firstException.Message, location, firstException); + } + } + } +} diff --git a/src/NAnt.Core/ExecutionNode.cs b/src/NAnt.Core/ExecutionNode.cs new file mode 100644 index 0000000..b0b5182 --- /dev/null +++ b/src/NAnt.Core/ExecutionNode.cs @@ -0,0 +1,122 @@ +// NAnt - A .NET build tool +// Copyright (C) 2013 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 +// +// Dmitry Kostenko (cod...@gm...) + +using System; +using System.Collections.Generic; +using System.Collections; +using System.Threading; + +namespace NAnt.Core { + + /// <summary> + /// Respresents a single node in the execution graph. A node typically corresponds to a target in the project. + /// </summary> + internal class ExecutionNode { + + /// <summary> + /// Name of the node. + /// </summary> + private string _name; + + /// <summary> + /// Total number of prerequisistes of the node. + /// </summary> + private int _prerequisitesCount; + + /// <summary> + /// Number of prerequisites resolved in the current run. + /// </summary> + private int _prerequisitesResolved; + + /// <summary> + /// The list of dependant nodes. + /// </summary> + private List<ExecutionNode> _dependantNodes = new List<ExecutionNode>(); + + /// <summary> + /// Name of the node. + /// </summary> + public string Name { + get { + return _name; + } + } + + /// <summary> + /// The list of dependant nodes. + /// </summary> + public IEnumerable<ExecutionNode> DependantNodes { + get { + return _dependantNodes; + } + } + + /// <summary> + /// Total number of prerequisistes of the node. + /// </summary> + public int PrerequisitesCount { + get { + return _prerequisitesCount; + } + } + + /// <summary> + /// Initializes a new instance of the <see cref="NAnt.Core.ExecutionNode"/> class. + /// </summary> + /// <param name='name'> + /// Name of the node. + /// </param> + public ExecutionNode(string name) { + _name = name; + } + + /// <summary> + /// Registers that the node has a prerequisite. + /// </summary> + public void AddPrerequisite() { + Interlocked.Increment(ref _prerequisitesCount); + } + + /// <summary> + /// Registers that the node's prerequisite has been resolved. + /// </summary> + /// <returns> + /// <c>true</c> if all registered prerequisites are known to be resolved, <c>false</c> otherwise. + /// </returns> + public bool ResolvePrerequisite() { + return Interlocked.Increment(ref _prerequisitesResolved) == _prerequisitesCount; + } + + /// <summary> + /// Prepares the node for execution run, resetting its state to initial "before run" state. + /// </summary> + public void PrepareForRun() { + _prerequisitesResolved = 0; + } + + /// <summary> + /// Registers a dependant node for the current node. Implicitly registers current node as prerequisite for the dependant node. + /// </summary> + /// <param name='node'>Reference to the dependant node to connect with the current node.</param> + public void RegisterDependantNode(ExecutionNode node) { + _dependantNodes.Add(node); + node.AddPrerequisite(); + } + } +} diff --git a/src/NAnt.Core/NAnt.Core.csproj b/src/NAnt.Core/NAnt.Core.csproj index 1224840..eb12e93 100644 --- a/src/NAnt.Core/NAnt.Core.csproj +++ b/src/NAnt.Core/NAnt.Core.csproj @@ -92,6 +92,7 @@ <None Include="NAnt.Core.build" /> <Compile Include="PathScanner.cs" /> <Compile Include="PlatformHelper.cs" /> + <Compile Include="ExecutionGraph.cs" /> <Compile Include="Project.cs" /> <Compile Include="ProjectSettingsLoader.cs" /> <Compile Include="PropertyDictionary.cs" /> @@ -246,6 +247,7 @@ <Compile Include="Tasks\ChooseTask.cs" /> <Compile Include="Tasks\TryCatchTask.cs" /> <Compile Include="ElementContainer.cs" /> + <Compile Include="ExecutionNode.cs" /> </ItemGroup> <ItemGroup> <BootstrapperPackage Include="Microsoft.Net.Client.3.5"> @@ -266,4 +268,4 @@ </ItemGroup> <ItemGroup /> <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.Targets" /> -</Project> \ No newline at end of file +</Project> diff --git a/src/NAnt.Core/Project.cs b/src/NAnt.Core/Project.cs index 6bf31e1..5ea0262 100644 --- a/src/NAnt.Core/Project.cs +++ b/src/NAnt.Core/Project.cs @@ -1005,6 +1005,7 @@ namespace NAnt.Core { /// Global tasks are not executed. /// </remarks> public void Execute(string targetName, bool forceDependencies) { +#if FALSE // sort the dependency tree, and run everything from the // beginning until we hit our targetName. // @@ -1037,6 +1038,47 @@ namespace NAnt.Core { // target, the target that contained the <call> task should be // considered the current target again _currentTarget = callingTarget; +#else + // sorting checks if all the targets (and dependencies) + // exist, and if there is any cycle in the dependency + // graph. + TopologicalTargetSort (targetName, Targets); + + // Dictionary is faster than implementation in TargetCollection.Find + System.Collections.Generic.Dictionary<string, Target> targets = new System.Collections.Generic.Dictionary<string, Target>(); + foreach (Target target in Targets) { + targets [target.Name] = target; + } + + // Use execution graph to run targets in parallel + using (ExecutionGraph graph = new ExecutionGraph()) { + + PopulateExecutionGraph(targetName, Targets, graph); + graph.WalkThrough(delegate(string currentTargetName) { + + Target currentTarget; + if (!targets.TryGetValue(currentTargetName, out currentTarget)) { + Target wildcardTarget = targets [WildTarget]; + currentTarget = wildcardTarget.Clone (); + currentTarget.Name = targetName; + } + + Target savedTarget = _currentTarget; + _currentTarget = currentTarget; + + try { + lock (currentTarget) { + if (forceDependencies || !currentTarget.Executed || currentTarget.Name == targetName) { + currentTarget.Execute (); + } + } + } finally { + _currentTarget = savedTarget; + } + } + ); + } +#endif } /// <summary> @@ -1717,6 +1759,30 @@ namespace NAnt.Core { executeTargets.Add(target); } + private void PopulateExecutionGraph (string root, TargetCollection targets, ExecutionGraph graph) + { + Target target = targets.Find(root); + + ExecutionNode node = graph.GetNode(root); + + if (target == null) { + target = targets.Find(WildTarget); + } + + bool noDependencies = true; + foreach (string dependencyName in target.Dependencies) { + PopulateExecutionGraph(dependencyName, targets, graph); + + ExecutionNode dependencyNode = graph.GetNode(dependencyName); + dependencyNode.RegisterDependantNode(node); + noDependencies = false; + } + + if (noDependencies) { + graph.RegisterLeafNode(node); + } + } + /// <summary> /// Builds an appropriate exception detailing a specified circular /// dependency. -- 1.7.7 |
From: <nan...@na...> - 2014-12-21 17:10:20
|
From: Dmitry Kostenko <bis...@gm...> --- tests/NAnt.Core/ConcurrencyTest.cs | 74 ++++++++++++++++++++++++++++++++++ tests/NAnt.Core/TestBuildListener.cs | 25 +++++++++++- tests/NAnt.Tests.csproj | 3 +- 3 files changed, 100 insertions(+), 2 deletions(-) create mode 100644 tests/NAnt.Core/ConcurrencyTest.cs diff --git a/tests/NAnt.Core/ConcurrencyTest.cs b/tests/NAnt.Core/ConcurrencyTest.cs new file mode 100644 index 0000000..bb31fb0 --- /dev/null +++ b/tests/NAnt.Core/ConcurrencyTest.cs @@ -0,0 +1,74 @@ +// NAnt - A .NET build tool +// Copyright (C) 2001-2003 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 +// +// Gerry Shaw (ger...@ya...) +// Gert Driesen (dri...@us...) +// Dmitry Kostenko (cod...@gm...) + +using System; +using System.Globalization; + +using NUnit.Framework; + +using NAnt.Core; + +namespace Tests.NAnt.Core { + [TestFixture] + public class ConcurrencyTest : BuildTestBase { + #region Private Static Fields + + private const string TwoConcurrentTargets = @" + <project default='Target1'> + <target name='Target1' depends='Target2 Target3' /> + <target name='Target2'> + <sleep seconds='1' /> + </target> + <target name='Target3'> + <sleep seconds='1' /> + </target> + </project>"; + + #endregion Private Static Fields + + #region Public Instance Methods + + [Test] + public void Test_Concurrency() { + // create new listener that allows us to track build events + TestBuildListener listener = new TestBuildListener(); + + // run the build + Project project = CreateFilebasedProject(TwoConcurrentTargets, Level.Info); + project.RunTargetsInParallel = true; + + + //use Project.AttachBuildListeners to attach. + IBuildListener[] listeners = {listener}; + project.AttachBuildListeners(new BuildListenerCollection(listeners)); + + // execute the project + ExecuteProject(project); + + DateTime target2finishTime = listener.GetTargetFinishTime("Target2"); + DateTime target3startTime = listener.GetTargetStartTime("Target3"); + + Assert.IsTrue(target3startTime < target2finishTime, "Target3 was not started until Target2 was finished"); + } + + #endregion Public Instance Methods + } +} diff --git a/tests/NAnt.Core/TestBuildListener.cs b/tests/NAnt.Core/TestBuildListener.cs index 6f28e3c..e0b9b93 100644 --- a/tests/NAnt.Core/TestBuildListener.cs +++ b/tests/NAnt.Core/TestBuildListener.cs @@ -17,6 +17,7 @@ // // Gert Driesen (dri...@us...) +using System; using System.Collections; using NAnt.Core; @@ -28,6 +29,8 @@ namespace Tests.NAnt.Core { public TestBuildListener() { _executedTargets = new Hashtable(); _executedTasks = new Hashtable(); + _targetStartTimes = new Hashtable(); + _targetFinishTimes = new Hashtable(); _loggedMessages = new ArrayList(); } @@ -52,11 +55,13 @@ namespace Tests.NAnt.Core { } else { _executedTargets.Add(e.Target.Name, 1); } + _targetStartTimes[e.Target.Name] = DateTime.UtcNow; } } public void TargetFinished(object sender, BuildEventArgs e) { _targetFinishedFired = true; + _targetFinishTimes[e.Target.Name] = DateTime.UtcNow; } public void MessageLogged(object sender, BuildEventArgs e) { @@ -91,6 +96,22 @@ namespace Tests.NAnt.Core { } } + public DateTime GetTargetStartTime(string target) { + if (_targetStartTimes.ContainsKey(target)) { + return (DateTime) _targetStartTimes[target]; + } else { + return DateTime.MinValue; + } + } + + public DateTime GetTargetFinishTime(string target) { + if (_targetFinishTimes.ContainsKey(target)) { + return (DateTime) _targetFinishTimes[target]; + } else { + return DateTime.MinValue; + } + } + public int GetTaskExecutionCount(string task) { if (_executedTasks.ContainsKey(task)) { return (int) _executedTasks[task]; @@ -159,6 +180,8 @@ namespace Tests.NAnt.Core { private Hashtable _executedTargets; private Hashtable _executedTasks; + private Hashtable _targetStartTimes; + private Hashtable _targetFinishTimes; private ArrayList _loggedMessages; private bool _buildStartedFired; private bool _buildFinishedFired; @@ -169,4 +192,4 @@ namespace Tests.NAnt.Core { #endregion Private Instance Fields } -} \ No newline at end of file +} diff --git a/tests/NAnt.Tests.csproj b/tests/NAnt.Tests.csproj index a729e4b..da29c4f 100644 --- a/tests/NAnt.Tests.csproj +++ b/tests/NAnt.Tests.csproj @@ -73,6 +73,7 @@ <Compile Include="NAnt.Console\NAntTest.cs" /> <Compile Include="NAnt.Core\BuildFilesInResourcesTest.cs" /> <Compile Include="NAnt.Core\BuildTestBase.cs" /> + <Compile Include="NAnt.Core\ConcurrencyTest.cs" /> <Compile Include="NAnt.Core\DirectoryScannerTest.cs" /> <Compile Include="NAnt.Core\ElementTest.cs" /> <Compile Include="NAnt.Core\ExceptionTest.cs" /> @@ -217,4 +218,4 @@ <Name>NAnt.VisualCpp</Name> </ProjectReference> </ItemGroup> -</Project> \ No newline at end of file +</Project> -- 1.7.7 |
From: <nan...@na...> - 2014-12-21 17:10:19
|
From: Ryan Boggs <rm...@gm...> --- src/NAnt.Core/Tasks/CopyTask.cs | 69 ++++++++++++++++++++++++++++++++------ src/NAnt.Core/Tasks/MoveTask.cs | 14 ++++++-- 2 files changed, 69 insertions(+), 14 deletions(-) diff --git a/src/NAnt.Core/Tasks/CopyTask.cs b/src/NAnt.Core/Tasks/CopyTask.cs index a000186..4de6396 100644 --- a/src/NAnt.Core/Tasks/CopyTask.cs +++ b/src/NAnt.Core/Tasks/CopyTask.cs @@ -146,6 +146,8 @@ namespace NAnt.Core.Tasks { private FilterChain _filters; private Encoding _inputEncoding; private Encoding _outputEncoding; + private long _fileCount = 0; + private long _dirCount = 0; #endregion Private Instance Fields @@ -289,6 +291,23 @@ namespace NAnt.Core.Tasks { get { return _fileCopyMap; } } + /// <summary> + /// Gets the number of files that will be affected during the file operation. + /// </summary> + protected long FileCount + { + get { return _fileCount; } + } + + /// <summary> + /// Gets the number of directories that will be affected during the file + /// operation. + /// </summary> + protected long DirectoryCount + { + get { return _dirCount; } + } + #endregion Protected Instance Properties #region Override implementation of Task @@ -369,6 +388,7 @@ namespace NAnt.Core.Tasks { { // add to a copy map of absolute verified paths FileCopyMap.Add(dstInfo.FullName, new FileDateInfo(SourceFile.FullName, SourceFile.LastWriteTime)); + _fileCount++; if (dstInfo.Exists && dstInfo.Attributes != FileAttributes.Normal) { @@ -420,6 +440,7 @@ namespace NAnt.Core.Tasks { Location); } FileCopyMap.Add(destDirName, new FileDateInfo(sourceDirName, SourceFile.LastWriteTime, true)); + _dirCount++; } else { @@ -456,6 +477,7 @@ namespace NAnt.Core.Tasks { { FileCopyMap.Add(ToDirectory.FullName, new FileDateInfo(srcBaseInfo.FullName, srcBaseInfo.LastWriteTime, true)); + _dirCount++; } else { @@ -512,6 +534,8 @@ namespace NAnt.Core.Tasks { } } else { FileCopyMap.Add(dstInfo.FullName, newFile); + _fileCount++; + if (dstInfo.Exists && dstInfo.Attributes != FileAttributes.Normal) { File.SetAttributes(dstInfo.FullName, FileAttributes.Normal); } @@ -563,17 +587,37 @@ namespace NAnt.Core.Tasks { /// <summary> /// Actually does the file copies. /// </summary> - protected virtual void DoFileOperations() { - int fileCount = FileCopyMap.Count; + protected virtual void DoFileOperations() + { + FileSystemInfo fileTarget; string destinationFile; string destinationDirectory; string sourceFile; bool isDir; - if (fileCount > 0 || Verbose) { - if (ToFile != null) { - Log(Level.Info, "Copying {0} file{1} to '{2}'.", fileCount, (fileCount != 1) ? "s" : "", ToFile); - } else { - Log(Level.Info, "Copying {0} file{1} to '{2}'.", fileCount, (fileCount != 1) ? "s" : "", ToDirectory); + StringComparison strCmp = CopyFileSet.CaseSensitive ? + StringComparison.InvariantCulture : + StringComparison.InvariantCultureIgnoreCase; + + if (FileCount > 0 || DirectoryCount > 0 || Verbose) + { + if (FileCount > 0) + { + if (ToFile != null) + { + fileTarget = ToFile; + } + else + { + fileTarget = ToDirectory; + } + Log(Level.Info, "Copying {0} File{1} to '{2}'.", + FileCount, (FileCount > 1) ? "s" : "", fileTarget); + } + + if (DirectoryCount > 0) + { + Log(Level.Info, "Copying {0} Director{1}.", + DirectoryCount, (DirectoryCount > 1) ? "ies" : "y"); } // loop thru our file list @@ -582,20 +626,23 @@ namespace NAnt.Core.Tasks { sourceFile = ((FileDateInfo) fileEntry.Value).Path; isDir = ((FileDateInfo) fileEntry.Value).IsDirectory; - if (sourceFile == destinationFile) { + if (sourceFile.Equals(destinationFile, StringComparison.InvariantCulture)) + { Log(Level.Verbose, "Skipping self-copy of '{0}'.", sourceFile); continue; } - try { - Log(Level.Verbose, "Copying '{0}' to '{1}'.", sourceFile, destinationFile); - + try + { if (isDir) { + Log(Level.Verbose, "Copying directory '{0}' to '{1}'", + sourceFile, destinationFile); FileUtils.CopyDirectory(sourceFile, destinationFile); } else { + Log(Level.Verbose, "Copying '{0}' to '{1}'.", sourceFile, destinationFile); // create directory if not present destinationDirectory = Path.GetDirectoryName(destinationFile); if (!Directory.Exists(destinationDirectory)) { diff --git a/src/NAnt.Core/Tasks/MoveTask.cs b/src/NAnt.Core/Tasks/MoveTask.cs index cd3196c..47175d8 100644 --- a/src/NAnt.Core/Tasks/MoveTask.cs +++ b/src/NAnt.Core/Tasks/MoveTask.cs @@ -198,7 +198,8 @@ namespace NAnt.Core.Tasks { sourcePath = ((FileDateInfo) fileEntry.Value).Path; isDir = ((FileDateInfo) fileEntry.Value).IsDirectory; - if (sourcePath.Equals(destinationPath, StringComparison.InvariantCulture)) { + if (sourcePath.Equals(destinationPath, StringComparison.InvariantCulture)) + { Log(Level.Warning, "Skipping self-move of {0}." + sourcePath); continue; } @@ -206,7 +207,8 @@ namespace NAnt.Core.Tasks { try { // check if directory exists if (isDir) { - Log(Level.Verbose, "Moving directory '{0}' to '{1}'.", sourcePath, destinationPath); + Log(Level.Verbose, "Moving directory '{0}' to '{1}'.", + sourcePath, destinationPath); if (sourcePath.Equals(destinationPath, strCmp)) { @@ -246,7 +248,13 @@ namespace NAnt.Core.Tasks { Location, ex); } } - Log(Level.Info, "{0} files moved.", FileCopyMap.Count); + if (FileCount > 0) + Log(Level.Info, "{0} file{1} moved.", FileCount, + (FileCount > 1) ? "s" : ""); + + if (DirectoryCount > 0) + Log(Level.Info, "{0} director{1} moved.", DirectoryCount, + (DirectoryCount > 1) ? "ies" : "y"); } } -- 1.7.7 |
From: <nan...@na...> - 2014-12-21 17:10:19
|
From: Ryan Boggs <rm...@gm...> --- src/NAnt.Core/DirectoryScanner.cs | 38 ++++++++++++++++++++++++++++++------ 1 files changed, 31 insertions(+), 7 deletions(-) diff --git a/src/NAnt.Core/DirectoryScanner.cs b/src/NAnt.Core/DirectoryScanner.cs index 025d2cb..8232dc9 100644 --- a/src/NAnt.Core/DirectoryScanner.cs +++ b/src/NAnt.Core/DirectoryScanner.cs @@ -105,7 +105,8 @@ namespace NAnt.Core { // set to current directory in Scan if user doesn't specify something first. // keeping it null, lets the user detect if it's been set or not. private DirectoryInfo _baseDirectory; - + + // Holds every file and subdirectory information found in BaseDirectory. private List<FileSystemInfo> _baseDirFileSystem = new List<FileSystemInfo>(); // holds the nant patterns (absolute or relative paths) @@ -134,7 +135,8 @@ namespace NAnt.Core { // Indicates whether or not every file scanned was included private bool _isEverythingIncluded = true; - + + // Indicates whether or not the base directory contains empty subdirectories. private bool _hasEmptyDirectories = false; #endregion Private Instance Fields @@ -231,7 +233,13 @@ namespace NAnt.Core { clone._searchDirIsRecursive = (ArrayList) _searchDirIsRecursive.Clone(); } + if (_baseDirFileSystem != null) + clone._baseDirFileSystem = new List<FileSystemInfo>(_baseDirFileSystem); + clone._caseSensitive = _caseSensitive; + clone._isEverythingIncluded = _isEverythingIncluded; + clone._hasEmptyDirectories = _hasEmptyDirectories; + return clone; } @@ -438,7 +446,7 @@ namespace NAnt.Core { } // Wait for the directory scan to finish before checking if - // everything is included. + // everything is included and if there are any empty directories. getDirList.Join(); // Run both "Check" methods in parallel. @@ -466,7 +474,11 @@ namespace NAnt.Core { #region Private Instance Methods - private void Reset () { + private void Reset () + { + _isEverythingIncluded = true; + _hasEmptyDirectories = false; + _baseDirFileSystem.Clear(); _includePatterns = null; _includeNames = null; _excludePatterns = null; @@ -480,6 +492,9 @@ namespace NAnt.Core { _scannedDirectories = null; } + /// <summary> + /// Checks to see if <see cref="BaseDirectory"/> contains empty directories. + /// </summary> private void CheckHasEmptyDirectories() { if (_baseDirFileSystem == null) return; @@ -491,7 +506,9 @@ namespace NAnt.Core { if (!(fs is DirectoryInfo)) continue; tmp = fs as DirectoryInfo; - + + // If the current directory does not contain any files or directories, + // indicate that BaseDirectory has empty directories and exit loop. if (tmp.GetFiles().Length == 0 && tmp.GetDirectories().Length == 0) { _hasEmptyDirectories = true; @@ -499,7 +516,11 @@ namespace NAnt.Core { } } } - + + /// <summary> + /// Checks to see if all of the files/subdirectories in <see cref="BaseDirectory"/> + /// will be included in the calling task. + /// </summary> private void CheckIsEverythingIncluded() { if (_baseDirFileSystem == null) return; @@ -508,7 +529,10 @@ namespace NAnt.Core { string fsFullName; StringComparison strCmp = CaseSensitive ? StringComparison.InvariantCulture : StringComparison.InvariantCultureIgnoreCase; - + + // Loop through all of the files/subdirectories in BaseDirectory and make sure that + // the are both included in the appropriate include list and not included in the + // appropriate exclude list. foreach (FileSystemInfo fs in _baseDirFileSystem) { found = false; -- 1.7.7 |
From: <nan...@na...> - 2014-12-21 17:10:19
|
From: Dmitry Kostenko <bis...@gm...> --- src/NAnt.Core/ExecutionGraph.cs | 12 ++++++------ 1 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/NAnt.Core/ExecutionGraph.cs b/src/NAnt.Core/ExecutionGraph.cs index e03c549..2ac683c 100644 --- a/src/NAnt.Core/ExecutionGraph.cs +++ b/src/NAnt.Core/ExecutionGraph.cs @@ -86,11 +86,11 @@ namespace NAnt.Core { private void ScheduleForExecution(ExecutionNode node) { Interlocked.Increment(ref _activeNodes); - StartTask(() => { + StartTask(delegate { try { this.VisitNode(node.Name); - foreach (var dependantNode in node.DependantNodes) { + foreach (ExecutionNode dependantNode in node.DependantNodes) { if (dependantNode.ResolvePrerequisite()) { this.ScheduleForExecution(dependantNode); } @@ -128,8 +128,8 @@ namespace NAnt.Core { /// <param name='action'> /// Action to be executed in the task. /// </param> - private void StartTask(Action action) { - ThreadPool.QueueUserWorkItem(delegate { action(); }); + private void StartTask(WaitCallback action) { + ThreadPool.QueueUserWorkItem(action); } /// <summary> @@ -177,7 +177,7 @@ namespace NAnt.Core { /// Initiates execution of the tree and waits for completion. /// </summary> private void Run () { - foreach (var node in this._nodes.Values) { + foreach (ExecutionNode node in this._nodes.Values) { node.PrepareForRun (); } @@ -187,7 +187,7 @@ namespace NAnt.Core { Interlocked.Increment (ref _activeNodes); - foreach (var node in this._leaves) { + foreach (ExecutionNode node in this._leaves) { this.ScheduleForExecution (node); } -- 1.7.7 |
From: <nan...@na...> - 2014-12-21 17:10:19
|
From: Ryan Boggs <rm...@gm...> --- src/NAnt.Core/DirectoryScanner.cs | 137 +++++++++++++++++++++++++++++++++--- src/NAnt.Core/Tasks/CopyTask.cs | 36 ++++++---- src/NAnt.Core/Tasks/MoveTask.cs | 20 +++++- src/NAnt.Core/Types/FileSet.cs | 9 ++- 4 files changed, 173 insertions(+), 29 deletions(-) diff --git a/src/NAnt.Core/DirectoryScanner.cs b/src/NAnt.Core/DirectoryScanner.cs index 72a1807..a285fc5 100644 --- a/src/NAnt.Core/DirectoryScanner.cs +++ b/src/NAnt.Core/DirectoryScanner.cs @@ -48,13 +48,13 @@ foreach (string filename in GetIncludedFiles()) { using System; using System.Collections; +using System.Collections.Generic; using System.Collections.Specialized; using System.Globalization; using System.IO; using System.Text; using System.Text.RegularExpressions; - -using NAnt.Core.Util; +using System.Threading; namespace NAnt.Core { /// <summary> @@ -101,6 +101,8 @@ namespace NAnt.Core { // set to current directory in Scan if user doesn't specify something first. // keeping it null, lets the user detect if it's been set or not. private DirectoryInfo _baseDirectory; + + private List<FileSystemInfo> _baseDirFileSystem = new List<FileSystemInfo>(); // holds the nant patterns (absolute or relative paths) private StringCollectionWithGoodToString _includes = new StringCollectionWithGoodToString(); @@ -370,6 +372,12 @@ namespace NAnt.Core { /// <see cref="BaseDirectory" /> or absolute), to search for filesystem objects. /// </summary> public void Scan() { + Thread getDirList; + bool found; + string fsFullName; + StringComparison strCmp = CaseSensitive ? StringComparison.InvariantCulture + : StringComparison.InvariantCultureIgnoreCase; + _includePatterns = new ArrayList(); _includeNames = new StringCollectionWithGoodToString (); _excludePatterns = new ArrayList(); @@ -400,6 +408,14 @@ namespace NAnt.Core { Console.WriteLine("--- Starting Scan ---"); #endif + // Begin scanning the base directory file system + if (_baseDirFileSystem != null) _baseDirFileSystem.Clear(); + + // Gather all of the file system info objects in the background while + // scan is performing. Hoping this will save some time. + getDirList = new Thread(new ParameterizedThreadStart(GetAllFileSystemInfo)); + getDirList.IsBackground = true; + getDirList.Start(BaseDirectory); // convert given NAnt patterns to regex patterns with absolute paths // side effect: searchDirectories will be populated @@ -410,6 +426,81 @@ namespace NAnt.Core { ScanDirectory(_searchDirectories[index], (bool) _searchDirIsRecursive[index]); } + // Wait for the directory scan to finish before checking if + // everything is included. + getDirList.Join(); + + foreach (FileSystemInfo fs in _baseDirFileSystem) + { + found = false; + fsFullName = fs.FullName; + + if (fs is FileInfo) + { + if (_excludedFileNames.Count > 0) + { + foreach (string efName in _excludedFileNames) + { + if (fsFullName.Equals(efName, strCmp)) + { + _isEverythingIncluded = false; + break; + } + } + if (!_isEverythingIncluded) + break; + } + if (_fileNames.Count > 0) + { + foreach (string fName in _fileNames) + { + if (fsFullName.Equals(fName, strCmp)) + { + found = true; + break; + } + } + if (!found) + { + _isEverythingIncluded = false; + break; + } + } + } + else if (fs is DirectoryInfo) + { + if (_excludedDirectoryNames.Count > 0) + { + foreach (string edName in _excludedDirectoryNames) + { + if (fsFullName.Equals(edName, strCmp)) + { + _isEverythingIncluded = false; + break; + } + } + if (!_isEverythingIncluded) + break; + } + if (_directoryNames.Count > 0) + { + foreach (string dName in _directoryNames) + { + if (fsFullName.Equals(dName, strCmp)) + { + found = true; + break; + } + } + if (!found) + { + _isEverythingIncluded = false; + break; + } + } + } + } + #if DEBUG_REGEXES Console.WriteLine("*********************************************************************"); #endif @@ -694,7 +785,7 @@ namespace NAnt.Core { _excludedFileNames.Add(Path.Combine(path, filename)); } else if (IsPathIncluded(filename, includedPatterns)) { - _fileNames.Add(Path.Combine(path, fileInfo.Name)); + _fileNames.Add(filename); } } @@ -778,7 +869,6 @@ namespace NAnt.Core { #if DEBUG_REGEXES Console.WriteLine("Excluded by name: {0}", name); #endif - _isEverythingIncluded = false; return true; } } @@ -793,7 +883,6 @@ namespace NAnt.Core { #if DEBUG_REGEXES Console.WriteLine("Excluded by pattern: {0}", entry.Pattern); #endif - _isEverythingIncluded = false; return true; } } @@ -847,15 +936,39 @@ namespace NAnt.Core { #if DEBUG_REGEXES Console.WriteLine("Result: {0} not included", path); #endif - // If the current path is not the provided base directory at this point - // of the method, indicate that everything is not included. - if (compare.Compare(path, BaseDirectory.ToString(), compareOptions) != 0) - { - _isEverythingIncluded = false; - } return false; } + + private void GetAllFileSystemInfo(object dir) + { + DirectoryInfo rootDir; + + if (!(dir is DirectoryInfo)) + throw new ArgumentException( + String.Format("'dir' is not instance of DirectoryInfo: '{0}'", + dir.GetType().Name)); + + rootDir = dir as DirectoryInfo; + + if (_baseDirFileSystem == null) + _baseDirFileSystem = new List<FileSystemInfo>(); + + // If the rootDir parameter does not point to an existing directory + // on the underlying system, exit the method. + if (!rootDir.Exists) return; + + // Get the files located in rootDir + foreach (FileInfo f in rootDir.GetFiles()) _baseDirFileSystem.Add(f); + + // Retrieve all the subdirectory info + foreach (DirectoryInfo d in rootDir.GetDirectories()) + { + _baseDirFileSystem.Add(d); + GetAllFileSystemInfo(d); + } + } + #endregion Private Instance Methods #region Private Static Methods @@ -1049,7 +1162,7 @@ namespace NAnt.Core { /// </summary> /// <param name="value">The string to locate in the <see cref="DirScannerStringCollection" />. The value can be <see langword="null" />.</param> /// <returns> - /// <seee langword="true" /> if value is found in the <see cref="DirScannerStringCollection" />; otherwise, <see langword="false" />. + /// <see langword="true" /> if value is found in the <see cref="DirScannerStringCollection" />; otherwise, <see langword="false" />. /// </returns> /// <remarks> /// String comparisons within the <see cref="DirScannerStringCollection" /> diff --git a/src/NAnt.Core/Tasks/CopyTask.cs b/src/NAnt.Core/Tasks/CopyTask.cs index 02e000f..ec7ba8d 100644 --- a/src/NAnt.Core/Tasks/CopyTask.cs +++ b/src/NAnt.Core/Tasks/CopyTask.cs @@ -303,15 +303,15 @@ namespace NAnt.Core.Tasks { Location); } - if (ToDirectory == null && CopyFileSet != null && - (CopyFileSet.Includes.Count > 0 || CopyFileSet.IsEverythingIncluded)) { + if (ToDirectory == null && CopyFileSet != null && CopyFileSet.BaseDirectory != null) + { throw new BuildException(string.Format(CultureInfo.InvariantCulture, "The 'todir' should be set when using the <fileset> element" + " to specify the list of files to be copied."), Location); } - if (SourceFile != null && CopyFileSet != null && - (CopyFileSet.Includes.Count > 0 || CopyFileSet.IsEverythingIncluded)) { + if (SourceFile != null && CopyFileSet != null && CopyFileSet.BaseDirectory != null) + { throw new BuildException(string.Format(CultureInfo.InvariantCulture, "The 'file' attribute and the <fileset> element" + " cannot be combined."), Location); @@ -348,7 +348,7 @@ namespace NAnt.Core.Tasks { if (SourceFile != null) { // copy a single file. - if (SourceFile.Exists) + if (SourceFile.Exists) { FileInfo dstInfo = null; if (ToFile != null) @@ -428,25 +428,34 @@ namespace NAnt.Core.Tasks { } // copy file set contents. - else + else { // get the complete path of the base directory of the fileset, ie, c:\work\nant\src DirectoryInfo srcBaseInfo = CopyFileSet.BaseDirectory; // Check to see if the file operation is a straight pass through (ie: no file or // directory modifications) before proceeding. - bool completeDir = (CopyFileSet.FileNames.Count <= 0 || CopyFileSet.IsEverythingIncluded) && - !Flatten && IncludeEmptyDirs && FilterChain.IsNullOrEmpty(Filters) && - _inputEncoding == null && _outputEncoding == null && srcBaseInfo != null && - !String.IsNullOrEmpty(srcBaseInfo.FullName) && srcBaseInfo.Exists && - !ToDirectory.Exists; + bool completeDir = true; + + // completeDir criteria + bool[] dirCheck = new bool[8]; + dirCheck[0] = CopyFileSet.IsEverythingIncluded; + dirCheck[1] = !Flatten; + dirCheck[2] = IncludeEmptyDirs; + dirCheck[3] = FilterChain.IsNullOrEmpty(Filters); + dirCheck[4] = _inputEncoding == null; + dirCheck[5] = _outputEncoding == null; + dirCheck[6] = srcBaseInfo != null && srcBaseInfo.Exists; + dirCheck[7] = !ToDirectory.Exists || + srcBaseInfo.FullName.Equals(ToDirectory.FullName, + StringComparison.InvariantCultureIgnoreCase); + for (int b = 0; b < dirCheck.Length; b++) completeDir &= dirCheck[b]; + if (completeDir) { FileCopyMap.Add(ToDirectory.FullName, new FileDateInfo(srcBaseInfo.FullName, srcBaseInfo.LastWriteTime, true)); - Console.WriteLine("Complete Dir Entry added: '{0}' - '{1}'", ToDirectory.FullName, - FileCopyMap[ToDirectory.FullName].ToString()); } else { @@ -692,7 +701,6 @@ namespace NAnt.Core.Tasks { #endregion - #region Private Instance Fields private DateTime _lastWriteTime; diff --git a/src/NAnt.Core/Tasks/MoveTask.cs b/src/NAnt.Core/Tasks/MoveTask.cs index 7f2c8c8..cd3196c 100644 --- a/src/NAnt.Core/Tasks/MoveTask.cs +++ b/src/NAnt.Core/Tasks/MoveTask.cs @@ -187,6 +187,9 @@ namespace NAnt.Core.Tasks { string destinationPath; string sourcePath; bool isDir; + StringComparison strCmp = CopyFileSet.CaseSensitive ? + StringComparison.InvariantCulture : + StringComparison.InvariantCultureIgnoreCase; if (FileCopyMap.Count > 0) { // loop thru our file list @@ -195,7 +198,7 @@ namespace NAnt.Core.Tasks { sourcePath = ((FileDateInfo) fileEntry.Value).Path; isDir = ((FileDateInfo) fileEntry.Value).IsDirectory; - if (sourcePath == destinationPath) { + if (sourcePath.Equals(destinationPath, StringComparison.InvariantCulture)) { Log(Level.Warning, "Skipping self-move of {0}." + sourcePath); continue; } @@ -204,7 +207,20 @@ namespace NAnt.Core.Tasks { // check if directory exists if (isDir) { Log(Level.Verbose, "Moving directory '{0}' to '{1}'.", sourcePath, destinationPath); - Directory.Move(sourcePath, destinationPath); + + if (sourcePath.Equals(destinationPath, strCmp)) + { + string rootDir = !String.IsNullOrEmpty(Path.GetDirectoryName(destinationPath)) ? + Path.GetDirectoryName(destinationPath) : destinationPath; + string tmpDir = Path.Combine(rootDir, Path.GetRandomFileName()); + + Directory.Move(sourcePath, tmpDir); + Directory.Move(tmpDir, destinationPath); + } + else + { + Directory.Move(sourcePath, destinationPath); + } } else { DirectoryInfo todir = new DirectoryInfo(destinationPath); if (!todir.Exists) { diff --git a/src/NAnt.Core/Types/FileSet.cs b/src/NAnt.Core/Types/FileSet.cs index 38a3cf9..86a8dac 100644 --- a/src/NAnt.Core/Types/FileSet.cs +++ b/src/NAnt.Core/Types/FileSet.cs @@ -436,7 +436,14 @@ namespace NAnt.Core.Types { /// </summary> public bool IsEverythingIncluded { - get { return _scanner.IsEverythingIncluded && _hasScanned; } + get + { + if (!_hasScanned) + { + Scan(); + } + return _scanner.IsEverythingIncluded; + } } /// <summary> -- 1.7.7 |
From: <nan...@na...> - 2014-12-21 17:10:19
|
From: Ryan Boggs <rm...@gm...> --- src/NAnt.Core/Tasks/CopyTask.cs | 3 --- tests/NAnt.Core/Tasks/MoveTest.cs | 6 ++---- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/src/NAnt.Core/Tasks/CopyTask.cs b/src/NAnt.Core/Tasks/CopyTask.cs index 4de6396..af11cf7 100644 --- a/src/NAnt.Core/Tasks/CopyTask.cs +++ b/src/NAnt.Core/Tasks/CopyTask.cs @@ -594,9 +594,6 @@ namespace NAnt.Core.Tasks { string destinationDirectory; string sourceFile; bool isDir; - StringComparison strCmp = CopyFileSet.CaseSensitive ? - StringComparison.InvariantCulture : - StringComparison.InvariantCultureIgnoreCase; if (FileCount > 0 || DirectoryCount > 0 || Verbose) { diff --git a/tests/NAnt.Core/Tasks/MoveTest.cs b/tests/NAnt.Core/Tasks/MoveTest.cs index 9af6ac1..0613424 100644 --- a/tests/NAnt.Core/Tasks/MoveTest.cs +++ b/tests/NAnt.Core/Tasks/MoveTest.cs @@ -346,10 +346,8 @@ namespace Tests.NAnt.Core.Tasks { { string buildScript1 = String.Format(_xmlProjectTemplate5, _tempDirTargetOne, _tempDirSourceOne); string buildScript2 = String.Format(_xmlProjectTemplate5, _tempDirTargetThree, _tempDirSourceThree); - string emptySourceDirOne = CreateTempDir(Path.Combine(_tempDirSourceThree, "EmptyOne")); - string emptySourceDirTwo = CreateTempDir(Path.Combine(_tempDirSourceThree, "EmptyTwo")); - string emptyTargetDirOne = Path.Combine(_tempDirTargetThree, "EmptyOne"); - string emptyTargetDirTwo = Path.Combine(_tempDirTargetThree, "EmptyTwo"); + CreateTempDir(Path.Combine(_tempDirSourceThree, "EmptyOne")); + CreateTempDir(Path.Combine(_tempDirSourceThree, "EmptyTwo")); RunBuild(buildScript1); -- 1.7.7 |
From: <nan...@na...> - 2014-12-21 17:10:19
|
From: Ryan Boggs <rm...@gm...> --- src/NAnt.Core/DirectoryScanner.cs | 109 ++++++++++++++++++++++++++++--------- src/NAnt.Core/Tasks/CopyTask.cs | 2 +- src/NAnt.Core/Types/FileSet.cs | 15 +++++ tests/NAnt.Core/Tasks/MoveTest.cs | 52 ++++++++++++------ 4 files changed, 134 insertions(+), 44 deletions(-) diff --git a/src/NAnt.Core/DirectoryScanner.cs b/src/NAnt.Core/DirectoryScanner.cs index a285fc5..025d2cb 100644 --- a/src/NAnt.Core/DirectoryScanner.cs +++ b/src/NAnt.Core/DirectoryScanner.cs @@ -56,6 +56,10 @@ using System.Text; using System.Text.RegularExpressions; using System.Threading; +#if NET_4_0 +using System.Threading.Tasks; +#endif + namespace NAnt.Core { /// <summary> /// Used for searching filesystem based on given include/exclude rules. @@ -130,6 +134,8 @@ namespace NAnt.Core { // Indicates whether or not every file scanned was included private bool _isEverythingIncluded = true; + + private bool _hasEmptyDirectories = false; #endregion Private Instance Fields @@ -362,6 +368,15 @@ namespace NAnt.Core { { get { return _isEverythingIncluded; } } + + /// <summary> + /// Indicates whether or not <see cref="P:BaseDirectory"/> contains + /// any empty directories. + /// </summary> + public bool HasEmptyDirectories + { + get { return _hasEmptyDirectories; } + } #endregion Public Instance Properties @@ -373,10 +388,6 @@ namespace NAnt.Core { /// </summary> public void Scan() { Thread getDirList; - bool found; - string fsFullName; - StringComparison strCmp = CaseSensitive ? StringComparison.InvariantCulture - : StringComparison.InvariantCultureIgnoreCase; _includePatterns = new ArrayList(); _includeNames = new StringCollectionWithGoodToString (); @@ -430,6 +441,74 @@ namespace NAnt.Core { // everything is included. getDirList.Join(); + // Run both "Check" methods in parallel. +#if NET_4_0 + Parallel.Invoke(CheckHasEmptyDirectories, CheckIsEverythingIncluded); +#else + Thread[] lastTasks = new Thread[2]; + lastTasks[0] = new Thread(new ThreadStart(CheckHasEmptyDirectories)); + lastTasks[1] = new Thread(new ThreadStart(CheckIsEverythingIncluded)); + + foreach (Thread t in lastTasks) + { + t.IsBackground = true; + t.Start(); + } + foreach (Thread t in lastTasks) t.Join(); +#endif + +#if DEBUG_REGEXES + Console.WriteLine("*********************************************************************"); +#endif + } + + #endregion Public Instance Methods + + #region Private Instance Methods + + private void Reset () { + _includePatterns = null; + _includeNames = null; + _excludePatterns = null; + _excludeNames = null; + _fileNames = null; + _directoryNames = null; + _excludedFileNames = null; + _excludedDirectoryNames = null; + _searchDirectories = null; + _searchDirIsRecursive = null; + _scannedDirectories = null; + } + + private void CheckHasEmptyDirectories() + { + if (_baseDirFileSystem == null) return; + + DirectoryInfo tmp; + + foreach (FileSystemInfo fs in _baseDirFileSystem) + { + if (!(fs is DirectoryInfo)) continue; + + tmp = fs as DirectoryInfo; + + if (tmp.GetFiles().Length == 0 && tmp.GetDirectories().Length == 0) + { + _hasEmptyDirectories = true; + break; + } + } + } + + private void CheckIsEverythingIncluded() + { + if (_baseDirFileSystem == null) return; + + bool found; + string fsFullName; + StringComparison strCmp = CaseSensitive ? StringComparison.InvariantCulture + : StringComparison.InvariantCultureIgnoreCase; + foreach (FileSystemInfo fs in _baseDirFileSystem) { found = false; @@ -500,28 +579,6 @@ namespace NAnt.Core { } } } - -#if DEBUG_REGEXES - Console.WriteLine("*********************************************************************"); -#endif - } - - #endregion Public Instance Methods - - #region Private Instance Methods - - private void Reset () { - _includePatterns = null; - _includeNames = null; - _excludePatterns = null; - _excludeNames = null; - _fileNames = null; - _directoryNames = null; - _excludedFileNames = null; - _excludedDirectoryNames = null; - _searchDirectories = null; - _searchDirIsRecursive = null; - _scannedDirectories = null; } /// <summary> diff --git a/src/NAnt.Core/Tasks/CopyTask.cs b/src/NAnt.Core/Tasks/CopyTask.cs index ec7ba8d..a000186 100644 --- a/src/NAnt.Core/Tasks/CopyTask.cs +++ b/src/NAnt.Core/Tasks/CopyTask.cs @@ -441,7 +441,7 @@ namespace NAnt.Core.Tasks { bool[] dirCheck = new bool[8]; dirCheck[0] = CopyFileSet.IsEverythingIncluded; dirCheck[1] = !Flatten; - dirCheck[2] = IncludeEmptyDirs; + dirCheck[2] = IncludeEmptyDirs || !CopyFileSet.HasEmptyDirectories; dirCheck[3] = FilterChain.IsNullOrEmpty(Filters); dirCheck[4] = _inputEncoding == null; dirCheck[5] = _outputEncoding == null; diff --git a/src/NAnt.Core/Types/FileSet.cs b/src/NAnt.Core/Types/FileSet.cs index 86a8dac..0f4e261 100644 --- a/src/NAnt.Core/Types/FileSet.cs +++ b/src/NAnt.Core/Types/FileSet.cs @@ -445,6 +445,21 @@ namespace NAnt.Core.Types { return _scanner.IsEverythingIncluded; } } + + /// <summary> + /// Gets a value indicating whether this instance contains empty directories. + /// </summary> + public bool HasEmptyDirectories + { + get + { + if (!_hasScanned) + { + Scan(); + } + return _scanner.HasEmptyDirectories; + } + } /// <summary> /// The items to include in the fileset. diff --git a/tests/NAnt.Core/Tasks/MoveTest.cs b/tests/NAnt.Core/Tasks/MoveTest.cs index 1bb6f1e..9af6ac1 100644 --- a/tests/NAnt.Core/Tasks/MoveTest.cs +++ b/tests/NAnt.Core/Tasks/MoveTest.cs @@ -318,36 +318,54 @@ namespace Tests.NAnt.Core.Tasks { } } + private void PrintDirContents(DirectoryInfo dir) + { + if (!dir.Exists) return; + foreach (FileInfo f in dir.GetFiles()) + { + System.Console.WriteLine(f.FullName); + } + foreach (DirectoryInfo d in dir.GetDirectories()) + { + System.Console.WriteLine(d.FullName); + PrintDirContents(d); + } + } + /// <summary> /// Tests empty directory moves when includeemptydir property is false. /// </summary> - //[Test] + /// <remarks> + /// Copy tasks for directories with includeemptydir='false' should only + /// copy the entire directory structure if no empty directories are found + /// in the source directory tree. If empty directories are found, don't copy + /// the directory (since no include files were specified in the fileset element). + /// </remarks> + [Test] public void DoNotIncludeEmptyDirMoveTest() { - string emptySourceDirOne = CreateTempDir(Path.Combine(_tempDirSourceOne, "EmptyOne")); - string emptySourceDirTwo = CreateTempDir(Path.Combine(_tempDirSourceOne, "EmptyTwo")); - string emptyTargetDirOne = Path.Combine(_tempDirTargetOne, "EmptyOne"); - string emptyTargetDirTwo = Path.Combine(_tempDirTargetOne, "EmptyTwo"); + string buildScript1 = String.Format(_xmlProjectTemplate5, _tempDirTargetOne, _tempDirSourceOne); + string buildScript2 = String.Format(_xmlProjectTemplate5, _tempDirTargetThree, _tempDirSourceThree); + string emptySourceDirOne = CreateTempDir(Path.Combine(_tempDirSourceThree, "EmptyOne")); + string emptySourceDirTwo = CreateTempDir(Path.Combine(_tempDirSourceThree, "EmptyTwo")); + string emptyTargetDirOne = Path.Combine(_tempDirTargetThree, "EmptyOne"); + string emptyTargetDirTwo = Path.Combine(_tempDirTargetThree, "EmptyTwo"); - RunBuild(String.Format(_xmlProjectTemplate5, _tempDirTargetOne, _tempDirSourceOne)); + RunBuild(buildScript1); Assert.IsTrue(Directory.Exists(_tempDirTargetOne), string.Format("'{0}' target directory does not exist", _tempDirTargetOne)); - Assert.IsTrue(Directory.Exists(_tempDirSourceOne), - string.Format("'{0}' source directory does not exist", _tempDirSourceOne)); - - Assert.IsTrue(Directory.Exists(emptySourceDirOne), - string.Format("'{0}' empty directory does not exist", emptySourceDirOne)); + Assert.IsFalse(Directory.Exists(_tempDirSourceOne), + string.Format("'{0}' source directory does exist", _tempDirSourceOne)); - Assert.IsTrue(Directory.Exists(emptySourceDirTwo), - string.Format("'{0}' empty directory does not exist", emptySourceDirTwo)); + RunBuild(buildScript2); - Assert.IsFalse(Directory.Exists(emptyTargetDirOne), - string.Format("'{0}' empty directory does exist", emptyTargetDirOne)); + Assert.IsTrue(Directory.Exists(_tempDirSourceThree), + string.Format("'{0}' target directory does not exist", _tempDirSourceThree)); - Assert.IsFalse(Directory.Exists(emptyTargetDirTwo), - string.Format("'{0}' empty directory does exist", emptyTargetDirTwo)); + Assert.IsFalse(Directory.Exists(_tempDirTargetThree), + string.Format("'{0}' source directory does exist", _tempDirTargetThree)); } /// <summary> -- 1.7.7 |
From: Ryan Boggs <rm...@gm...> --- src/CommonAssemblyInfo.cs | 10 +- src/NAnt.Core/DirectoryScanner.cs | 24 +- src/NAnt.Core/Filters/Support/FilterChain.cs | 26 - src/NAnt.Core/Tasks/CopyTask.cs | 992 +++----------------------- src/NAnt.Core/Tasks/MoveTask.cs | 179 +---- src/NAnt.Core/Types/FileSet.cs | 31 +- src/NAnt.Core/Util/FileUtils.cs | 373 +--------- tests/NAnt.Core/DirectoryScannerTest.cs | 24 - tests/NAnt.Core/FrameworkInfoTest.cs | 2 +- tests/NAnt.Core/Tasks/CopyTest.cs | 72 ++- tests/NAnt.Core/Tasks/MoveTest.cs | 329 +--------- 11 files changed, 234 insertions(+), 1828 deletions(-) diff --git a/src/CommonAssemblyInfo.cs b/src/CommonAssemblyInfo.cs index be85e07..dd8d612 100644 --- a/src/CommonAssemblyInfo.cs +++ b/src/CommonAssemblyInfo.cs @@ -5,7 +5,7 @@ using System.Runtime.InteropServices; //------------------------------------------------------------------------------ // <auto-generated> // This code was generated by a tool. -// Runtime Version:4.0.30319.269 +// Runtime Version:4.0.30319.1008 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. @@ -16,12 +16,12 @@ using System.Runtime.InteropServices; [assembly: CLSCompliantAttribute(true)] [assembly: AssemblyTitleAttribute("NAnt")] [assembly: AssemblyDescriptionAttribute("A .NET Build Tool")] -[assembly: AssemblyConfigurationAttribute("release")] +[assembly: AssemblyConfigurationAttribute("dev")] [assembly: AssemblyCompanyAttribute("http://nant.sourceforge.net")] [assembly: AssemblyProductAttribute("NAnt")] -[assembly: AssemblyCopyrightAttribute("Copyright (C) 2001-2012 Gerry Shaw")] +[assembly: AssemblyCopyrightAttribute("Copyright (C) 2001-2013 Gerry Shaw")] [assembly: AssemblyTrademarkAttribute("")] [assembly: AssemblyCultureAttribute("")] -[assembly: AssemblyVersionAttribute("0.92.4543.0")] -[assembly: AssemblyInformationalVersionAttribute("0.92")] +[assembly: AssemblyVersionAttribute("0.93.5019.0")] +[assembly: AssemblyInformationalVersionAttribute("0.93")] diff --git a/src/NAnt.Core/DirectoryScanner.cs b/src/NAnt.Core/DirectoryScanner.cs index 8ff53e9..bf259bf 100644 --- a/src/NAnt.Core/DirectoryScanner.cs +++ b/src/NAnt.Core/DirectoryScanner.cs @@ -124,9 +124,6 @@ namespace NAnt.Core { private ArrayList _searchDirIsRecursive; private bool _caseSensitive; - // Indicates whether or not every file scanned was included - private bool _isEverythingIncluded = true; - #endregion Private Instance Fields #region Private Static Fields @@ -310,15 +307,6 @@ namespace NAnt.Core { } } - /// <summary> - /// Indicates whether or not the directory scanner included everything - /// that it scanned. - /// </summary> - public bool IsEverythingIncluded - { - get { return _isEverythingIncluded; } - } - #endregion Public Instance Properties #region Public Instance Methods @@ -376,7 +364,6 @@ namespace NAnt.Core { #region Private Instance Methods private void Reset () { - _isEverythingIncluded = true; _includePatterns = null; _includeNames = null; _excludePatterns = null; @@ -766,17 +753,8 @@ namespace NAnt.Core { } #if DEBUG_REGEXES - Console.WriteLine("Result: {0}", included); + Console.WriteLine("Result: {0}", included); #endif - // If the current file was not included and the isEverythingIncluded - // indicator is true; set the isEverythingIncluded indicator to false. - // Note: File.Exists(path) is used to make sure the current path is - // a file and not a directory. - if (!included && _isEverythingIncluded && File.Exists(path)) - { - _isEverythingIncluded = false; - } - return included; } diff --git a/src/NAnt.Core/Filters/Support/FilterChain.cs b/src/NAnt.Core/Filters/Support/FilterChain.cs index c81b50e..7790829 100644 --- a/src/NAnt.Core/Filters/Support/FilterChain.cs +++ b/src/NAnt.Core/Filters/Support/FilterChain.cs @@ -176,32 +176,6 @@ namespace NAnt.Core.Filters { #endregion Internal Instance Methods - #region Internal Static Methods - - /// <summary> - /// Determines whether a given FilterChain is null or empty. - /// </summary> - /// <returns> - /// <c>true</c> if <paramref name="filterChain"/> is null or empty; - /// otherwise, <c>false</c>. - /// </returns> - /// <param name='filterChain'> - /// The FilterChain to check. - /// </param> - internal static bool IsNullOrEmpty(FilterChain filterChain) - { - if (filterChain == null) - { - return true; - } - else - { - return filterChain.Filters.Count <= 0; - } - } - - #endregion Internal Static Methods - /// <summary> /// Configurator that initializes filters in the order in which they've /// been specified in the build file. diff --git a/src/NAnt.Core/Tasks/CopyTask.cs b/src/NAnt.Core/Tasks/CopyTask.cs index 1535166..7c146d3 100644 --- a/src/NAnt.Core/Tasks/CopyTask.cs +++ b/src/NAnt.Core/Tasks/CopyTask.cs @@ -17,15 +17,14 @@ // // Gerry Shaw (ger...@ya...) // Ian MacLean (ima...@gm...) -// Ryan Boggs (rm...@us...) using System; using System.Collections; -using System.Collections.ObjectModel; using System.Collections.Specialized; using System.Globalization; using System.IO; using System.Text; +using System.Xml; using NAnt.Core.Attributes; using NAnt.Core.Types; @@ -44,38 +43,8 @@ namespace NAnt.Core.Tasks { /// explicitly overwrite files with the <see cref="Overwrite" /> attribute. /// </para> /// <para> - /// Entire directory structures can be copied to a new location. For this - /// to happen, the following criteria must be met: - /// </para> - /// <list type="bullet"> - /// <item> - /// <description> - /// Everything in the fileset is included - /// </description> - /// </item> - /// <item> - /// <description> - /// The directory structure is not flattened - /// </description> - /// </item> - /// <item> - /// <description> - /// Empty directories are included - /// </description> - /// </item> - /// <item> - /// <description> - /// Destination directory does not exist - /// </description> - /// </item> - /// </list> - /// <para> - /// If any of these items are not met, then the files within the source - /// directory will be copied over instead of the entire directory structure. - /// </para> - /// <para> - /// When a <see cref="FileSet" /> is used to select files or directories to - /// copy, the <see cref="ToDirectory" /> attribute must be set. Files that are + /// When a <see cref="FileSet" /> is used to select files to copy, the + /// <see cref="ToDirectory" /> attribute must be set. Files that are /// located under the base directory of the <see cref="FileSet" /> will /// be copied to a directory under the destination directory matching the /// path relative to the base directory of the <see cref="FileSet" />, @@ -156,7 +125,7 @@ namespace NAnt.Core.Tasks { /// </para> /// <code> /// <![CDATA[ - /// <copy todir="target/dir"> + /// <copy tofile="target/dir"> /// <fileset basedir="source/dir"/> /// </copy> /// ]]> @@ -172,7 +141,7 @@ namespace NAnt.Core.Tasks { private bool _overwrite; private bool _flatten; private FileSet _fileset = new FileSet(); - private FileOperationMap _operationMap; + private Hashtable _fileCopyMap; private bool _includeEmptyDirs = true; private FilterChain _filters; private Encoding _inputEncoding; @@ -187,9 +156,9 @@ namespace NAnt.Core.Tasks { /// </summary> public CopyTask() { if (PlatformHelper.IsUnix) { - _operationMap = new FileOperationMap(); + _fileCopyMap = new Hashtable(); } else { - _operationMap = new FileOperationMap(StringComparer.InvariantCultureIgnoreCase); + _fileCopyMap = CollectionsUtil.CreateCaseInsensitiveHashtable(); } } @@ -306,48 +275,18 @@ namespace NAnt.Core.Tasks { /// </summary> /// <remarks> /// <para> - /// FileCopyMap should now be considered a readonly hashtable. Any changes to - /// this property will not be taken into account during the file operation - /// task. To interact with the file operation, use the - /// <see cref="OperationMap"/> property. - /// </para> - /// <para> - /// The key of the <see cref="Hashtable" /> is the absolute path of + /// The key of the <see cref="Hashtable" /> is the absolute path of /// the destination file and the value is a <see cref="FileDateInfo" /> /// holding the path and last write time of the most recently updated - /// source file that is selected to be copied or moved to the + /// source file that is selected to be copied or moved to the /// destination file. /// </para> /// <para> /// On Windows, the <see cref="Hashtable" /> is case-insensitive. /// </para> /// </remarks> - [ObsoleteAttribute("FileCopyMap is now considered a readonly hashtable. To interact with file operation, use the OperationMap property")] - protected Hashtable FileCopyMap - { - get { return _operationMap.ConvertToHashtable(); } - } - - /// <summary> - /// Gets the operation map containing all the files/directories to - /// perform file operations on. - /// </summary> - /// <remarks> - /// <para> - /// The type of class for this object inherits from KeyedCollection - /// and is structured so that the key of this collection contains the - /// full path of the target file/location while the value contains - /// the <see cref="NAnt.Core.Tasks.CopyTask.FileOperation"/> object - /// with the operation details. - /// </para> - /// <para> - /// On Windows, the <see cref="NAnt.Core.Tasks.CopyTask.FileOperationMap"/> - /// is case-insensitive. - /// </para> - /// </remarks> - protected FileOperationMap OperationMap - { - get { return _operationMap; } + protected Hashtable FileCopyMap { + get { return _fileCopyMap; } } #endregion Protected Instance Properties @@ -401,91 +340,37 @@ namespace NAnt.Core.Tasks { } // Clear previous copied files - _operationMap.Clear(); + _fileCopyMap = new Hashtable(); - // copy a single file object. - if (SourceFile != null) - { - // Setup the necessary local vars - FileOperation operation; - FileSystemInfo srcInfo; - FileSystemInfo dstInfo; - - // If the full path in the SourceFile is an actual file, - // assign the SourceFile object as is to srcInfo. - if (SourceFile.Exists) - { - srcInfo = SourceFile; - } - // If the full path in the SoureFile is a directory, - // assign the SourceFile object as a DirectoryInfo object to srcInfo. - else if (Directory.Exists(SourceFile.FullName)) - { - srcInfo = new DirectoryInfo(SourceFile.FullName); - } - // Otherwise, throw an error. - else - { - throw CreateSourceFileNotFoundException(SourceFile.FullName); - } - - // If the ToFile object is not null, assign it to dstInfo; - // otherwise, assign the ToDirectory object to dstInfo. - if (ToFile != null) - { - dstInfo = ToFile; - } - else - { - dstInfo = ToDirectory; - } - - // Initialize the operation var with the srcInfo and dstInfo - // objects that were assigned above. - operation = new FileOperation(srcInfo, dstInfo); + // copy a single file. + if (SourceFile != null) { + if (SourceFile.Exists) { + FileInfo dstInfo = null; + if (ToFile != null) { + dstInfo = ToFile; + } else { + string dstFilePath = Path.Combine(ToDirectory.FullName, + SourceFile.Name); + dstInfo = new FileInfo(dstFilePath); + } - // If the user specified "Overwrite" or the target file/path - // is considered outdated, ensure that the target file/path is - // normalized before adding to the operation map. - if (Overwrite || operation.Outdated) - { - operation.NormalizeTargetAttributes(); - _operationMap.Add(operation); - } - } - // This copy/moves the entire directory. In order for this to occur, the - // following criteria needs to be met: - // * Everything in the fileset is included - // * The directory structure is not flattened - // * Empty directories are included - // * and either - // * the destination directory does not exist - // * or the destination directory is the same as source directory but - // with different casing (ie: C:\nant to C:\NAnt) - else if (CopyFileSet.IsEverythingIncluded && !Flatten && IncludeEmptyDirs && - FileOperation.TargetDirectoryDoesNotExist(CopyFileSet.BaseDirectory, - ToDirectory)) - { - OperationMap.Add(new FileOperation(CopyFileSet.BaseDirectory, ToDirectory)); - } - // Otherwise, copy/move the individual files. - else - { - // If no includes were specified, add all files and subdirectories - // from the fileset's base directory to the fileset. - if ((CopyFileSet.Includes.Count == 0) && (CopyFileSet.AsIs.Count == 0)) - { - CopyFileSet.Includes.Add("**/*"); + // do the outdated check + bool outdated = (!dstInfo.Exists) || (SourceFile.LastWriteTime > dstInfo.LastWriteTime); - // Make sure to rescan the fileset after adding "**/*" - CopyFileSet.Scan(); + if (Overwrite || outdated) { + // add to a copy map of absolute verified paths + FileCopyMap.Add(dstInfo.FullName, new FileDateInfo(SourceFile.FullName, SourceFile.LastWriteTime)); + if (dstInfo.Exists && dstInfo.Attributes != FileAttributes.Normal) { + File.SetAttributes(dstInfo.FullName, FileAttributes.Normal); + } + } + } else { + throw CreateSourceFileNotFoundException (SourceFile.FullName); } - - // copy file set contents. - // get the complete path of the base directory of the fileset, - // ie, c:\work\nant\src + } else { // copy file set contents. + // get the complete path of the base directory of the fileset, ie, c:\work\nant\src DirectoryInfo srcBaseInfo = CopyFileSet.BaseDirectory; - + // if source file not specified use fileset foreach (string pathname in CopyFileSet.FileNames) { FileInfo srcInfo = new FileInfo(pathname); @@ -518,32 +403,33 @@ namespace NAnt.Core.Tasks { dstRelFilePath); } - // Setup both the destination info and file operation vars. + // do the outdated check FileInfo dstInfo = new FileInfo(dstFilePath); - FileOperation operation = new FileOperation(srcInfo, dstInfo); - - // If the user specified "Overwrite" or the target file/path - // is considered outdated, proceed to add to operation map. - if (Overwrite || operation.Outdated) - { + bool outdated = (!dstInfo.Exists) || (srcInfo.LastWriteTime > dstInfo.LastWriteTime); + if (Overwrite || outdated) { + // construct FileDateInfo for current file + FileDateInfo newFile = new FileDateInfo(srcInfo.FullName, + srcInfo.LastWriteTime); // if multiple source files are selected to be copied // to the same destination file, then only the last // updated source should actually be copied - if (_operationMap.ContainsKey(dstInfo.FullName)) - { - _operationMap[dstInfo.FullName].UpdateSource(srcInfo); - } - else - { - // ensure that the target file/path is normalized - // before adding to the operation map. - operation.NormalizeTargetAttributes(); - _operationMap.Add(operation); + FileDateInfo oldFile = (FileDateInfo) FileCopyMap[dstInfo.FullName]; + if (oldFile != null) { + // if current file was updated after scheduled file, + // then replace it + if (newFile.LastWriteTime > oldFile.LastWriteTime) { + FileCopyMap[dstInfo.FullName] = newFile; + } + } else { + FileCopyMap.Add(dstInfo.FullName, newFile); + if (dstInfo.Exists && dstInfo.Attributes != FileAttributes.Normal) { + File.SetAttributes(dstInfo.FullName, FileAttributes.Normal); + } } } } else { - throw CreateSourceFileNotFoundException(srcInfo.FullName); + throw CreateSourceFileNotFoundException (srcInfo.FullName); } } @@ -567,7 +453,7 @@ namespace NAnt.Core.Tasks { Directory.CreateDirectory(destinationDirectory); } catch (Exception ex) { throw new BuildException(string.Format(CultureInfo.InvariantCulture, - "Failed to create directory '{0}'.", destinationDirectory), + "Failed to create directory '{0}'.", destinationDirectory ), Location, ex); } Log(Level.Verbose, "Created directory '{0}'.", destinationDirectory); @@ -588,139 +474,43 @@ namespace NAnt.Core.Tasks { /// Actually does the file copies. /// </summary> protected virtual void DoFileOperations() { - // If the operation map is empty, exit (return) the method. - if (OperationMap.Count <= 0) - { - return; - } - - // Get the number of file and directory copies to display to - // the user. - int fileMovements = OperationMap.CountFileOperations(); - int dirMovements = OperationMap.CountDirectoryOperations(); - - // Output the number of file copies - if (fileMovements > 0) - { - if (ToFile != null) { - Log(Level.Info, "Copying {0} file{1} to '{2}'.", - fileMovements, (fileMovements != 1) ? "s" : "", ToFile); - } else { - Log(Level.Info, "Copying {0} file{1} to '{2}'.", - fileMovements, (fileMovements != 1) ? "s" : "", ToDirectory); - } - } - - // Output the number of directory copies - if (dirMovements > 0) - { + int fileCount = FileCopyMap.Count; + if (fileCount > 0 || Verbose) { if (ToFile != null) { - Log(Level.Info, "Copying {0} {1} to '{2}'.", - dirMovements, (dirMovements != 1) ? "directories" : "directory", - ToFile); + Log(Level.Info, "Copying {0} file{1} to '{2}'.", fileCount, (fileCount != 1) ? "s" : "", ToFile); } else { - Log(Level.Info, "Copying {0} {1} to '{2}'.", - dirMovements, (dirMovements != 1) ? "directories" : "directory", - ToDirectory); + Log(Level.Info, "Copying {0} file{1} to '{2}'.", fileCount, (fileCount != 1) ? "s" : "", ToDirectory); } - } - // loop thru our file list - for (int i = 0; i < OperationMap.Count; i++) - { - // Setup a temporary var to hold the current file operation - // details. - FileOperation currentOperation = OperationMap[i]; - if (currentOperation.SourceEqualsTarget()) - { - Log(Level.Verbose, "Skipping self-copy of '{0}'.", - currentOperation.Source); - continue; - } + // loop thru our file list + foreach (DictionaryEntry fileEntry in FileCopyMap) { + string destinationFile = (string) fileEntry.Key; + string sourceFile = ((FileDateInfo) fileEntry.Value).Path; - try - { - Log(Level.Verbose, "Copying {0}.", currentOperation.ToString()); - - switch (currentOperation.OperationType) - { - case OperationType.FileToFile: - // create directory if not present - string destinationDirectory = - Path.GetDirectoryName(currentOperation.Target); - if (!Directory.Exists(destinationDirectory)) - { - Directory.CreateDirectory(destinationDirectory); - Log(Level.Verbose, "Created directory '{0}'.", - destinationDirectory); - } + if (sourceFile == destinationFile) { + Log(Level.Verbose, "Skipping self-copy of '{0}'.", sourceFile); + continue; + } - // Ensure the target file is removed before - // attempting to copy. - if (File.Exists(currentOperation.Target)) - { - File.Delete(currentOperation.Target); - } - - // copy the file with filters - FileUtils.CopyFile(currentOperation.Source, - currentOperation.Target, Filters, - InputEncoding, OutputEncoding); - break; - case OperationType.FileToDirectory: - // Setup a local var that combines the directory - // of the target path with the source file name. - string targetFile = Path.Combine(currentOperation.Target, - Path.GetFileName(currentOperation.Source)); - // create directory if not present - if (!Directory.Exists(currentOperation.Target)) - { - Directory.CreateDirectory(currentOperation.Target); - Log(Level.Verbose, "Created directory '{0}'.", - currentOperation.Target); - } + try { + Log(Level.Verbose, "Copying '{0}' to '{1}'.", sourceFile, destinationFile); + + // create directory if not present + string destinationDirectory = Path.GetDirectoryName(destinationFile); + if (!Directory.Exists(destinationDirectory)) { + Directory.CreateDirectory(destinationDirectory); + Log(Level.Verbose, "Created directory '{0}'.", destinationDirectory); + } - // Ensure the target file is removed before - // attempting to copy. - if (File.Exists(targetFile)) - { - File.Delete(targetFile); - } - - // copy the file with filters - FileUtils.CopyFile(currentOperation.Source, - targetFile, Filters, InputEncoding, OutputEncoding); - break; - case OperationType.DirectoryToDirectory: - // Throw a build exception if the target directory - // already exists. - if (Directory.Exists(currentOperation.Target)) - { - throw new BuildException( - string.Format(CultureInfo.InvariantCulture, - "Failed to copy {0}. Directory '{1}' already exists.", - currentOperation.ToString(), - currentOperation.Target)); - } - - // Copy over the entire directory with filters - FileUtils.CopyDirectory(currentOperation.Source, - currentOperation.Target, Filters, InputEncoding, - OutputEncoding); - break; - default: - throw new - BuildException("Unrecognized copy operation. " + - "The copy task can only copy a file to file, " + - "file to directory, or directory to directory."); + // copy the file with filters + FileUtils.CopyFile(sourceFile, destinationFile, Filters, + InputEncoding, OutputEncoding); + } catch (Exception ex) { + throw new BuildException(string.Format(CultureInfo.InvariantCulture, + "Cannot copy '{0}' to '{1}'.", sourceFile, destinationFile), + Location, ex); } } - catch (Exception ex) - { - throw new BuildException(string.Format(CultureInfo.InvariantCulture, - "Cannot copy {0}.", currentOperation.ToString()), - Location, ex); - } } } @@ -735,30 +525,16 @@ namespace NAnt.Core.Tasks { /// <summary> /// Holds the absolute paths and last write time of a given file. /// </summary> - protected class FileDateInfo - { + protected class FileDateInfo { #region Public Instance Constructors /// <summary> - /// Initializes a new instance of the - /// <see cref="NAnt.Core.Tasks.CopyTask.FileDateInfo"/> class - /// for the specified <paramref name="file"/>. - /// </summary> - /// <param name="file"> - /// A <see cref="System.IO.FileSystemInfo"/> object containing - /// the full path and last write time of the file the object represents. - /// </param> - public FileDateInfo(FileSystemInfo file) - : this(file.FullName, file.LastWriteTime) {} - - /// <summary> /// Initializes a new instance of the <see cref="FileDateInfo" /> /// class for the specified file and last write time. /// </summary> /// <param name="path">The absolute path of the file.</param> /// <param name="lastWriteTime">The last write time of the file.</param> - public FileDateInfo(string path, DateTime lastWriteTime) - { + public FileDateInfo(string path, DateTime lastWriteTime) { _path = path; _lastWriteTime = lastWriteTime; } @@ -773,8 +549,7 @@ namespace NAnt.Core.Tasks { /// <value> /// The absolute path of the current file. /// </value> - public string Path - { + public string Path { get { return _path; } } @@ -784,8 +559,7 @@ namespace NAnt.Core.Tasks { /// <value> /// The time when the current file was last written to. /// </value> - public DateTime LastWriteTime - { + public DateTime LastWriteTime { get { return _lastWriteTime; } } @@ -798,593 +572,5 @@ namespace NAnt.Core.Tasks { #endregion Private Instance Fields } - - /// <summary> - /// Provides methods and properties to properly manage file operations for - /// NAnt file system based tasks (such as CopyTask and MoveTask). - /// </summary> - protected class FileOperation - { - #region Private Instance Fields - - private FileSystemInfo _source; - private FileSystemInfo _target; - private StringComparer _comparer; - - #endregion Private Instance Fields - - #region Public Constructors - - /// <summary> - /// Initializes a new instance of the - /// <see cref="NAnt.Core.Tasks.CopyTask.FileOperation"/> class with the - /// source and target locations specified. - /// </summary> - /// <param name="source"> - /// A <see cref="FileSystemInfo"/> object representing the file/location - /// where the file operation will start. - /// </param> - /// <param name="target"> - /// A <see cref="FileSystemInfo"/> object representing the file/location - /// where the file operation will end. - /// </param> - public FileOperation(FileSystemInfo source, FileSystemInfo target) - { - if (source == null) - { - throw new ArgumentNullException("source"); - } - if (target == null) - { - throw new ArgumentNullException("target"); - } - if (IsFileSystemType<DirectoryInfo>(source) && - IsFileSystemType<FileInfo>(target)) - { - throw new BuildException("Cannot transfer directory to file"); - } - _source = source; - _target = target; - } - - #endregion Public Constructors - - #region Public Instance Properties - - /// <summary> - /// Gets or sets the string comparer to use when comparing - /// the source path to the target path. - /// </summary> - public StringComparer Comparer - { - get { return _comparer; } - set { _comparer = value; } - } - - /// <summary> - /// Gets the full path of - /// <see cref="P:NAnt.Core.Tasks.CopyTask.FileOperation.SourceInfo"/>. - /// </summary> - public string Source - { - get { return _source.FullName; } - } - - /// <summary> - /// Gets the details of the source path. - /// </summary> - public FileSystemInfo SourceInfo - { - get { return _source; } - } - - /// <summary> - /// Gets the type of - /// <see cref="P:NAnt.Core.Tasks.CopyTask.FileOperation.SourceInfo"/>. - /// </summary> - public Type SourceType - { - get { return _source.GetType(); } - } - - /// <summary> - /// Gets the type of the file operation an instance of - /// <see cref="NAnt.Core.Tasks.CopyTask.FileOperation"/> represents. - /// </summary> - public OperationType OperationType - { - get - { - if (IsFileSystemType<FileInfo>(SourceInfo) && - IsFileSystemType<FileInfo>(TargetInfo)) - { - return OperationType.FileToFile; - } - if (IsFileSystemType<FileInfo>(SourceInfo) && - IsFileSystemType<DirectoryInfo>(TargetInfo)) - { - return OperationType.FileToDirectory; - } - return OperationType.DirectoryToDirectory; - } - } - - /// <summary> - /// Gets a value indicating whether - /// <see cref="P:NAnt.Core.Tasks.CopyTask.FileOperation.TargetInfo"/> is - /// outdated. - /// </summary> - /// <value> - /// <c>true</c> if - /// <see cref="P:NAnt.Core.Tasks.CopyTask.FileOperation.TargetInfo"/> is - /// outdated (or simply a directory); otherwise, <c>false</c>. - /// </value> - public bool Outdated - { - get - { - return IsFileSystemType<DirectoryInfo>(_target) || - (IsFileSystemType<FileInfo>(_target) && - TargetIsOutdated(_source, _target)); - } - } - - /// <summary> - /// Gets the full path of - /// <see cref="P:NAnt.Core.Tasks.CopyTask.FileOperation.TargetInfo"/>. - /// </summary> - public string Target - { - get { return _target.FullName; } - } - - /// <summary> - /// Gets the details of the target path. - /// </summary> - public FileSystemInfo TargetInfo - { - get { return _target; } - } - - /// <summary> - /// Gets the type of - /// <see cref="P:NAnt.Core.Tasks.CopyTask.FileOperation.TargetInfo"/>. - /// </summary> - public Type TargetType - { - get { return _target.GetType(); } - } - - #endregion Public Instance Properties - - #region Public Instance Methods - - /// <summary> - /// Normalizes the attributes of - /// <see cref="P:NAnt.Core.Tasks.CopyTask.FileOperation.TargetInfo"/>. - /// </summary> - public void NormalizeTargetAttributes() - { - if (IsFileSystemType<FileInfo>(_target) && - _target.Exists && - _target.Attributes != FileAttributes.Normal) - { - File.SetAttributes(_target.FullName, FileAttributes.Normal); - } - } - - /// <summary> - /// Checks to see whether or not the full path of - /// <see cref="P:NAnt.Core.Tasks.CopyTask.FileOperation.SourceInfo"/> - /// matches the full path of - /// <see cref="P:NAnt.Core.Tasks.CopyTask.FileOperation.TargetInfo"/>. - /// </summary> - /// <remarks> - /// <see cref="P:NAnt.Core.Tasks.CopyTask.FileOperation.Comparer"/> is - /// used to check path equality. - /// </remarks> - /// <returns> - /// <c>true</c> if both paths match; otherwise <c>false</c>. - /// </returns> - public bool SourceEqualsTarget() - { - return _comparer.Compare(_source.FullName, _target.FullName) == 0; - } - - /// <summary> - /// Checks to see whether or not the full path of - /// <see cref="P:NAnt.Core.Tasks.CopyTask.FileOperation.SourceInfo"/> - /// is identical to the full path of - /// <see cref="P:NAnt.Core.Tasks.CopyTask.FileOperation.TargetInfo"/>. - /// </summary> - /// <remarks> - /// The difference between this method and SourceEqualsTarget is - /// that the casing of the path is never ignored regardless of - /// operating system. - /// </remarks> - /// <returns> - /// <c>true</c> if both paths are identical; otherwise <c>false</c>. - /// </returns> - public bool SourceIsIdenticalToTarget() - { - return _source.FullName.Equals(_target.FullName, StringComparison.InvariantCulture); - } - - /// <summary> - /// Updates the source of a given instance based on the - /// <see cref="P:System.IO.FileSystemInfo.LastWriteTime"/>. - /// <remarks> - /// If the LastWriteTime property of the <paramref name="newSource"/> - /// is greater than the LastWriteTime property of - /// <see cref="P:NAnt.Core.Tasks.CopyTask.FileOperation.SourceInfo"/>, then - /// <see cref="P:NAnt.Core.Tasks.CopyTask.FileOperation.SourceInfo"/> is - /// replaced with <paramref name="newSource"/>. - /// </remarks> - /// </summary> - /// <param name='newSource'> - /// The new <see cref="System.IO.FileSystemInfo"/> to replace - /// the current <see cref="P:NAnt.Core.Tasks.CopyTask.FileOperation.SourceInfo"/> - /// object. - /// </param> - public void UpdateSource(FileSystemInfo newSource) - { - if (_source.LastWriteTime < newSource.LastWriteTime) - { - _source = newSource; - } - } - - /// <summary> - /// Returns a <see cref="System.String"/> that represents the current - /// <see cref="NAnt.Core.Tasks.CopyTask.FileOperation"/>. - /// </summary> - /// <returns> - /// A <see cref="System.String"/> that represents the current - /// <see cref="NAnt.Core.Tasks.CopyTask.FileOperation"/>. - /// </returns> - public override string ToString() - { - return String.Format("'{0}' to '{1}'", Source, Target); - } - - #endregion Public Instance Methods - - #region Public Static Methods - - /// <summary> - /// Checks to see if a given <see cref="System.IO.FileSystemInfo"/> - /// target is considered outdated. - /// </summary> - /// <param name='source'> - /// A <see cref="System.IO.FileSystemInfo"/> used for comparison purposes - /// against <paramref name="target"/>. - /// </param> - /// <param name='target'> - /// The <see cref="System.IO.FileSystemInfo"/> to check. - /// </param> - /// <returns> - /// <c>true</c> if the target file is considered out of date; otherwise - /// <c>false</c> - /// </returns> - public static bool TargetIsOutdated(FileSystemInfo source, FileSystemInfo target) - { - return (!target.Exists) || (source.LastWriteTime > target.LastWriteTime); - } - - /// <summary> - /// Checks to see if the target directory does not exist or that - /// it does match the source directory name but not string casing. - /// </summary> - /// <param name="source"> - /// Source directory to check against <paramref name="target"/>. - /// </param> - /// <param name="target"> - /// The target directory to validate. - /// </param> - /// <returns> - /// <c>true</c> if the target directory does not exist or matches the source - /// directory name but not casing; otherwise <c>false</c> - /// </returns> - public static bool TargetDirectoryDoesNotExist(DirectoryInfo source, DirectoryInfo target) - { - // If the target doesn't exist, return true. - if (!target.Exists) - { - return true; - } - // Otherwise, check to see if the source and target paths are the same when ignoring case. - // Return the result of the path comparison. - return source.FullName.Equals(target.FullName, StringComparison.InvariantCultureIgnoreCase); - } - - #endregion Public Static Methods - - #region Private Instance Methods - - /// <summary> - /// Checks to see whether <paramref name="item"/> is a file type or - /// a directory type. - /// </summary> - /// <typeparam name="TFileSystemInfo"> - /// The FileSystemInfo type used to compare <paramref name="item"/> with. - /// </typeparam> - /// <param name="item"> - /// The object to check. - /// </param> - /// <returns> - /// <c>true</c> if <paramref name="item"/> is the same type as - /// <typeparamref name="TFileSystemInfo"/>; otherwise, <c>false</c>. - /// </returns> - private bool IsFileSystemType<TFileSystemInfo>(FileSystemInfo item) - where TFileSystemInfo : FileSystemInfo - { - return item.GetType() == typeof(TFileSystemInfo); - } - - #endregion Private Instance Methods - } - - /// <summary> - /// A collection class used to track all of the - /// <see cref="NAnt.Core.Tasks.CopyTask.FileOperation"/> objects for - /// a given file operation task (such as the CopyTask or MoveTask). - /// </summary> - protected class FileOperationMap : KeyedCollection<string, FileOperation> - { - #region Private Instance Fields - - /// <summary> - /// The StringComparer used when comparing file paths. - /// </summary> - private StringComparer _stringComparer; - - #endregion Private Instance Fields - - #region Public Constructors - - /// <summary> - /// Initializes a new instance of the - /// <see cref="NAnt.Core.Tasks.CopyTask.FileOperationMap"/> - /// class that uses the default string comparer. - /// </summary> - public FileOperationMap() : base(StringComparer.InvariantCulture) - { - _stringComparer = StringComparer.InvariantCulture; - } - - /// <summary> - /// Initializes a new instance of the - /// <see cref="NAnt.Core.Tasks.CopyTask.FileOperationMap"/> - /// class that uses the specified string comparer. - /// </summary> - /// <param name="comparer"> - /// The string comparer to use when comparing keys in the - /// <see cref="NAnt.Core.Tasks.CopyTask.FileOperationMap"/>. - /// </param> - public FileOperationMap(StringComparer comparer) : base(comparer) - { - _stringComparer = comparer; - } - - #endregion Public Constructors - - #region Public Instance Methods - - /// <summary> - /// Determines whether the - /// <see cref="NAnt.Core.Tasks.CopyTask.FileOperationMap"/> contains the - /// specified key. - /// </summary> - /// <param name="key"> - /// The key to locate in the - /// <see cref="NAnt.Core.Tasks.CopyTask.FileOperationMap"/>. - /// </param> - /// <returns> - /// <c>true</c> if the <see cref="NAnt.Core.Tasks.CopyTask.FileOperationMap"/> - /// contains an element with the specified key; otherwise, <c>false</c>. - /// </returns> - public bool ContainsKey(string key) - { - if (Dictionary != null) - { - return Dictionary.ContainsKey(key); - } - return false; - } - - /// <summary> - /// Counts the number of directory operations in a collection. - /// </summary> - /// <returns> - /// The number of directory operations performed by this collection. - /// </returns> - public int CountDirectoryOperations() - { - int result = 0; - for (int i = 0; i < this.Count; i++) - { - if (this[i].SourceType == typeof(DirectoryInfo)) - { - result++; - } - } - return result; - } - - /// <summary> - /// Counts the number of file operations in a collection. - /// </summary> - /// <returns> - /// The number of file operations performed by this collection. - /// </returns> - public int CountFileOperations() - { - int result = 0; - for (int i = 0; i < this.Count; i++) - { - if (this[i].SourceType == typeof(FileInfo)) - { - result++; - } - } - return result; - } - - /// <summary> - /// Converts the current instance of - /// <see cref="NAnt.Core.Tasks.CopyTask.FileOperationMap"/> to - /// the old style FileCopyMap hashtable. - /// </summary> - /// <returns> - /// The contents of - /// <see cref="NAnt.Core.Tasks.CopyTask.FileOperationMap"/> in a - /// new hashtable. - /// </returns> - public Hashtable ConvertToHashtable() - { - // Setup var to return - Hashtable result; - - // Initialize return var with the proper case sensitivity - // based on underlying OS. - if (PlatformHelper.IsUnix) - { - result = new Hashtable(); - } - else - { - result = CollectionsUtil.CreateCaseInsensitiveHashtable(); - } - - // Loop through this collection and load the return hashtable var. - for (int i = 0; i < this.Count; i++) - { - FileOperation temp = this[i]; - string sourceFileName; - string targetFileName; - - // For a FileToFile operation, load the file names in the return - // hashtable var as is. - if (temp.OperationType == CopyTask.OperationType.FileToFile) - { - result.Add(temp.Target, new FileDateInfo(temp.SourceInfo)); - } - // For a FileToDirectory operation, use the source file name as - // the target file name and load accordingly. - else if (temp.OperationType == CopyTask.OperationType.FileToDirectory) - { - sourceFileName = Path.GetFileName(temp.Source); - targetFileName = Path.Combine(temp.Target, sourceFileName); - - result.Add(targetFileName, new FileDateInfo(temp.SourceInfo)); - } - // For other operations (ie: DirectoryToDirectory), scan the - // source directory for all files and load them into the - // return hashtable var. - else - { - // Retrieve all files from the current path and any subdirectories. - DirectoryScanner dirScan = new DirectoryScanner(); - dirScan.BaseDirectory = temp.SourceInfo as DirectoryInfo; - dirScan.Includes.Add("**/*"); - dirScan.Scan(); - StringCollection sourceFiles = dirScan.FileNames; - - for (int s = 0; s < sourceFiles.Count; s++) - { - string source = sourceFiles[s]; - sourceFileName = Path.GetFileName(source); - targetFileName = Path.Combine(temp.Target, sourceFileName); - - result.Add(targetFileName, new FileDateInfo(sourceFileName, - File.GetLastWriteTime(sourceFileName))); - } - } - - } - return result; - } - - #endregion Public Instance Methods - - #region Protected Instance Methods - - /// <summary> - /// Extracts the key from the specified - /// <see cref="NAnt.Core.Tasks.CopyTask.FileOperation"/> element. - /// </summary> - /// <param name="item"> - /// The <see cref="NAnt.Core.Tasks.CopyTask.FileOperation"/> from which to - /// extract the key. - /// </param> - /// <returns> - /// The key for the specified - /// <see cref="NAnt.Core.Tasks.CopyTask.FileOperation"/>. - /// </returns> - protected override string GetKeyForItem(FileOperation item) - { - return item.Target; - } - - /// <summary> - /// Inserts an element into the - /// <see cref="NAnt.Core.Tasks.CopyTask.FileOperationMap"/> at the - /// specified index. - /// </summary> - /// <param name="index"> - /// The zero-based index at which item should be inserted. - /// </param> - /// <param name="item"> - /// The <see cref="NAnt.Core.Tasks.CopyTask.FileOperation"/> to insert. - /// </param> - protected override void InsertItem(int index, FileOperation item) - { - // Assigns the string comparer to the item before calling - // the base method. - item.Comparer = _stringComparer; - base.InsertItem(index, item); - } - - /// <summary> - /// Replaces the item at the specified index with the specified item. - /// </summary> - /// <param name="index"> - /// The zero-based index of the item to be replaced. - /// </param> - /// <param name="item"> - /// The new item. - /// </param> - protected override void SetItem(int index, FileOperation item) - { - // Assigns the string comparer to the item before calling - // the base method. - item.Comparer = _stringComparer; - base.SetItem(index, item); - } - - #endregion Protected Instance Methods - } - - /// <summary> - /// Used to identify the type of operation a given - /// <see cref="NAnt.Core.Tasks.CopyTask.FileOperation"/> represent. - /// </summary> - protected enum OperationType - { - /// <summary> - /// Indicates that the operation is from file to file. - /// </summary> - FileToFile = 0, - - /// <summary> - /// Indicates that the operation is from file to directory. - /// </summary> - FileToDirectory = 1, - - /// <summary> - /// Indicates that the operation is from directory to directory. - /// </summary> - DirectoryToDirectory = 2 - } } } diff --git a/src/NAnt.Core/Tasks/MoveTask.cs b/src/NAnt.Core/Tasks/MoveTask.cs index 3480dec..2928ba9 100644 --- a/src/NAnt.Core/Tasks/MoveTask.cs +++ b/src/NAnt.Core/Tasks/MoveTask.cs @@ -17,9 +17,9 @@ // // Gerry Shaw (ger...@ya...) // Ian MacLean (ima...@gm...) -// Ryan Boggs (rm...@us...) using System; +using System.Collections; using System.Globalization; using System.IO; @@ -40,38 +40,8 @@ namespace NAnt.Core.Tasks { /// attribute. /// </para> /// <para> - /// Entire directory structures can be moved to a new location. For this - /// to happen, the following criteria must be met: - /// </para> - /// <list type="bullet"> - /// <item> - /// <description> - /// Everything in the fileset is included - /// </description> - /// </item> - /// <item> - /// <description> - /// The directory structure is not flattened - /// </description> - /// </item> - /// <item> - /// <description> - /// Empty directories are included - /// </description> - /// </item> - /// <item> - /// <description> - /// Destination directory does not exist - /// </description> - /// </item> - /// </list> - /// <para> - /// If any of these items are not met, then the files within the source - /// directory will be moved over instead of the entire directory structure. - /// </para> - /// <para> - /// A <see cref="FileSet" /> can be used to select files or directories to move. - /// To use a <see cref="FileSet" />, the <see cref="CopyTask.ToDirectory" /> + /// A <see cref="FileSet" /> can be used to select files to move. To use + /// a <see cref="FileSet" />, the <see cref="CopyTask.ToDirectory" /> /// attribute must be set. /// </para> /// <h3>Encoding</h3> @@ -143,7 +113,7 @@ namespace NAnt.Core.Tasks { /// </para> /// <code> /// <![CDATA[ - /// <move todir="target/dir"> + /// <move tofile="target/dir"> /// <fileset basedir="source/dir"/> /// </move> /// ]]> @@ -214,122 +184,48 @@ namespace NAnt.Core.Tasks { /// Actually does the file moves. /// </summary> protected override void DoFileOperations() { - // If the operation map is empty, exit (return) the method. - if (OperationMap.Count <= 0) - { - return; - } - - // loop thru our file list - for (int i = 0; i < OperationMap.Count; i++) - { - // Setup a temporary var to hold the current file operation - // details. - FileOperation currentOperation = OperationMap[i]; - if (currentOperation.SourceIsIdenticalToTarget()) - { - Log(Level.Warning, String.Format("Skipping self-move of {0}.", - currentOperation.Source)); - continue; - } + if (FileCopyMap.Count > 0) { + // loop thru our file list + foreach (DictionaryEntry fileEntry in FileCopyMap) { + string destinationPath = (string) fileEntry.Key; + string sourcePath = ((FileDateInfo) fileEntry.Value).Path; - try - { - Log(Level.Verbose, "Moving {0}.", currentOperation.ToString()); - - string destinationDirectory = null; - - switch (currentOperation.OperationType) - { - case OperationType.FileToFile: - // Setup the dest directory var - destinationDirectory = - Path.GetDirectoryName(currentOperation.Target); - - // create directory if not present - if (!Directory.Exists(destinationDirectory)) - { - Directory.CreateDirectory(destinationDirectory); - Log(Level.Verbose, "Created directory '{0}'.", - destinationDirectory); - } + if (sourcePath == destinationPath) { + Log(Level.Warning, "Skipping self-move of {0}." + sourcePath); + continue; + } - // Ensure the target file is removed before - // attempting to move. - if (File.Exists(currentOperation.Target)) - { - File.Delete(currentOperation.Target); + try { + // check if directory exists + if (Directory.Exists(sourcePath)) { + Log(Level.Verbose, "Moving directory '{0}' to '{1}'.", sourcePath, destinationPath); + Directory.Move(sourcePath, destinationPath); + } else { + DirectoryInfo todir = new DirectoryInfo(destinationPath); + if (!todir.Exists) { + Directory.CreateDirectory(Path.GetDirectoryName(destinationPath)); } - // move the file with filters - FileUtils.MoveFile(currentOperation.Source, - currentOperation.... [truncated message content] |
From: Ryan Boggs <rm...@gm...> --- src/NAnt.Core/Filters/Support/FilterChain.cs | 19 ++ src/NAnt.Core/Tasks/CopyTask.cs | 329 ++++++++++++++++++-------- src/NAnt.Core/Tasks/MoveTask.cs | 11 +- src/NAnt.Core/Util/FileUtils.cs | 48 ++++ tests/NAnt.Core/Tasks/MoveTest.cs | 2 +- 5 files changed, 305 insertions(+), 104 deletions(-) diff --git a/src/NAnt.Core/Filters/Support/FilterChain.cs b/src/NAnt.Core/Filters/Support/FilterChain.cs index 7790829..901bbc5 100644 --- a/src/NAnt.Core/Filters/Support/FilterChain.cs +++ b/src/NAnt.Core/Filters/Support/FilterChain.cs @@ -176,6 +176,25 @@ namespace NAnt.Core.Filters { #endregion Internal Instance Methods + #region Internal Static Methods + + /// <summary> + /// Determines whether a given FilterChain is null or empty. + /// </summary> + /// <returns> + /// <c>true</c> if <paramref name="filterChain"/> is null or empty; + /// otherwise, <c>false</c>. + /// </returns> + /// <param name='filterChain'> + /// The FilterChain to check. + /// </param> + internal static bool IsNullOrEmpty(FilterChain filterChain) + { + return (filterChain == null) || filterChain.Filters.Count <= 0; + } + + #endregion Internal Static Methods + /// <summary> /// Configurator that initializes filters in the order in which they've /// been specified in the build file. diff --git a/src/NAnt.Core/Tasks/CopyTask.cs b/src/NAnt.Core/Tasks/CopyTask.cs index b59efce..02e000f 100644 --- a/src/NAnt.Core/Tasks/CopyTask.cs +++ b/src/NAnt.Core/Tasks/CopyTask.cs @@ -303,13 +303,15 @@ namespace NAnt.Core.Tasks { Location); } - if (ToDirectory == null && CopyFileSet != null && CopyFileSet.Includes.Count > 0) { + if (ToDirectory == null && CopyFileSet != null && + (CopyFileSet.Includes.Count > 0 || CopyFileSet.IsEverythingIncluded)) { throw new BuildException(string.Format(CultureInfo.InvariantCulture, "The 'todir' should be set when using the <fileset> element" + " to specify the list of files to be copied."), Location); } - if (SourceFile != null && CopyFileSet != null && CopyFileSet.Includes.Count > 0) { + if (SourceFile != null && CopyFileSet != null && + (CopyFileSet.Includes.Count > 0 || CopyFileSet.IsEverythingIncluded)) { throw new BuildException(string.Format(CultureInfo.InvariantCulture, "The 'file' attribute and the <fileset> element" + " cannot be combined."), Location); @@ -342,13 +344,19 @@ namespace NAnt.Core.Tasks { // Clear previous copied files _fileCopyMap.Clear(); - // copy a single file. - if (SourceFile != null) { - if (SourceFile.Exists) { + // if the source file is specified, check to see whether it is a file or directory before proceeding + if (SourceFile != null) + { + // copy a single file. + if (SourceFile.Exists) + { FileInfo dstInfo = null; - if (ToFile != null) { + if (ToFile != null) + { dstInfo = ToFile; - } else { + } + else + { string dstFilePath = Path.Combine(ToDirectory.FullName, SourceFile.Name); dstInfo = new FileInfo(dstFilePath); @@ -357,112 +365,185 @@ namespace NAnt.Core.Tasks { // do the outdated check bool outdated = (!dstInfo.Exists) || (SourceFile.LastWriteTime > dstInfo.LastWriteTime); - if (Overwrite || outdated) { + if (Overwrite || outdated) + { // add to a copy map of absolute verified paths FileCopyMap.Add(dstInfo.FullName, new FileDateInfo(SourceFile.FullName, SourceFile.LastWriteTime)); - if (dstInfo.Exists && dstInfo.Attributes != FileAttributes.Normal) { + + if (dstInfo.Exists && dstInfo.Attributes != FileAttributes.Normal) + { File.SetAttributes(dstInfo.FullName, FileAttributes.Normal); } } - } else { + } + // If SourceFile exists as a directory, proceed with moving the specified directory + else if (!SourceFile.Exists && Directory.Exists(SourceFile.FullName)) + { + // Stage the directory names + string sourceDirName = SourceFile.FullName; + string destDirName; + + // If ToFile was specified, make sure the specified filename does not exist + // as a file or a directory. + if (ToFile != null) + { + if (ToFile.Exists) + { + throw new BuildException(String.Format(CultureInfo.InvariantCulture, + "Cannot move directory '{0}' to an existing file '{1}'", + SourceFile.FullName, ToFile.FullName), Location); + } + if (Directory.Exists(ToFile.FullName)) + { + throw new BuildException(String.Format(CultureInfo.InvariantCulture, + "Cannot move directory '{0}' to an existing directory '{1}'", + SourceFile.FullName, ToFile.FullName), Location); + } + destDirName = ToFile.FullName; + } + // If ToDirectory was specified, make sure the specified directory does not + // exist. + else if (ToDirectory != null) + { + if (ToDirectory.Exists) + { + throw new BuildException(String.Format(CultureInfo.InvariantCulture, + "Cannot move directory '{0}' to an existing directory '{1}'", + SourceFile.FullName, ToDirectory.FullName), Location); + } + destDirName = ToDirectory.FullName; + } + // Else, throw an exception + else + { + throw new BuildException("Target directory name not specified", + Location); + } + FileCopyMap.Add(destDirName, new FileDateInfo(sourceDirName, SourceFile.LastWriteTime, true)); + } + else + { throw CreateSourceFileNotFoundException (SourceFile.FullName); } - } else { // copy file set contents. + } + + // copy file set contents. + else + { // get the complete path of the base directory of the fileset, ie, c:\work\nant\src DirectoryInfo srcBaseInfo = CopyFileSet.BaseDirectory; - - // if source file not specified use fileset - foreach (string pathname in CopyFileSet.FileNames) { - FileInfo srcInfo = new FileInfo(pathname); - if (srcInfo.Exists) { - // will holds the full path to the destination file - string dstFilePath; - if (Flatten) { - dstFilePath = Path.Combine(ToDirectory.FullName, - srcInfo.Name); - } else { - // Gets the relative path and file info from the full - // source filepath - // pathname = C:\f2\f3\file1, srcBaseInfo=C:\f2, then - // dstRelFilePath=f3\file1 - string dstRelFilePath = ""; - if (srcInfo.FullName.IndexOf(srcBaseInfo.FullName, 0) != -1) { - dstRelFilePath = srcInfo.FullName.Substring( - srcBaseInfo.FullName.Length); + // Check to see if the file operation is a straight pass through (ie: no file or + // directory modifications) before proceeding. + bool completeDir = (CopyFileSet.FileNames.Count <= 0 || CopyFileSet.IsEverythingIncluded) && + !Flatten && IncludeEmptyDirs && FilterChain.IsNullOrEmpty(Filters) && + _inputEncoding == null && _outputEncoding == null && srcBaseInfo != null && + !String.IsNullOrEmpty(srcBaseInfo.FullName) && srcBaseInfo.Exists && + !ToDirectory.Exists; + + if (completeDir) + { + FileCopyMap.Add(ToDirectory.FullName, + new FileDateInfo(srcBaseInfo.FullName, srcBaseInfo.LastWriteTime, true)); + Console.WriteLine("Complete Dir Entry added: '{0}' - '{1}'", ToDirectory.FullName, + FileCopyMap[ToDirectory.FullName].ToString()); + } + else + { + // if source file not specified use fileset + foreach (string pathname in CopyFileSet.FileNames) + { + FileInfo srcInfo = new FileInfo(pathname); + if (srcInfo.Exists) { + // will holds the full path to the destination file + string dstFilePath; + + if (Flatten) { + dstFilePath = Path.Combine(ToDirectory.FullName, + srcInfo.Name); } else { - dstRelFilePath = srcInfo.Name; - } - - if (dstRelFilePath[0] == Path.DirectorySeparatorChar) { - dstRelFilePath = dstRelFilePath.Substring(1); + // Gets the relative path and file info from the full + // source filepath + // pathname = C:\f2\f3\file1, srcBaseInfo=C:\f2, then + // dstRelFilePath=f3\file1 + string dstRelFilePath = ""; + if (srcInfo.FullName.IndexOf(srcBaseInfo.FullName, 0) != -1) { + dstRelFilePath = srcInfo.FullName.Substring( + srcBaseInfo.FullName.Length); + } else { + dstRelFilePath = srcInfo.Name; + } + + if (dstRelFilePath[0] == Path.DirectorySeparatorChar) { + dstRelFilePath = dstRelFilePath.Substring(1); + } + + // The full filepath to copy to. + dstFilePath = Path.Combine(ToDirectory.FullName, + dstRelFilePath); } - - // The full filepath to copy to. - dstFilePath = Path.Combine(ToDirectory.FullName, - dstRelFilePath); - } - - // do the outdated check - FileInfo dstInfo = new FileInfo(dstFilePath); - bool outdated = (!dstInfo.Exists) || (srcInfo.LastWriteTime > dstInfo.LastWriteTime); + + // do the outdated check + FileInfo dstInfo = new FileInfo(dstFilePath); + bool outdated = (!dstInfo.Exists) || (srcInfo.LastWriteTime > dstInfo.LastWriteTime); - if (Overwrite || outdated) { - // construct FileDateInfo for current file - FileDateInfo newFile = new FileDateInfo(srcInfo.FullName, - srcInfo.LastWriteTime); - // if multiple source files are selected to be copied - // to the same destination file, then only the last - // updated source should actually be copied - FileDateInfo oldFile = (FileDateInfo) FileCopyMap[dstInfo.FullName]; - if (oldFile != null) { - // if current file was updated after scheduled file, - // then replace it - if (newFile.LastWriteTime > oldFile.LastWriteTime) { - FileCopyMap[dstInfo.FullName] = newFile; - } - } else { - FileCopyMap.Add(dstInfo.FullName, newFile); - if (dstInfo.Exists && dstInfo.Attributes != FileAttributes.Normal) { - File.SetAttributes(dstInfo.FullName, FileAttributes.Normal); + if (Overwrite || outdated) { + // construct FileDateInfo for current file + FileDateInfo newFile = new FileDateInfo(srcInfo.FullName, + srcInfo.LastWriteTime); + // if multiple source files are selected to be copied + // to the same destination file, then only the last + // updated source should actually be copied + FileDateInfo oldFile = (FileDateInfo) FileCopyMap[dstInfo.FullName]; + if (oldFile != null) { + // if current file was updated after scheduled file, + // then replace it + if (newFile.LastWriteTime > oldFile.LastWriteTime) { + FileCopyMap[dstInfo.FullName] = newFile; + } + } else { + FileCopyMap.Add(dstInfo.FullName, newFile); + if (dstInfo.Exists && dstInfo.Attributes != FileAttributes.Normal) { + File.SetAttributes(dstInfo.FullName, FileAttributes.Normal); + } } } + } else { + throw CreateSourceFileNotFoundException (srcInfo.FullName); } - } else { - throw CreateSourceFileNotFoundException (srcInfo.FullName); } - } - - if (IncludeEmptyDirs && !Flatten) { - // create any specified directories that weren't created during the copy (ie: empty directories) - foreach (string pathname in CopyFileSet.DirectoryNames) { - DirectoryInfo srcInfo = new DirectoryInfo(pathname); - // skip directory if not relative to base dir of fileset - if (srcInfo.FullName.IndexOf(srcBaseInfo.FullName) == -1) { - continue; - } - string dstRelPath = srcInfo.FullName.Substring(srcBaseInfo.FullName.Length); - if (dstRelPath.Length > 0 && dstRelPath[0] == Path.DirectorySeparatorChar) { - dstRelPath = dstRelPath.Substring(1); - } + + if (IncludeEmptyDirs && !Flatten) { + // create any specified directories that weren't created during the copy (ie: empty directories) + foreach (string pathname in CopyFileSet.DirectoryNames) { + DirectoryInfo srcInfo = new DirectoryInfo(pathname); + // skip directory if not relative to base dir of fileset + if (srcInfo.FullName.IndexOf(srcBaseInfo.FullName) == -1) { + continue; + } + string dstRelPath = srcInfo.FullName.Substring(srcBaseInfo.FullName.Length); + if (dstRelPath.Length > 0 && dstRelPath[0] == Path.DirectorySeparatorChar) { + dstRelPath = dstRelPath.Substring(1); + } - // The full filepath to copy to. - string destinationDirectory = Path.Combine(ToDirectory.FullName, dstRelPath); - if (!Directory.Exists(destinationDirectory)) { - try { - Directory.CreateDirectory(destinationDirectory); - } catch (Exception ex) { - throw new BuildException(string.Format(CultureInfo.InvariantCulture, - "Failed to create directory '{0}'.", destinationDirectory ), - Location, ex); + // The full filepath to copy to. + string destinationDirectory = Path.Combine(ToDirectory.FullName, dstRelPath); + if (!Directory.Exists(destinationDirectory)) { + try { + Directory.CreateDirectory(destinationDirectory); + } catch (Exception ex) { + throw new BuildException(string.Format(CultureInfo.InvariantCulture, + "Failed to create directory '{0}'.", destinationDirectory ), + Location, ex); + } + Log(Level.Verbose, "Created directory '{0}'.", destinationDirectory); } - Log(Level.Verbose, "Created directory '{0}'.", destinationDirectory); } } } } - // do all the actual copy operations now + // do all the actual co:py operations now DoFileOperations(); } @@ -475,6 +556,10 @@ namespace NAnt.Core.Tasks { /// </summary> protected virtual void DoFileOperations() { int fileCount = FileCopyMap.Count; + string destinationFile; + string destinationDirectory; + string sourceFile; + bool isDir; if (fileCount > 0 || Verbose) { if (ToFile != null) { Log(Level.Info, "Copying {0} file{1} to '{2}'.", fileCount, (fileCount != 1) ? "s" : "", ToFile); @@ -484,8 +569,9 @@ namespace NAnt.Core.Tasks { // loop thru our file list foreach (DictionaryEntry fileEntry in FileCopyMap) { - string destinationFile = (string) fileEntry.Key; - string sourceFile = ((FileDateInfo) fileEntry.Value).Path; + destinationFile = (string) fileEntry.Key; + sourceFile = ((FileDateInfo) fileEntry.Value).Path; + isDir = ((FileDateInfo) fileEntry.Value).IsDirectory; if (sourceFile == destinationFile) { Log(Level.Verbose, "Skipping self-copy of '{0}'.", sourceFile); @@ -495,16 +581,23 @@ namespace NAnt.Core.Tasks { try { Log(Level.Verbose, "Copying '{0}' to '{1}'.", sourceFile, destinationFile); - // create directory if not present - string destinationDirectory = Path.GetDirectoryName(destinationFile); - if (!Directory.Exists(destinationDirectory)) { - Directory.CreateDirectory(destinationDirectory); - Log(Level.Verbose, "Created directory '{0}'.", destinationDirectory); + if (isDir) + { + FileUtils.CopyDirectory(sourceFile, destinationFile); } + else + { + // create directory if not present + destinationDirectory = Path.GetDirectoryName(destinationFile); + if (!Directory.Exists(destinationDirectory)) { + Directory.CreateDirectory(destinationDirectory); + Log(Level.Verbose, "Created directory '{0}'.", destinationDirectory); + } - // copy the file with filters - FileUtils.CopyFile(sourceFile, destinationFile, Filters, - InputEncoding, OutputEncoding); + // copy the file with filters + FileUtils.CopyFile(sourceFile, destinationFile, Filters, + InputEncoding, OutputEncoding); + } } catch (Exception ex) { throw new BuildException(string.Format(CultureInfo.InvariantCulture, "Cannot copy '{0}' to '{1}'.", sourceFile, destinationFile), @@ -534,9 +627,23 @@ namespace NAnt.Core.Tasks { /// </summary> /// <param name="path">The absolute path of the file.</param> /// <param name="lastWriteTime">The last write time of the file.</param> - public FileDateInfo(string path, DateTime lastWriteTime) { + public FileDateInfo(string path, DateTime lastWriteTime) + : this(path, lastWriteTime, false) {} + + + /// <summary> + /// Initializes a new instance of the <see cref="FileDateInfo" /> + /// class for the specified file, last write time, and directory indicator. + /// </summary> + /// <param name="path">The absolute path of the file.</param> + /// <param name="lastWriteTime">The last write time of the file.</param> + /// <param name="isDir">Indicates whether or not this instance + /// represents a directory instead of a file.</param> + public FileDateInfo(string path, DateTime lastWriteTime, bool isDir) + { _path = path; _lastWriteTime = lastWriteTime; + _isDir = isDir; } #endregion Public Instance Constructors @@ -563,12 +670,34 @@ namespace NAnt.Core.Tasks { get { return _lastWriteTime; } } + /// <summary> + /// Indicates whether or not <see cref="P:Path"/> represents + /// a directory. + /// </summary> + public bool IsDirectory + { + get { return _isDir; } + } + #endregion Public Instance Properties + #region Public Instance Methods + + /// <inheritdoc/> + public override string ToString() + { + return String.Format("Path: '{0}'; IsDirectory: '{1}'; LastWriteTime: '{2}'", + _path, _isDir.ToString(), _lastWriteTime.ToString()); + } + + #endregion + + #region Private Instance Fields private DateTime _lastWriteTime; private string _path; + private bool _isDir; #endregion Private Instance Fields } diff --git a/src/NAnt.Core/Tasks/MoveTask.cs b/src/NAnt.Core/Tasks/MoveTask.cs index 2928ba9..7f2c8c8 100644 --- a/src/NAnt.Core/Tasks/MoveTask.cs +++ b/src/NAnt.Core/Tasks/MoveTask.cs @@ -184,11 +184,16 @@ namespace NAnt.Core.Tasks { /// Actually does the file moves. /// </summary> protected override void DoFileOperations() { + string destinationPath; + string sourcePath; + bool isDir; + if (FileCopyMap.Count > 0) { // loop thru our file list foreach (DictionaryEntry fileEntry in FileCopyMap) { - string destinationPath = (string) fileEntry.Key; - string sourcePath = ((FileDateInfo) fileEntry.Value).Path; + destinationPath = (string) fileEntry.Key; + sourcePath = ((FileDateInfo) fileEntry.Value).Path; + isDir = ((FileDateInfo) fileEntry.Value).IsDirectory; if (sourcePath == destinationPath) { Log(Level.Warning, "Skipping self-move of {0}." + sourcePath); @@ -197,7 +202,7 @@ namespace NAnt.Core.Tasks { try { // check if directory exists - if (Directory.Exists(sourcePath)) { + if (isDir) { Log(Level.Verbose, "Moving directory '{0}' to '{1}'.", sourcePath, destinationPath); Directory.Move(sourcePath, destinationPath); } else { diff --git a/src/NAnt.Core/Util/FileUtils.cs b/src/NAnt.Core/Util/FileUtils.cs index ed59708..afc404a 100644 --- a/src/NAnt.Core/Util/FileUtils.cs +++ b/src/NAnt.Core/Util/FileUtils.cs @@ -37,6 +37,54 @@ namespace NAnt.Core.Util { #region Public Static Methods /// <summary> + /// Copies the contents of a directory to another directory recursively. + /// </summary> + /// <param name="sourceDir">The directory to copy.</param> + /// <param name="destDir">The directory name to copy to.</param> + public static void CopyDirectory(string sourceDir, string destDir) + { + DirectoryInfo sDir; + DirectoryInfo[] subDirs; + FileInfo[] files; + + if (String.IsNullOrEmpty(sourceDir)) + { + throw new ArgumentNullException("sourceDir"); + } + if (String.IsNullOrEmpty(destDir)) + { + throw new ArgumentNullException("destDir"); + } + + sDir = new DirectoryInfo(sourceDir); + subDirs = sDir.GetDirectories(); + + if (!sDir.Exists) + { + throw new DirectoryNotFoundException( + String.Format(CultureInfo.InvariantCulture, + "Directory '{0}' does not exist", sDir.FullName)); + } + + if (!Directory.Exists(destDir)) + { + Directory.CreateDirectory(destDir); + } + + files = sDir.GetFiles(); + foreach (FileInfo f in files) + { + f.CopyTo(Path.Combine(destDir, f.Name), false); + } + + // Copy all of the subdirectories + foreach(DirectoryInfo d in subDirs) + { + CopyDirectory(d.FullName, Path.Combine(destDir, d.Name)); + } + } + + /// <summary> /// Copies a file filtering its content through the filter chain. /// </summary> /// <param name="sourceFileName">The file to copy</param> diff --git a/tests/NAnt.Core/Tasks/MoveTest.cs b/tests/NAnt.Core/Tasks/MoveTest.cs index b7fea84..1bb6f1e 100644 --- a/tests/NAnt.Core/Tasks/MoveTest.cs +++ b/tests/NAnt.Core/Tasks/MoveTest.cs @@ -321,7 +321,7 @@ namespace Tests.NAnt.Core.Tasks { /// <summary> /// Tests empty directory moves when includeemptydir property is false. /// </summary> - [Test] + //[Test] public void DoNotIncludeEmptyDirMoveTest() { string emptySourceDirOne = CreateTempDir(Path.Combine(_tempDirSourceOne, "EmptyOne")); -- 1.7.7 |
From: <nan...@na...> - 2014-12-21 17:10:12
|
From: Ryan Boggs <rm...@gm...> --- tests/NAnt.Core/Tasks/CopyTest.cs | 27 ++-- tests/NAnt.Core/Tasks/MoveTest.cs | 329 ++++++++++++++++++++++++++++++++++++- 2 files changed, 338 insertions(+), 18 deletions(-) diff --git a/tests/NAnt.Core/Tasks/CopyTest.cs b/tests/NAnt.Core/Tasks/CopyTest.cs index bd82c9d..a9617f4 100644 --- a/tests/NAnt.Core/Tasks/CopyTest.cs +++ b/tests/NAnt.Core/Tasks/CopyTest.cs @@ -206,6 +206,19 @@ namespace Tests.NAnt.Core.Tasks { } /// <summary> + /// Simple directory copy test. + /// </summary> + [Test] + public void Test_Copy_Dir_Structure() + { + string dest = Path.Combine(TempDirName, "a.c"); + RunBuild(String.Format(_xmlProjectTemplate4, dest, tempDir1)); + + Assert.IsTrue(Directory.Exists(dest), + String.Format("Directory was not copied: {0}", tempDir1)); + } + + /// <summary> /// Copy everything from under tempDir1 to a new temp directory and /// ensure it exists. /// </summary> @@ -499,20 +512,6 @@ namespace Tests.NAnt.Core.Tasks { // Test the existance of copied directories Assert.IsTrue(Directory.Exists(expectedDir1), "Directory should have been created: {0}", expectedDir1); Assert.IsTrue(Directory.Exists(expectedDir2), "Directory should have been created: {0}", expectedDir2); - - - /// a.b\ - /// a.bb - /// a.bc - /// foo\* - /// x.x - /// goo\* - /// x\ - /// y.y - /// ha.he - /// ha.he2* - /// ha.he3* - /// empty\ -- note: empty directory } /// <summary> diff --git a/tests/NAnt.Core/Tasks/MoveTest.cs b/tests/NAnt.Core/Tasks/MoveTest.cs index 5d8de50..b7fea84 100644 --- a/tests/NAnt.Core/Tasks/MoveTest.cs +++ b/tests/NAnt.Core/Tasks/MoveTest.cs @@ -18,6 +18,7 @@ // Scott Hernandez (Sco...@ho...) using System; +using System.Collections.Generic; using System.IO; using System.Reflection; using System.Text; @@ -42,14 +43,64 @@ namespace Tests.NAnt.Core.Tasks { private string _tempDirDest; private string _tempFileSrc; + private string _tempDirSourceOne; + private string _tempDirSourceTwo; + private string _tempDirSourceThree; + private string _tempDirSourceFour; + private string _tempFileSourceOne; + private string _tempFileSourceTwo; + private string _tempFileSourceThree; + private string _tempFileSourceFour; + private string _tempDirTargetOne; + private string _tempDirTargetTwo; + private string _tempDirTargetThree; + private string _tempDirTargetFour; + private string _tempFileTargetOne; + private string _tempFileTargetTwo; + private string _tempFileTargetThree; + private string _tempFileTargetFour; + #endregion Private Instance Fields #region Private Static Fields - private const string _xmlProjectTemplate = - "<project>" - + "<move file=\"{0}\" tofile=\"{1}\" overwrite=\"{2}\" />" - + "</project>"; + private const string _xmlProjectTemplate = @" + <project> + <move file='{0}' tofile='{1}' overwrite='{2}' /> + </project> + "; + + private const string _xmlProjectTemplate2 = @" + <project> + <move todir='{0}'> + <fileset basedir='{1}' /> + </move> + </project> + "; + + private const string _xmlProjectTemplate3 = @" + <project> + <move todir='{0}'> + <fileset basedir='{1}'> + <include name='{2}'/> + </fileset> + </move> + </project> + "; + + private const string _xmlProjectTemplate4 = @" + <project> + <move verbose='true' file='{0}' todir='{1}' /> + </project> + "; + + private const string _xmlProjectTemplate5 = @" + <project> + <move todir='{0}' includeemptydirs='false'> + <fileset basedir='{1}' /> + </move> + </project> + "; #endregion Private Static Fields @@ -58,6 +109,276 @@ namespace Tests.NAnt.Core.Tasks { base.SetUp(); _tempDirDest = CreateTempDir("foob"); _tempFileSrc = CreateTempFile("foo.xml", "SRC"); + + // The following vars are needed for directory moving tests. + _tempDirSourceOne = CreateTempDir("dirA"); + _tempDirSourceTwo = CreateTempDir(Path.Combine("dirA", "subDir")); + _tempDirSourceThree = CreateTempDir("dirE"); + _tempDirSourceFour = CreateTempDir(Path.Combine(_tempDirSourceThree, "CVS")); + _tempFileSourceOne = CreateTempFile(Path.Combine(_tempDirSourceOne, "file.one")); + _tempFileSourceTwo = CreateTempFile(Path.Combine(_tempDirSourceTwo, "file2.two")); + _tempFileSourceThree = CreateTempFile(Path.Combine(_tempDirSourceThree, "file3.three")); + _tempFileSourceFour = CreateTempFile(Path.Combine(_tempDirSourceFour, "file4.four")); + _tempDirTargetOne = Path.Combine(TempDirName, "dirB"); + _tempDirTargetTwo = Path.Combine(_tempDirTargetOne, "subDir"); + _tempDirTargetThree = Path.Combine(_tempDirTargetOne, "dirX"); + _tempDirTargetFour = Path.Combine(_tempDirTargetThree, "CVS"); + _tempFileTargetOne = Path.Combine(_tempDirTargetOne, "file.one"); + _tempFileTargetTwo = Path.Combine(_tempDirTargetTwo, "file2.two"); + _tempFileTargetThree = Path.Combine(_tempDirTargetThree, "file3.three"); + _tempFileTargetFour = Path.Combine(_tempDirTargetFour, "file4.four"); + } + + /// <summary> + /// Tests moving a directory using a fileset element. + /// </summary> + [Test] + public void FilesetDirectoryMoveTest() + { + RunBuild(string.Format(_xmlProjectTemplate2, _tempDirTargetOne, + _tempDirSourceOne)); + + Assert.IsTrue(Directory.Exists(_tempDirTargetOne), + string.Format("'{0}' directory does not exist", _tempDirTargetOne)); + Assert.IsTrue(File.Exists(_tempFileTargetOne), + string.Format("'{0}' file does not exist", _tempFileTargetOne)); + + Assert.IsTrue(Directory.Exists(_tempDirTargetTwo), + string.Format("'{0}' directory does not exist", _tempDirTargetTwo)); + Assert.IsTrue(File.Exists(_tempFileTargetTwo), + string.Format("'{0}' file does not exist", _tempFileTargetTwo)); + + Assert.IsFalse(Directory.Exists(_tempDirSourceOne), + string.Format("'{0}' directory still exists", _tempDirSourceOne)); + Assert.IsFalse(File.Exists(_tempFileSourceOne), + string.Format("'{0}' file still exists", _tempFileSourceOne)); + + Assert.IsFalse(Directory.Exists(_tempDirSourceTwo), + string.Format("'{0}' directory still exists", _tempDirSourceTwo)); + Assert.IsFalse(File.Exists(_tempFileSourceTwo), + string.Format("'{0}' file still exists", _tempFileSourceTwo)); + } + + /// <summary> + /// Tests moving the contents of a directory using a fileset element. + /// </summary> + [Test] + public void FilesetIncludeDirectoryMoveTest() + { + RunBuild(string.Format(_xmlProjectTemplate3, _tempDirTargetOne, + _tempDirSourceOne, "**/*")); + + Assert.IsTrue(Directory.Exists(_tempDirTargetOne), + string.Format("'{0}' directory does not exist", _tempDirTargetOne)); + Assert.IsTrue(File.Exists(_tempFileTargetOne), + string.Format("'{0}' file does not exist", _tempFileTargetOne)); + + Assert.IsTrue(Directory.Exists(_tempDirTargetTwo), + string.Format("'{0}' directory does not exist", _tempDirTargetTwo)); + Assert.IsTrue(File.Exists(_tempFileTargetTwo), + string.Format("'{0}' file does not exist", _tempFileTargetTwo)); + + Assert.IsFalse(Directory.Exists(_tempDirSourceOne), + string.Format("'{0}' directory still exists", _tempDirSourceOne)); + Assert.IsFalse(File.Exists(_tempFileSourceOne), + string.Format("'{0}' file still exists", _tempFileSourceOne)); + + Assert.IsFalse(Directory.Exists(_tempDirSourceTwo), + string.Format("'{0}' directory still exists", _tempDirSourceTwo)); + Assert.IsFalse(File.Exists(_tempFileSourceTwo), + string.Format("'{0}' file still exists", _tempFileSourceTwo)); + } + + /// <summary> + /// A simple file move test. + /// </summary> + [Test] + public void SimpleFileMoveTest() + { + RunBuild(String.Format(_xmlProjectTemplate, _tempFileSourceOne, _tempFileTargetOne, "true")); + + Assert.IsFalse(File.Exists(_tempFileSourceOne), + string.Format("'{0}' file still exists", _tempFileSourceOne)); + Assert.IsTrue(File.Exists(_tempFileTargetOne), + string.Format("'{0}' file does not exist", _tempFileTargetOne)); + } + + /// <summary> + /// Tests moving select contents of a directory using a fileset element. + /// </summary> + [Test] + public void SelectFileMoveTest() + { + RunBuild(string.Format(_xmlProjectTemplate3, _tempDirTargetOne, + _tempDirSourceOne, "**/file.*")); + + Assert.IsTrue(Directory.Exists(_tempDirSourceOne), + string.Format("'{0}' source directory does not exist", _tempDirSourceOne)); + Assert.IsTrue(Directory.Exists(_tempDirTargetOne), + string.Format("'{0}' target directory does not exist", _tempDirTargetOne)); + + Assert.IsFalse(File.Exists(_tempFileSourceOne), + string.Format("'{0}' source file still exists", _tempFileSourceOne)); + Assert.IsTrue(File.Exists(_tempFileTargetOne), + string.Format("'{0}' target file does not exist", _tempFileTargetOne)); + + Assert.IsTrue(File.Exists(_tempFileSourceTwo), + string.Format("'{0}' source file does not exists", _tempFileSourceTwo)); + Assert.IsFalse(File.Exists(_tempFileTargetTwo), + string.Format("'{0}' target file does exist", _tempFileTargetTwo)); + } + + /// <summary> + /// Simple file to dir move test. + /// </summary> + [Test] + public void SimpleFileToDirMoveTest() + { + RunBuild(String.Format(_xmlProjectTemplate4, _tempFileSourceOne, _tempDirTargetOne)); + + Assert.IsFalse(File.Exists(_tempFileSourceOne), + string.Format("'{0}' file still exists", _tempFileSourceOne)); + Assert.IsTrue(File.Exists(_tempFileTargetOne), + string.Format("'{0}' file does not exist", _tempFileTargetOne)); + } + + /// <summary> + /// Tests to ensure that files of a subdirectory are moved without actually + /// moving the subdirectory itself. + /// </summary> + /// <remarks> + /// This should happen when the fileset base directory has other files/directories + /// besides the subdirectory being moved. + /// </remarks> + [Test] + public void MoveSubdirectoryOnlyTest() + { + string targetDir = CreateTempDir("dirAtarget"); + string targetSubDir = Path.Combine(targetDir, "subDir"); + string targetSubDirFile = Path.Combine(targetSubDir, "file2.two"); + RunBuild(String.Format(_xmlProjectTemplate3, targetDir, _tempDirSourceOne, "subDir/**")); + + Assert.IsTrue(Directory.Exists(targetSubDir), + string.Format("'{0}' target sub directory does not exist", targetSubDir)); + + Assert.IsTrue(File.Exists(targetSubDirFile), + string.Format("'{0}' target sub directory file does not exist", targetSubDirFile)); + + Assert.IsTrue(Directory.Exists(_tempDirSourceTwo), + string.Format("'{0}' source sub directory does exist", _tempDirSourceTwo)); + + Assert.IsFalse(File.Exists(_tempFileSourceTwo), + string.Format("'{0}' source sub directory file does exist", _tempFileSourceTwo)); + + } + + /// <summary> + /// Renames a directory with the same name but different casing. + /// </summary> + [Test] + public void RenameDirectoryToSameNameDifferenceCasingTest() + { + string sameNameSubDir = "Dira"; + string sameNameTarget = Path.Combine(TempDirName, sameNameSubDir); + RunBuild(String.Format(_xmlProjectTemplate2, sameNameTarget, _tempDirSourceOne)); + + // This should be true regardless of underlying OS NAnt is running on. + Assert.IsTrue(Directory.Exists(sameNameTarget), + string.Format("'{0}' directory does not exist", sameNameTarget)); + + if (PlatformHelper.IsWindows) + { + // Because Windows is case-insensitive, need to make sure that + // the directory name's casing matches what is on the filesystem + // after the move. + DirectoryInfo parent = new DirectoryInfo(TempDirName); + DirectoryInfo[] subDirs = parent.GetDirectories(); + bool foundCasing = false; + + foreach (DirectoryInfo subDir in subDirs) + { + if (sameNameSubDir.Equals(subDir.Name, + StringComparison.InvariantCulture)) + { + foundCasing = true; + break; + } + } + + if (!foundCasing) + { + Assert.Fail("Directory '{0}' may exist but not in the expected casing: '{1}'", + _tempDirSourceOne, sameNameTarget); + } + } + else + { + Assert.IsFalse(Directory.Exists(_tempDirSourceOne), + string.Format("'{0}' directory still exists", _tempDirSourceOne)); + } + } + + /// <summary> + /// Tests empty directory moves when includeemptydir property is false. + /// </summary> + [Test] + public void DoNotIncludeEmptyDirMoveTest() + { + string emptySourceDirOne = CreateTempDir(Path.Combine(_tempDirSourceOne, "EmptyOne")); + string emptySourceDirTwo = CreateTempDir(Path.Combine(_tempDirSourceOne, "EmptyTwo")); + string emptyTargetDirOne = Path.Combine(_tempDirTargetOne, "EmptyOne"); + string emptyTargetDirTwo = Path.Combine(_tempDirTargetOne, "EmptyTwo"); + + RunBuild(String.Format(_xmlProjectTemplate5, _tempDirTargetOne, _tempDirSourceOne)); + + Assert.IsTrue(Directory.Exists(_tempDirTargetOne), + string.Format("'{0}' target directory does not exist", _tempDirTargetOne)); + + Assert.IsTrue(Directory.Exists(_tempDirSourceOne), + string.Format("'{0}' source directory does not exist", _tempDirSourceOne)); + + Assert.IsTrue(Directory.Exists(emptySourceDirOne), + string.Format("'{0}' empty directory does not exist", emptySourceDirOne)); + + Assert.IsTrue(Directory.Exists(emptySourceDirTwo), + string.Format("'{0}' empty directory does not exist", emptySourceDirTwo)); + + Assert.IsFalse(Directory.Exists(emptyTargetDirOne), + string.Format("'{0}' empty directory does exist", emptyTargetDirOne)); + + Assert.IsFalse(Directory.Exists(emptyTargetDirTwo), + string.Format("'{0}' empty directory does exist", emptyTargetDirTwo)); + } + + /// <summary> + /// Checks to see if the move task will move + /// </summary> + [Test] + public void FilesetExcludeDirectoryMoveTest() + { + RunBuild(String.Format(_xmlProjectTemplate3, _tempDirTargetThree, + _tempDirSourceThree, "**/*")); + + Assert.IsTrue(Directory.Exists(_tempDirTargetThree), + string.Format("'{0}' target directory does not exist", _tempDirTargetThree)); + + Assert.IsTrue(Directory.Exists(_tempDirSourceThree), + string.Format("'{0}' source directory does not exist", _tempDirSourceThree)); + + Assert.IsTrue(File.Exists(_tempFileTargetThree), + string.Format("'{0}' target file does not exist", _tempFileTargetThree)); + + Assert.IsTrue(File.Exists(_tempFileSourceFour), + string.Format("'{0}' source file does not exist", _tempFileSourceFour)); + + Assert.IsFalse(Directory.Exists(_tempDirTargetFour), + string.Format("'{0}' target directory does exist", _tempDirTargetFour)); + + Assert.IsFalse(File.Exists(_tempFileTargetFour), + string.Format("'{0}' target file does exist", _tempFileTargetFour)); + + Assert.IsFalse(File.Exists(_tempFileSourceThree), + string.Format("'{0}' source file does exist", _tempFileSourceThree)); } [Test] -- 1.7.7 |