From 3912151c7c9ffc9d1d6a0ae9e1c1d3a1ea441e1a Mon Sep 17 00:00:00 2001 From: Dominick Sidiropoulos Date: Tue, 12 Feb 2019 22:32:32 +0200 Subject: [PATCH] #286 DeleteTree: Retry on set intervals - DeleteTree.cs: Added two new properties: public int Retries { get; set; } = 0; public int RetryDelayMilliseconds { get; set; } The implementation has been enriched to switch over to try-catch-retry-mode when/if Retries > 0. --- .gitignore | 1 + .../DeleteTreeTest.cs | 79 ++++- Source/MSBuild.Community.Tasks/DeleteTree.cs | 149 +++++++-- .../Properties/Resources.Designer.cs | 297 ++++++++++-------- .../Properties/Resources.resx | 19 +- 5 files changed, 394 insertions(+), 151 deletions(-) diff --git a/.gitignore b/.gitignore index e4872dbc..164817d2 100644 --- a/.gitignore +++ b/.gitignore @@ -16,3 +16,4 @@ Test *.chm /Tools /build.txt +.vs \ No newline at end of file diff --git a/Source/MSBuild.Community.Tasks.Tests/DeleteTreeTest.cs b/Source/MSBuild.Community.Tasks.Tests/DeleteTreeTest.cs index b3b0ed6d..e6d512dc 100644 --- a/Source/MSBuild.Community.Tasks.Tests/DeleteTreeTest.cs +++ b/Source/MSBuild.Community.Tasks.Tests/DeleteTreeTest.cs @@ -1,8 +1,11 @@ using System; using System.IO; +using System.Linq; +using System.Threading; using Microsoft.Build.Framework; using Microsoft.Build.Utilities; using NUnit.Framework; +using Task = System.Threading.Tasks.Task; namespace MSBuild.Community.Tasks.Tests { @@ -14,7 +17,7 @@ public void GetDirectories() { var root = Path.GetFullPath(@"..\..\..\"); - var directories = Directory.GetDirectories(root, "*", SearchOption.AllDirectories); + var _ = Directory.GetDirectories(root, "*", SearchOption.AllDirectories); } [Test] @@ -151,5 +154,77 @@ public void MatchDirectoriesRelativeWildCard() path = DeleteTree.MatchDirectories(@"..\..\..\MSBuild.*.Tests\**\obj\**"); Assert.Greater(path.Count, 0); } + + [Test] + [Explicit] + public void DeleteWithRetriesDirectoryWhichAppearsWithDelay_ShouldSucceed() + { + //Arrange + const string fullTargetDirectoryPath = @"C:\Temp\xn_TestDirectoryWhichDoesntInitiallyExist"; + + var task = new DeleteTree + { + BuildEngine = new MockBuild(), + + Retries = 10, + RetryDelayMilliseconds = 300, + + Directories = new ITaskItem[] + { + new TaskItem(fullTargetDirectoryPath) + } + }; + + //Act + new Task(() => + { + Thread.Sleep(2000); + + Directory.CreateDirectory(fullTargetDirectoryPath); + }).Start(); + var result = task.Execute(); + + //Assert + Assert.IsTrue(result); + Assert.AreEqual(1, task.DeletedDirectories.Length); + Assert.AreEqual(fullTargetDirectoryPath, task.DeletedDirectories.FirstOrDefault().ItemSpec); + } + + [Test] + [Explicit] + public void DeleteWithRetriesDirectoryWhichDoesntAppearsAtAll_ShouldFailWithException() + { + //Arrange + const string fullTargetDirectoryPath = @"C:\Temp\xn_TestDirectoryWhichDoesntInitiallyExist"; + + var task = new DeleteTree + { + BuildEngine = new MockBuild(), + + Retries = 10, + RetryDelayMilliseconds = 300, + + Directories = new ITaskItem[] + { + new TaskItem(fullTargetDirectoryPath) + } + }; + + var exception = (Exception) null; + + //Act + try + { + task.Execute(); + } + catch (Exception ex) + { + exception = ex; + } + + //Assert + Assert.IsInstanceOf(exception); + } } -} \ No newline at end of file +} + diff --git a/Source/MSBuild.Community.Tasks/DeleteTree.cs b/Source/MSBuild.Community.Tasks/DeleteTree.cs index ed11884c..0e3c15eb 100644 --- a/Source/MSBuild.Community.Tasks/DeleteTree.cs +++ b/Source/MSBuild.Community.Tasks/DeleteTree.cs @@ -33,6 +33,7 @@ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. using System.Linq; using System.Text; using System.Text.RegularExpressions; +using System.Threading; using Microsoft.Build.Framework; using Microsoft.Build.Utilities; @@ -59,11 +60,16 @@ public class DeleteTree : Task private const string recursiveDirectoryMatch = "**"; private static readonly char[] wildcardCharacters = new[] { '*', '?' }; private static readonly char[] directorySeparatorCharacters = new[] { Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar }; - + private const string recursiveRegex = @"(?:\\.*?)*"; private const string anyCharRegex = @"[^\\]*?"; private const string singleCharRegex = @"[^\\]"; + /// + /// Default milliseconds to wait between necessary retries + /// + private const int RetryDelayMillisecondsDefault = 1000; + /// /// Initializes a new instance of the class. /// @@ -82,6 +88,21 @@ public DeleteTree() [Required] public ITaskItem[] Directories { get; set; } + /// + /// The maximum amount of times to attempt to delete the given directories, if all previous + /// attempts fail. Defaults to zero. + /// + /// + /// Warning: using Retries may mask a synchronization problem in your build process. + /// + public int Retries { get; set; } = 0; + + /// + /// Delay between any necessary retries. + /// Defaults to RetryDelayMillisecondsDefault + /// + public int RetryDelayMilliseconds { get; set; } = RetryDelayMillisecondsDefault; + /// /// Gets or sets a value indicating whether this is recursive. /// @@ -108,31 +129,117 @@ public ITaskItem[] DeletedDirectories /// public override bool Execute() { - foreach (var directory in Directories) - { - var matched = MatchDirectories(directory.ItemSpec); + if (!ValidateInputs()) + return false; - foreach (var dir in matched) + foreach (var dir in Directories.SelectMany(x => MatchDirectories(x.ItemSpec))) + { + if (Retries > 0) { - _deletedDirectories.Add(new TaskItem(dir)); + DeleteTreeImplPersistant(dir); + continue; + } - if (!Directory.Exists(dir)) - continue; + DeleteTreeImplOldSchool(dir); //oldschool approach we keep it around out of respect for backwards compatibility + } - Log.LogMessage(" Deleting Directory '{0}'", dir); - try - { - Directory.Delete(dir, Recursive); - } - catch (IOException ex) // continue to delete on the following exceptions + return true; + } + + internal void DeleteTreeImplOldSchool(string dir) //old + { + _deletedDirectories.Add(new TaskItem(dir)); + + Log.LogMessage(" Deleting Directory '{0}'", dir); + + try + { + Directory.Delete(dir, Recursive); + } + catch (DirectoryNotFoundException) //no worries + { + } + catch (IOException ex) // resume deletion on such exceptions + { + Log.LogErrorFromException(ex, false); + } + catch (UnauthorizedAccessException ex) + { + Log.LogErrorFromException(ex, false); + } + } + + internal void DeleteTreeImplPersistant(string dir) //modern + { + Log.LogMessage(" Deleting Directory '{0}'", dir); + + //if (!Directory.Exists(dir)) return; //dont + + var retries = 0; + while (true) + { + try + { + Directory.Delete(dir, Recursive); + _deletedDirectories.Add(new TaskItem(dir)); + } + catch (PathTooLongException) //no point to retry on this one + { + throw; + } + catch (ArgumentNullException) //shouldnt happen but just in case + { + throw; + } + catch (ArgumentException) //path is only whitespace or has invalid chars in it + { + throw; + } + catch (Exception ex) //directorynotfoundexception unauthorizedaccess or ioexceptions fall through here + { + if (retries < Retries) { - Log.LogErrorFromException(ex, false); + retries++; + Log.LogWarning(Properties.Resources.DeleteTreeRetrying, dir, retries, RetryDelayMilliseconds, ex.Message); + Thread.Sleep(RetryDelayMilliseconds); + continue; } - catch (UnauthorizedAccessException ex) + + if (Retries > 0) //retries >= Retries { - Log.LogErrorFromException(ex, false); + Log.LogError(Properties.Resources.DeleteTreeExceededRetries, dir, RetryDelayMilliseconds, ex.Message); + throw; } + + throw; } + + break; + } + } + + /// + /// Verify that the inputs are correct. + /// + /// False on an error, implying that the overall copy operation should be aborted. + internal bool ValidateInputs() + { + if (Retries < 0) + { + Log.LogError(Properties.Resources.DeleteTreeInvalidRetryCount, Retries); + return false; + } + + if (RetryDelayMilliseconds < 0) + { + Log.LogError(Properties.Resources.DeleteTreeInvalidRetryDelay, RetryDelayMilliseconds); + return false; + } + + if (Directories.Any(x => string.IsNullOrWhiteSpace(x.ItemSpec))) + { + Log.LogError(Properties.Resources.DeleteTreeInvalidDirectoriesPaths); + return false; } return true; @@ -144,7 +251,7 @@ internal static IList MatchDirectories(string pattern) var pathIndex = 0; // find root path with no wildcards var rootPath = FindRootPath(pathParts, out pathIndex); - + var directories = new List(128); if (pathIndex >= pathParts.Length) // no wild cards or relative directories because there are no parts left, use root { @@ -184,13 +291,13 @@ internal static IList MatchDirectories(string pattern) pathRegex.Append(singleCharRegex); } partStart = wildIndex + 1; - } + } } pathRegex.Append("$"); var searchRegex = new Regex(pathRegex.ToString(), RegexOptions.IgnoreCase); var dirs = Directory.GetDirectories(rootPath, "*", SearchOption.AllDirectories); - + directories.AddRange(dirs.Where(dir => searchRegex.IsMatch(dir))); return directories; @@ -204,7 +311,7 @@ private static string FindRootPath(string[] parts, out int pathIndex) .ToList(); var rootPath = root.Any() - ? Path.Combine(root.ToArray()) + ? string.Join(Path.DirectorySeparatorChar.ToString(), root.ToArray()) //dont use Path.Combine(root.ToArray()) here it doesnt work as intended : Environment.CurrentDirectory; if (!Path.IsPathRooted(rootPath)) diff --git a/Source/MSBuild.Community.Tasks/Properties/Resources.Designer.cs b/Source/MSBuild.Community.Tasks/Properties/Resources.Designer.cs index f1e56378..8d6a360f 100644 --- a/Source/MSBuild.Community.Tasks/Properties/Resources.Designer.cs +++ b/Source/MSBuild.Community.Tasks/Properties/Resources.Designer.cs @@ -1,10 +1,10 @@ //------------------------------------------------------------------------------ // -// 此代码由工具生成。 -// 运行时版本:4.0.30319.42000 +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 // -// 对此文件的更改可能会导致不正确的行为,并且如果 -// 重新生成代码,这些更改将会丢失。 +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. // //------------------------------------------------------------------------------ @@ -13,13 +13,13 @@ namespace MSBuild.Community.Tasks.Properties { /// - /// 一个强类型的资源类,用于查找本地化的字符串等。 + /// A strongly-typed resource class, for looking up localized strings, etc. /// - // 此类是由 StronglyTypedResourceBuilder - // 类通过类似于 ResGen 或 Visual Studio 的工具自动生成的。 - // 若要添加或移除成员,请编辑 .ResX 文件,然后重新运行 ResGen - // (以 /str 作为命令选项),或重新生成 VS 项目。 - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "15.0.0.0")] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] internal class Resources { @@ -33,7 +33,7 @@ internal Resources() { } /// - /// 返回此类使用的缓存的 ResourceManager 实例。 + /// Returns the cached ResourceManager instance used by this class. /// [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] internal static global::System.Resources.ResourceManager ResourceManager { @@ -47,8 +47,8 @@ internal Resources() { } /// - /// 使用此强类型资源类,为所有资源查找 - /// 重写当前线程的 CurrentUICulture 属性。 + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. /// [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] internal static global::System.Globalization.CultureInfo Culture { @@ -61,7 +61,7 @@ internal Resources() { } /// - /// 查找类似 Failed to lookup information for {0} in Active Directory. 的本地化字符串。 + /// Looks up a localized string similar to Failed to lookup information for {0} in Active Directory.. /// internal static string ActiveDirectoryLookupException { get { @@ -70,7 +70,7 @@ internal static string ActiveDirectoryLookupException { } /// - /// 查找类似 Attrib directory '{0}'. {1} 的本地化字符串。 + /// Looks up a localized string similar to Attrib directory '{0}'. {1}. /// internal static string AttribDirectory { get { @@ -79,7 +79,7 @@ internal static string AttribDirectory { } /// - /// 查找类似 Attrib file '{0}'. {1} 的本地化字符串。 + /// Looks up a localized string similar to Attrib file '{0}'. {1}. /// internal static string AttribFile { get { @@ -88,7 +88,7 @@ internal static string AttribFile { } /// - /// 查找类似 Couldn't connect to remove server. 的本地化字符串。 + /// Looks up a localized string similar to Couldn't connect to remove server.. /// internal static string CouldNotConnectToRemoteServer { get { @@ -97,7 +97,7 @@ internal static string CouldNotConnectToRemoteServer { } /// - /// 查找类似 Couldn't resolve server host name {0}. 的本地化字符串。 + /// Looks up a localized string similar to Couldn't resolve server host name {0}.. /// internal static string CouldNotResolveServerHostName { get { @@ -106,7 +106,7 @@ internal static string CouldNotResolveServerHostName { } /// - /// 查找类似 Creating directory "{0}". 的本地化字符串。 + /// Looks up a localized string similar to Creating directory "{0}".. /// internal static string CreatingDirectory { get { @@ -115,7 +115,52 @@ internal static string CreatingDirectory { } /// - /// 查找类似 Both "{0}" and "{1}" were specified as input parameters in the project file. Please choose one or the other. 的本地化字符串。 + /// Looks up a localized string similar to Could not delete "{0}". Exceeded retry count of {1}. Failed. {2}. + /// + internal static string DeleteTreeExceededRetries { + get { + return ResourceManager.GetString("DeleteTreeExceededRetries", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to One or more of the directory-paths specified is null or full of whitespaces.. + /// + internal static string DeleteTreeInvalidDirectoriesPaths { + get { + return ResourceManager.GetString("DeleteTreeInvalidDirectoriesPaths", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} is an invalid retry count. Value must not be negative.. + /// + internal static string DeleteTreeInvalidRetryCount { + get { + return ResourceManager.GetString("DeleteTreeInvalidRetryCount", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} is an invalid retry delay. Value must not be negative.. + /// + internal static string DeleteTreeInvalidRetryDelay { + get { + return ResourceManager.GetString("DeleteTreeInvalidRetryDelay", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Could delete "{0}". Beginning retry {1} in {2}ms. {3}. + /// + internal static string DeleteTreeRetrying { + get { + return ResourceManager.GetString("DeleteTreeRetrying", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Both "{0}" and "{1}" were specified as input parameters in the project file. Please choose one or the other.. /// internal static string ExactlyOneTypeOfDestination { get { @@ -124,7 +169,7 @@ internal static string ExactlyOneTypeOfDestination { } /// - /// 查找类似 File Not Found: {0} 的本地化字符串。 + /// Looks up a localized string similar to File Not Found: {0}. /// internal static string FileNotFound { get { @@ -133,7 +178,7 @@ internal static string FileNotFound { } /// - /// 查找类似 Local File Not Found: {0} 的本地化字符串。 + /// Looks up a localized string similar to Local File Not Found: {0}. /// internal static string FtpLocalNotFound { get { @@ -142,7 +187,7 @@ internal static string FtpLocalNotFound { } /// - /// 查找类似 {0}% Complete ({1}) 的本地化字符串。 + /// Looks up a localized string similar to {0}% Complete ({1}). /// internal static string FtpPercentComplete { get { @@ -151,7 +196,7 @@ internal static string FtpPercentComplete { } /// - /// 查找类似 Transfered {0} ({1}) in {2} 的本地化字符串。 + /// Looks up a localized string similar to Transfered {0} ({1}) in {2}. /// internal static string FtpTransfered { get { @@ -160,7 +205,7 @@ internal static string FtpTransfered { } /// - /// 查找类似 Upload File Complete, {0} 的本地化字符串。 + /// Looks up a localized string similar to Upload File Complete, {0}. /// internal static string FtpUploadComplete { get { @@ -169,9 +214,9 @@ internal static string FtpUploadComplete { } /// - /// 查找类似 Uploading "{0}" + /// Looks up a localized string similar to Uploading "{0}" /// to "{1}" - /// 的本地化字符串。 + ///. /// internal static string FtpUploading { get { @@ -180,7 +225,7 @@ internal static string FtpUploading { } /// - /// 查找类似 The URI "{0}" scheme is not valid. 的本地化字符串。 + /// Looks up a localized string similar to The URI "{0}" scheme is not valid.. /// internal static string FtpUriInvalid { get { @@ -189,7 +234,7 @@ internal static string FtpUriInvalid { } /// - /// 查找类似 Compressed by {0}, from {1} to {2} byte(s) 的本地化字符串。 + /// Looks up a localized string similar to Compressed by {0}, from {1} to {2} byte(s). /// internal static string JSCompressCompressed { get { @@ -198,7 +243,7 @@ internal static string JSCompressCompressed { } /// - /// 查找类似 Compressing JavaScript in "{0}". 的本地化字符串。 + /// Looks up a localized string similar to Compressing JavaScript in "{0}".. /// internal static string JSCompressCompressing { get { @@ -207,7 +252,7 @@ internal static string JSCompressCompressing { } /// - /// 查找类似 Writing compressed JavaScript back to "{0}" using {1}. 的本地化字符串。 + /// Looks up a localized string similar to Writing compressed JavaScript back to "{0}" using {1}.. /// internal static string JSCompressWriting { get { @@ -216,7 +261,7 @@ internal static string JSCompressWriting { } /// - /// 查找类似 Emailing "{0}". 的本地化字符串。 + /// Looks up a localized string similar to Emailing "{0}".. /// internal static string MailEmailing { get { @@ -225,7 +270,7 @@ internal static string MailEmailing { } /// - /// 查找类似 "{0}" is not a number. 的本地化字符串。 + /// Looks up a localized string similar to "{0}" is not a number.. /// internal static string MathNotNumber { get { @@ -234,7 +279,7 @@ internal static string MathNotNumber { } /// - /// 查找类似 Merge Complete: {0} files merged into '{1}'. 的本地化字符串。 + /// Looks up a localized string similar to Merge Complete: {0} files merged into '{1}'.. /// internal static string MergeComplete { get { @@ -243,7 +288,7 @@ internal static string MergeComplete { } /// - /// 查找类似 Merge Complete: No source files to merge. 的本地化字符串。 + /// Looks up a localized string similar to Merge Complete: No source files to merge.. /// internal static string MergeCompleteNoSourceFiles { get { @@ -252,7 +297,7 @@ internal static string MergeCompleteNoSourceFiles { } /// - /// 查找类似 Merging file '{0}' into '{1}' 的本地化字符串。 + /// Looks up a localized string similar to Merging file '{0}' into '{1}'. /// internal static string MergingFile { get { @@ -261,7 +306,7 @@ internal static string MergingFile { } /// - /// 查找类似 Unable to move file "{0}" to "{1}". {2} 的本地化字符串。 + /// Looks up a localized string similar to Unable to move file "{0}" to "{1}". {2}. /// internal static string MoveError { get { @@ -270,7 +315,7 @@ internal static string MoveError { } /// - /// 查找类似 Moving file from "{0}" to "{1}". 的本地化字符串。 + /// Looks up a localized string similar to Moving file from "{0}" to "{1}".. /// internal static string MoveFileComment { get { @@ -279,7 +324,7 @@ internal static string MoveFileComment { } /// - /// 查找类似 Could not find the NUnit Project File open command. Please make sure NUnit is installed. 的本地化字符串。 + /// Looks up a localized string similar to Could not find the NUnit Project File open command. Please make sure NUnit is installed.. /// internal static string NUnitNotFound { get { @@ -288,7 +333,7 @@ internal static string NUnitNotFound { } /// - /// 查找类似 Checking Oracle Home: {0} 的本地化字符串。 + /// Looks up a localized string similar to Checking Oracle Home: {0}. /// internal static string OracleHomeCheck { get { @@ -297,7 +342,7 @@ internal static string OracleHomeCheck { } /// - /// 查找类似 The parameter "{1}" does not apply to the current use of task "{0}". 的本地化字符串。 + /// Looks up a localized string similar to The parameter "{1}" does not apply to the current use of task "{0}".. /// internal static string ParameterNotUsed { get { @@ -306,7 +351,7 @@ internal static string ParameterNotUsed { } /// - /// 查找类似 The "{0}" task was not given a value for the required parameter "{1}". 的本地化字符串。 + /// Looks up a localized string similar to The "{0}" task was not given a value for the required parameter "{1}".. /// internal static string ParameterRequired { get { @@ -315,7 +360,7 @@ internal static string ParameterRequired { } /// - /// 查找类似 Read Windows Registry 的本地化字符串。 + /// Looks up a localized string similar to Read Windows Registry. /// internal static string RegistryRead { get { @@ -324,7 +369,7 @@ internal static string RegistryRead { } /// - /// 查找类似 Write Windows Registry 的本地化字符串。 + /// Looks up a localized string similar to Write Windows Registry. /// internal static string RegistryWrite { get { @@ -333,7 +378,7 @@ internal static string RegistryWrite { } /// - /// 查找类似 Cannot continue service {0} on computer '{1}' as it does not support the pause and continue. 的本地化字符串。 + /// Looks up a localized string similar to Cannot continue service {0} on computer '{1}' as it does not support the pause and continue.. /// internal static string ServiceCannotContinue { get { @@ -342,7 +387,7 @@ internal static string ServiceCannotContinue { } /// - /// 查找类似 Cannot pause service {0} on computer '{1}' as it does not support the pause and continue. 的本地化字符串。 + /// Looks up a localized string similar to Cannot pause service {0} on computer '{1}' as it does not support the pause and continue.. /// internal static string ServiceCannotPause { get { @@ -351,7 +396,7 @@ internal static string ServiceCannotPause { } /// - /// 查找类似 Cannot stop service {0} on computer '{1}'. 的本地化字符串。 + /// Looks up a localized string similar to Cannot stop service {0} on computer '{1}'.. /// internal static string ServiceCannotStop { get { @@ -360,7 +405,7 @@ internal static string ServiceCannotStop { } /// - /// 查找类似 {0} service was continued successfully. 的本地化字符串。 + /// Looks up a localized string similar to {0} service was continued successfully.. /// internal static string ServiceContinued { get { @@ -369,7 +414,7 @@ internal static string ServiceContinued { } /// - /// 查找类似 {0} service is continuing ... 的本地化字符串。 + /// Looks up a localized string similar to {0} service is continuing .... /// internal static string ServiceContinuing { get { @@ -378,7 +423,7 @@ internal static string ServiceContinuing { } /// - /// 查找类似 Couldn't find the '{0}' service on '{1}' 的本地化字符串。 + /// Looks up a localized string similar to Couldn't find the '{0}' service on '{1}'. /// internal static string ServiceNotFound { get { @@ -387,7 +432,7 @@ internal static string ServiceNotFound { } /// - /// 查找类似 Cannot continue service {0} on computer '{1}' as its not currently paused. 的本地化字符串。 + /// Looks up a localized string similar to Cannot continue service {0} on computer '{1}' as its not currently paused.. /// internal static string ServiceNotPaused { get { @@ -396,7 +441,7 @@ internal static string ServiceNotPaused { } /// - /// 查找类似 Cannot pause service {0} on computer '{1}' as its not currently started. 的本地化字符串。 + /// Looks up a localized string similar to Cannot pause service {0} on computer '{1}' as its not currently started.. /// internal static string ServiceNotStarted { get { @@ -405,7 +450,7 @@ internal static string ServiceNotStarted { } /// - /// 查找类似 {0} service was paused successfully. 的本地化字符串。 + /// Looks up a localized string similar to {0} service was paused successfully.. /// internal static string ServicePaused { get { @@ -414,7 +459,7 @@ internal static string ServicePaused { } /// - /// 查找类似 {0} service is pausing ... 的本地化字符串。 + /// Looks up a localized string similar to {0} service is pausing .... /// internal static string ServicePausing { get { @@ -423,7 +468,7 @@ internal static string ServicePausing { } /// - /// 查找类似 {0} service was started successfully. 的本地化字符串。 + /// Looks up a localized string similar to {0} service was started successfully.. /// internal static string ServiceStarted { get { @@ -432,7 +477,7 @@ internal static string ServiceStarted { } /// - /// 查找类似 {0} service is starting ... 的本地化字符串。 + /// Looks up a localized string similar to {0} service is starting .... /// internal static string ServiceStarting { get { @@ -441,7 +486,7 @@ internal static string ServiceStarting { } /// - /// 查找类似 The '{0}' service on '{1}' is '{2}'. 的本地化字符串。 + /// Looks up a localized string similar to The '{0}' service on '{1}' is '{2}'.. /// internal static string ServiceStatus { get { @@ -450,7 +495,7 @@ internal static string ServiceStatus { } /// - /// 查找类似 {0} service was stopped successfully. 的本地化字符串。 + /// Looks up a localized string similar to {0} service was stopped successfully.. /// internal static string ServiceStopped { get { @@ -459,7 +504,7 @@ internal static string ServiceStopped { } /// - /// 查找类似 {0} service is stopping ... 的本地化字符串。 + /// Looks up a localized string similar to {0} service is stopping .... /// internal static string ServiceStopping { get { @@ -468,7 +513,7 @@ internal static string ServiceStopping { } /// - /// 查找类似 Solution file "{0}" not found. 的本地化字符串。 + /// Looks up a localized string similar to Solution file "{0}" not found.. /// internal static string SolutionNotFound { get { @@ -477,7 +522,7 @@ internal static string SolutionNotFound { } /// - /// 查找类似 LocalPath is not a working subversion copy. 的本地化字符串。 + /// Looks up a localized string similar to LocalPath is not a working subversion copy.. /// internal static string SvnLocalPathNotWorkCopy { get { @@ -486,7 +531,7 @@ internal static string SvnLocalPathNotWorkCopy { } /// - /// 查找类似 Could not {0} the file "{1}" to the destination file "{2}", because the destination is a folder instead of a file. To {0} the source file into a folder, consider using the DestinationFolder parameter instead of DestinationFiles. 的本地化字符串。 + /// Looks up a localized string similar to Could not {0} the file "{1}" to the destination file "{2}", because the destination is a folder instead of a file. To {0} the source file into a folder, consider using the DestinationFolder parameter instead of DestinationFiles.. /// internal static string TaskDestinationIsDirectory { get { @@ -495,7 +540,7 @@ internal static string TaskDestinationIsDirectory { } /// - /// 查找类似 No destination specified for {0}. Please supply either "{1}" or "{2}". 的本地化字符串。 + /// Looks up a localized string similar to No destination specified for {0}. Please supply either "{1}" or "{2}".. /// internal static string TaskNeedsDestination { get { @@ -504,7 +549,7 @@ internal static string TaskNeedsDestination { } /// - /// 查找类似 The source file "{0}" is actually a directory. The "{1}" task does not support moving directories. 的本地化字符串。 + /// Looks up a localized string similar to The source file "{0}" is actually a directory. The "{1}" task does not support moving directories.. /// internal static string TaskSourceIsDirectory { get { @@ -513,7 +558,7 @@ internal static string TaskSourceIsDirectory { } /// - /// 查找类似 Failed to get current date! 的本地化字符串。 + /// Looks up a localized string similar to Failed to get current date!. /// internal static string TimeFormatException { get { @@ -522,7 +567,7 @@ internal static string TimeFormatException { } /// - /// 查找类似 Getting current date. 的本地化字符串。 + /// Looks up a localized string similar to Getting current date.. /// internal static string TimeGettingCurrentDate { get { @@ -531,7 +576,7 @@ internal static string TimeGettingCurrentDate { } /// - /// 查找类似 Adding TNSNAMES entry "{0}" to "{1}" 的本地化字符串。 + /// Looks up a localized string similar to Adding TNSNAMES entry "{0}" to "{1}". /// internal static string TnsnameAdded { get { @@ -540,7 +585,7 @@ internal static string TnsnameAdded { } /// - /// 查找类似 Looking for {0} 的本地化字符串。 + /// Looks up a localized string similar to Looking for {0}. /// internal static string TnsNamesFileCheck { get { @@ -549,7 +594,7 @@ internal static string TnsNamesFileCheck { } /// - /// 查找类似 Unable to locate a TNSNAMES.ORA file. Please specify a value for TnsNamesFile. 的本地化字符串。 + /// Looks up a localized string similar to Unable to locate a TNSNAMES.ORA file. Please specify a value for TnsNamesFile.. /// internal static string TnsNamesFileNotFound { get { @@ -558,7 +603,7 @@ internal static string TnsNamesFileNotFound { } /// - /// 查找类似 TNSNAME entry "{0}" already exists in "{1}" and AllowUpdates=false. 的本地化字符串。 + /// Looks up a localized string similar to TNSNAME entry "{0}" already exists in "{1}" and AllowUpdates=false.. /// internal static string TnsnameUpdateAborted { get { @@ -567,7 +612,7 @@ internal static string TnsnameUpdateAborted { } /// - /// 查找类似 Updating TNSNAMES entry "{0}" in "{1}" 的本地化字符串。 + /// Looks up a localized string similar to Updating TNSNAMES entry "{0}" in "{1}". /// internal static string TnsnameUpdated { get { @@ -576,7 +621,7 @@ internal static string TnsnameUpdated { } /// - /// 查找类似 "{2}" refers to {0} item(s), and "{3}" refers to {1} item(s). They must have the same number of items. 的本地化字符串。 + /// Looks up a localized string similar to "{2}" refers to {0} item(s), and "{3}" refers to {1} item(s). They must have the same number of items.. /// internal static string TwoVectorsMustHaveSameLength { get { @@ -585,7 +630,7 @@ internal static string TwoVectorsMustHaveSameLength { } /// - /// 查找类似 extracted "{0}" 的本地化字符串。 + /// Looks up a localized string similar to extracted "{0}". /// internal static string UnzipExtracted { get { @@ -594,9 +639,9 @@ internal static string UnzipExtracted { } /// - /// 查找类似 Unzip File "{0}" + /// Looks up a localized string similar to Unzip File "{0}" /// to Directory "{1}" - /// 的本地化字符串。 + ///. /// internal static string UnzipFileToDirectory { get { @@ -605,7 +650,7 @@ internal static string UnzipFileToDirectory { } /// - /// 查找类似 Unzipped file "{0}" successfully. 的本地化字符串。 + /// Looks up a localized string similar to Unzipped file "{0}" successfully.. /// internal static string UnzipSuccessfully { get { @@ -614,7 +659,7 @@ internal static string UnzipSuccessfully { } /// - /// 查找类似 Commitment of change set failed! 的本地化字符串。 + /// Looks up a localized string similar to Commitment of change set failed!. /// internal static string VaultAddFileCommitFailed { get { @@ -623,7 +668,7 @@ internal static string VaultAddFileCommitFailed { } /// - /// 查找类似 Files added to Vault repository successfully. 的本地化字符串。 + /// Looks up a localized string similar to Files added to Vault repository successfully.. /// internal static string VaultAddFileCommitSucceeded { get { @@ -632,7 +677,7 @@ internal static string VaultAddFileCommitSucceeded { } /// - /// 查找类似 Files specified for addition to repository cannot be found. 的本地化字符串。 + /// Looks up a localized string similar to Files specified for addition to repository cannot be found.. /// internal static string VaultAddFilesException { get { @@ -641,7 +686,7 @@ internal static string VaultAddFilesException { } /// - /// 查找类似 The file {0} could not be checked in: {1}. 的本地化字符串。 + /// Looks up a localized string similar to The file {0} could not be checked in: {1}.. /// internal static string VaultCheckinFileException { get { @@ -650,7 +695,7 @@ internal static string VaultCheckinFileException { } /// - /// 查找类似 File or folder {0} not found for checkin. 的本地化字符串。 + /// Looks up a localized string similar to File or folder {0} not found for checkin.. /// internal static string VaultCheckinFileNotFoundException { get { @@ -659,7 +704,7 @@ internal static string VaultCheckinFileNotFoundException { } /// - /// 查找类似 The folder {0} could not be checked in: {1}. 的本地化字符串。 + /// Looks up a localized string similar to The folder {0} could not be checked in: {1}.. /// internal static string VaultCheckinFolderException { get { @@ -668,7 +713,7 @@ internal static string VaultCheckinFolderException { } /// - /// 查找类似 {0} successfully checked out. 的本地化字符串。 + /// Looks up a localized string similar to {0} successfully checked out.. /// internal static string VaultCheckinSuccessful { get { @@ -677,7 +722,7 @@ internal static string VaultCheckinSuccessful { } /// - /// 查找类似 {0} successfully checked out. 的本地化字符串。 + /// Looks up a localized string similar to {0} successfully checked out.. /// internal static string VaultCheckoutSuccessful { get { @@ -686,7 +731,7 @@ internal static string VaultCheckoutSuccessful { } /// - /// 查找类似 Specified diskfile {0} does not exist. 的本地化字符串。 + /// Looks up a localized string similar to Specified diskfile {0} does not exist.. /// internal static string VaultDiskFileDoesNotExist { get { @@ -695,7 +740,7 @@ internal static string VaultDiskFileDoesNotExist { } /// - /// 查找类似 File [{0}] added to change set. 的本地化字符串。 + /// Looks up a localized string similar to File [{0}] added to change set.. /// internal static string VaultFileAddedToChangeSet { get { @@ -704,7 +749,7 @@ internal static string VaultFileAddedToChangeSet { } /// - /// 查找类似 Folder [{0}] added to change set. 的本地化字符串。 + /// Looks up a localized string similar to Folder [{0}] added to change set.. /// internal static string VaultFolderAddedToChangeSet { get { @@ -713,7 +758,7 @@ internal static string VaultFolderAddedToChangeSet { } /// - /// 查找类似 Incorrect parameters passed to VaultSession. 的本地化字符串。 + /// Looks up a localized string similar to Incorrect parameters passed to VaultSession.. /// internal static string VaultIncorrectParameters { get { @@ -722,7 +767,7 @@ internal static string VaultIncorrectParameters { } /// - /// 查找类似 Login to Vault repository failed. 的本地化字符串。 + /// Looks up a localized string similar to Login to Vault repository failed.. /// internal static string VaultLoginFailed { get { @@ -731,7 +776,7 @@ internal static string VaultLoginFailed { } /// - /// 查找类似 Error validating path "{0}". 的本地化字符串。 + /// Looks up a localized string similar to Error validating path "{0}".. /// internal static string VaultPathValidationException { get { @@ -740,7 +785,7 @@ internal static string VaultPathValidationException { } /// - /// 查找类似 Selection of the repository failed: {0}. 的本地化字符串。 + /// Looks up a localized string similar to Selection of the repository failed: {0}.. /// internal static string VaultRepositorySelectionFailure { get { @@ -749,7 +794,7 @@ internal static string VaultRepositorySelectionFailure { } /// - /// 查找类似 File or folder {0} not found for checkout. 的本地化字符串。 + /// Looks up a localized string similar to File or folder {0} not found for checkout.. /// internal static string VaultResourceNotFound { get { @@ -758,7 +803,7 @@ internal static string VaultResourceNotFound { } /// - /// 查找类似 Set working folder for {0} to {1} from {2}. 的本地化字符串。 + /// Looks up a localized string similar to Set working folder for {0} to {1} from {2}.. /// internal static string VaultSetNewWorkingFolder { get { @@ -767,7 +812,7 @@ internal static string VaultSetNewWorkingFolder { } /// - /// 查找类似 ClientInstance.TreeCache has not been initialized, Common cause is that SelectRepository has not been called sucessfully. 的本地化字符串。 + /// Looks up a localized string similar to ClientInstance.TreeCache has not been initialized, Common cause is that SelectRepository has not been called sucessfully.. /// internal static string VaultTreeCacheFailure { get { @@ -776,7 +821,7 @@ internal static string VaultTreeCacheFailure { } /// - /// 查找类似 Successfully undid check out for {0}. 的本地化字符串。 + /// Looks up a localized string similar to Successfully undid check out for {0}.. /// internal static string VaultUndoCheckoutSuccessful { get { @@ -785,7 +830,7 @@ internal static string VaultUndoCheckoutSuccessful { } /// - /// 查找类似 Url specifying vault location is required. 的本地化字符串。 + /// Looks up a localized string similar to Url specifying vault location is required.. /// internal static string VaultUrlRequired { get { @@ -794,7 +839,7 @@ internal static string VaultUrlRequired { } /// - /// 查找类似 Username must be set to access repository. 的本地化字符串。 + /// Looks up a localized string similar to Username must be set to access repository.. /// internal static string VaultUsernameRequired { get { @@ -803,7 +848,7 @@ internal static string VaultUsernameRequired { } /// - /// 查找类似 Clearing working folder for {0}. 的本地化字符串。 + /// Looks up a localized string similar to Clearing working folder for {0}.. /// internal static string VaultWorkingFolderCleared { get { @@ -812,7 +857,7 @@ internal static string VaultWorkingFolderCleared { } /// - /// 查找类似 Restoring working folder for {0} to {1}. 的本地化字符串。 + /// Looks up a localized string similar to Restoring working folder for {0} to {1}.. /// internal static string VaultWorkingFolderRestored { get { @@ -821,7 +866,7 @@ internal static string VaultWorkingFolderRestored { } /// - /// 查找类似 Version file "{0}" not found - creating new file. 的本地化字符串。 + /// Looks up a localized string similar to Version file "{0}" not found - creating new file.. /// internal static string VersionFileNotFound { get { @@ -830,7 +875,7 @@ internal static string VersionFileNotFound { } /// - /// 查找类似 Updated to version {0} 的本地化字符串。 + /// Looks up a localized string similar to Updated to version {0}. /// internal static string VersionModifiedValue { get { @@ -839,7 +884,7 @@ internal static string VersionModifiedValue { } /// - /// 查找类似 Initialized to version {0} 的本地化字符串。 + /// Looks up a localized string similar to Initialized to version {0}. /// internal static string VersionOriginalValue { get { @@ -848,7 +893,7 @@ internal static string VersionOriginalValue { } /// - /// 查找类似 Reading version from file "{0}". 的本地化字符串。 + /// Looks up a localized string similar to Reading version from file "{0}".. /// internal static string VersionRead { get { @@ -857,7 +902,7 @@ internal static string VersionRead { } /// - /// 查找类似 Unable to read version number from "{0}". {1} 的本地化字符串。 + /// Looks up a localized string similar to Unable to read version number from "{0}". {1}. /// internal static string VersionReadException { get { @@ -866,7 +911,7 @@ internal static string VersionReadException { } /// - /// 查找类似 Unable to write version number to "{0}". {1}" 的本地化字符串。 + /// Looks up a localized string similar to Unable to write version number to "{0}". {1}". /// internal static string VersionWriteException { get { @@ -875,7 +920,7 @@ internal static string VersionWriteException { } /// - /// 查找类似 Wrote version to file "{0}". 的本地化字符串。 + /// Looks up a localized string similar to Wrote version to file "{0}".. /// internal static string VersionWrote { get { @@ -884,7 +929,7 @@ internal static string VersionWrote { } /// - /// 查找类似 Web directory {0} does not exist on {1}. 的本地化字符串。 + /// Looks up a localized string similar to Web directory {0} does not exist on {1}.. /// internal static string WebDirectoryInvalidDirectory { get { @@ -893,7 +938,7 @@ internal static string WebDirectoryInvalidDirectory { } /// - /// 查找类似 Setting scriptmap for {0} on web directory {1} on {2}. 的本地化字符串。 + /// Looks up a localized string similar to Setting scriptmap for {0} on web directory {1} on {2}.. /// internal static string WebDirectoryScriptMapUpdate { get { @@ -902,7 +947,7 @@ internal static string WebDirectoryScriptMapUpdate { } /// - /// 查找类似 Web directory {0} on {1} does not have a setting called {2}. 的本地化字符串。 + /// Looks up a localized string similar to Web directory {0} on {1} does not have a setting called {2}.. /// internal static string WebDirectorySettingInvalidSetting { get { @@ -911,7 +956,7 @@ internal static string WebDirectorySettingInvalidSetting { } /// - /// 查找类似 Reading {0} property of web directory {1} on {2}. 的本地化字符串。 + /// Looks up a localized string similar to Reading {0} property of web directory {1} on {2}.. /// internal static string WebDirectorySettingStatusRead { get { @@ -920,7 +965,7 @@ internal static string WebDirectorySettingStatusRead { } /// - /// 查找类似 Setting {0} property of web directory {1} on {2}. 的本地化字符串。 + /// Looks up a localized string similar to Setting {0} property of web directory {1} on {2}.. /// internal static string WebDirectorySettingStatusSet { get { @@ -929,7 +974,7 @@ internal static string WebDirectorySettingStatusSet { } /// - /// 查找类似 Reading Xml Document "{0}". 的本地化字符串。 + /// Looks up a localized string similar to Reading Xml Document "{0}".. /// internal static string XmlReadDocument { get { @@ -938,7 +983,7 @@ internal static string XmlReadDocument { } /// - /// 查找类似 {0} node(s) selected for read. 的本地化字符串。 + /// Looks up a localized string similar to {0} node(s) selected for read.. /// internal static string XmlReadNodes { get { @@ -947,7 +992,7 @@ internal static string XmlReadNodes { } /// - /// 查找类似 XmlRead Result: "{0}" 的本地化字符串。 + /// Looks up a localized string similar to XmlRead Result: "{0}". /// internal static string XmlReadResult { get { @@ -956,7 +1001,7 @@ internal static string XmlReadResult { } /// - /// 查找类似 Updating Xml Document "{0}". 的本地化字符串。 + /// Looks up a localized string similar to Updating Xml Document "{0}".. /// internal static string XmlUpdateDocument { get { @@ -965,7 +1010,7 @@ internal static string XmlUpdateDocument { } /// - /// 查找类似 {0} node(s) selected for update. 的本地化字符串。 + /// Looks up a localized string similar to {0} node(s) selected for update.. /// internal static string XmlUpdateNodes { get { @@ -974,7 +1019,7 @@ internal static string XmlUpdateNodes { } /// - /// 查找类似 XmlUpdate Wrote: "{0}". 的本地化字符串。 + /// Looks up a localized string similar to XmlUpdate Wrote: "{0}".. /// internal static string XmlUpdateResult { get { @@ -983,7 +1028,7 @@ internal static string XmlUpdateResult { } /// - /// 查找类似 Adding Parameter "{0}": "{1}". 的本地化字符串。 + /// Looks up a localized string similar to Adding Parameter "{0}": "{1}".. /// internal static string XsltAddingParameter { get { @@ -992,7 +1037,7 @@ internal static string XsltAddingParameter { } /// - /// 查找类似 Adding root attribute {0}="{1}". 的本地化字符串。 + /// Looks up a localized string similar to Adding root attribute {0}="{1}".. /// internal static string XsltAddingRootAttribute { get { @@ -1001,7 +1046,7 @@ internal static string XsltAddingRootAttribute { } /// - /// 查找类似 Creating root tag "{0}". 的本地化字符串。 + /// Looks up a localized string similar to Creating root tag "{0}".. /// internal static string XsltCreatingRootTag { get { @@ -1010,7 +1055,7 @@ internal static string XsltCreatingRootTag { } /// - /// 查找类似 No input files. 的本地化字符串。 + /// Looks up a localized string similar to No input files.. /// internal static string XsltNoInputFiles { get { @@ -1019,7 +1064,7 @@ internal static string XsltNoInputFiles { } /// - /// 查找类似 No root tag inserted. 的本地化字符串。 + /// Looks up a localized string similar to No root tag inserted.. /// internal static string XsltNoRootTag { get { @@ -1028,7 +1073,7 @@ internal static string XsltNoRootTag { } /// - /// 查找类似 added "{0}". 的本地化字符串。 + /// Looks up a localized string similar to added "{0}".. /// internal static string ZipAdded { get { @@ -1037,7 +1082,7 @@ internal static string ZipAdded { } /// - /// 查找类似 Creating zip file "{0}". 的本地化字符串。 + /// Looks up a localized string similar to Creating zip file "{0}".. /// internal static string ZipCreating { get { @@ -1046,7 +1091,7 @@ internal static string ZipCreating { } /// - /// 查找类似 Zip File Not Found: {0}. 的本地化字符串。 + /// Looks up a localized string similar to Zip File Not Found: {0}.. /// internal static string ZipFileNotFound { get { @@ -1055,7 +1100,7 @@ internal static string ZipFileNotFound { } /// - /// 查找类似 Created zip file "{0}" successfully. 的本地化字符串。 + /// Looks up a localized string similar to Created zip file "{0}" successfully.. /// internal static string ZipSuccessfully { get { diff --git a/Source/MSBuild.Community.Tasks/Properties/Resources.resx b/Source/MSBuild.Community.Tasks/Properties/Resources.resx index 1b13d9b6..ce613963 100644 --- a/Source/MSBuild.Community.Tasks/Properties/Resources.resx +++ b/Source/MSBuild.Community.Tasks/Properties/Resources.resx @@ -112,10 +112,10 @@ 2.0 - System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 Attrib directory '{0}'. {1} @@ -456,4 +456,19 @@ Merging file '{0}' into '{1}' + + Could not delete "{0}". Exceeded retry count of {1}. Failed. {2} + + + One or more of the directory-paths specified is null or full of whitespaces. + + + {0} is an invalid retry count. Value must not be negative. + + + {0} is an invalid retry delay. Value must not be negative. + + + Could delete "{0}". Beginning retry {1} in {2}ms. {3} + \ No newline at end of file