|
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
///--------------------------------------------------------------------------------------------
/// CommonUtility.cs
///
/// Common utility function
///
/// Copyright(c) 2006 Microsoft Corporation
///--------------------------------------------------------------------------------------------
using System.Diagnostics;
using System.Reflection;
using System.Xml;
using Microsoft.NET.Sdk.Publish.Tasks.Properties;
using CultureInfo = System.Globalization.CultureInfo;
using Framework = Microsoft.Build.Framework;
using RegularExpressions = System.Text.RegularExpressions;
using Utilities = Microsoft.Build.Utilities;
namespace Microsoft.NET.Sdk.Publish.Tasks.MsDeploy
{
internal enum PipelineMetadata
{
//<ItemDefinitionGroup>
// <FilesForPackagingFromProject>
// <DestinationRelativePath></DestinationRelativePath>
// <Exclude>False</Exclude>
// <FromTarget>Unknown</FromTarget>
// <Category>Run</Category>
// </FilesForPackagingFromProject>
//</ItemDefinitionGroup>
DestinationRelativePath,
Exclude,
FromTarget,
Category,
};
internal enum ReplaceRuleMetadata
{
//<ItemDefinitionGroup>
// <MsDeployReplaceRules>
// <ObjectName></ObjectName>
// <ScopeAttributeName></ScopeAttributeName>
// <ScopeAttributeValue></ScopeAttributeValue>
// <TargetAttributeName></TargetAttributeName>
// <Match></Match>
// <Replace></Replace>
// </MsDeployReplaceRules>
//</ItemDefinitionGroup>
ObjectName,
ScopeAttributeName,
ScopeAttributeValue,
TargetAttributeName,
Match,
Replace,
};
internal enum SkipRuleMetadata
{
//<ItemDefinitionGroup>
// <MsDeploySkipRules>
// <SkipAction></SkipAction>
// <ObjectName></ObjectName>
// <AbsolutePath></AbsolutePath>
// <XPath></XPath>
// <KeyAttribute></KeyAttribute>
// </MsDeploySkipRules>
//</ItemDefinitionGroup>
SkipAction,
ObjectName,
AbsolutePath,
XPath,
KeyAttribute,
};
internal enum DeclareParameterMetadata
{
//<ItemDefinitionGroup>
// <MsDeployDeclareParameters>
// <Kind></Kind>
// <Scope></Scope>
// <Match></Match>
// <Description></Description>
// <DefaultValue></DefaultValue>
// </MsDeployDeclareParameters>
//</ItemDefinitionGroup>
Kind,
Scope,
Match,
Description,
DefaultValue,
Tags,
};
internal enum ExistingDeclareParameterMetadata
{
//<ItemDefinitionGroup>
// <MsDeployDeclareParameters>
// <Kind></Kind>
// <Scope></Scope>
// <Match></Match>
// <Description></Description>
// <DefaultValue></DefaultValue>
// </MsDeployDeclareParameters>
//</ItemDefinitionGroup>
Kind,
Scope,
Match,
};
internal enum SimpleSyncParameterMetadata
{
//<ItemDefinitionGroup>
// <MsDeploySimpleSetParameters>
// <Value></Value>
// </MsDeploySimpleSetParameters>
//</ItemDefinitionGroup>
Value,
}
internal enum SqlCommandVariableMetaData
{
Value,
IsDeclared,
SourcePath,
SourcePath_RegExEscaped,
DestinationGroup
}
internal enum ExistingParameterValidationMetadata
{
Element,
Kind,
ValidationString,
}
internal enum SyncParameterMetadata
{
//<ItemDefinitionGroup>
// <MsDeploySetParameters>
// <Kind></Kind>
// <Scope></Scope>
// <Match></Match>
// <Value></Value>
// </MsDeploySetParameters>
//</ItemDefinitionGroup>
Kind,
Scope,
Match,
Value,
Description,
DefaultValue,
Tags,
};
internal enum ExistingSyncParameterMetadata
{
//<ItemDefinitionGroup>
// <MsDeploySetParameters>
// <Kind></Kind>
// <Scope></Scope>
// <Match></Match>
// <Value></Value>
// </MsDeploySetParameters>
//</ItemDefinitionGroup>
Kind,
Scope,
Match,
Value,
};
internal class ParameterInfo
{
public string Name;
public string Value;
public ParameterInfo(string parameterName, string parameterStringValue)
{
Name = parameterName;
Value = parameterStringValue;
}
}
internal class ProviderOption : ParameterInfo
{
public string FactoryName;
public ProviderOption(string factorName, string parameterName, string parameterStringValue) :
base(parameterName, parameterStringValue)
{
FactoryName = factorName;
}
}
internal class ParameterInfoWithEntry : ParameterInfo
{
//Kind,
//Scope,
//Match,
//Value,
//Description,
//DefaultValue,
public string Kind;
public string Scope;
public string Match;
public string Description;
public string DefaultValue;
public string Tags;
public string Element;
public string ValidationString;
public ParameterInfoWithEntry(string name, string value, string kind, string scope, string matchRegularExpression, string description, string defaultValue, string tags, string element, string validationString) :
base(name, value)
{
Kind = kind;
Scope = scope;
Match = matchRegularExpression;
Description = description;
DefaultValue = defaultValue;
Tags = tags;
Element = element;
ValidationString = validationString;
}
}
internal static class Utility
{
static Dictionary<string, string?>? s_wellKnownNamesDict = null;
static Dictionary<string, string?>? s_wellKnownNamesMsdeployDict = null;
internal enum IISExpressMetadata
{
WebServerDirectory, WebServerManifest, WebServerAppHostConfigDirectory
}
public static bool IsInternalMsdeployWellKnownItemMetadata(string name)
{
if (Enum.TryParse<IISExpressMetadata>(name, out _))
{
return true;
}
if (string.Compare(name, "Path", StringComparison.OrdinalIgnoreCase) == 0)
{
return true;
}
return IsMSBuildWellKnownItemMetadata(name);
}
// Utility function to filter out known MSBuild Metatdata
public static bool IsMSBuildWellKnownItemMetadata(string name)
{
if (s_wellKnownNamesDict == null)
{
string[] wellKnownNames =
{
"FullPath",
"RootDir",
"Filename",
"Extension",
"RelativeDir",
"Directory",
"RecursiveDir",
"Identity",
"ModifiedTime",
"CreatedTime",
"AccessedTime",
"OriginalItemSpec",
"DefiningProjectDirectory",
"DefiningProjectDirectoryNoRoot",
"DefiningProjectExtension",
"DefiningProjectFile",
"DefiningProjectFullPath",
"DefiningProjectName"
};
s_wellKnownNamesDict = new Dictionary<string, string?>(wellKnownNames.GetLength(0), StringComparer.OrdinalIgnoreCase);
foreach (string wellKnownName in wellKnownNames)
{
s_wellKnownNamesDict.Add(wellKnownName, null);
}
}
return s_wellKnownNamesDict.ContainsKey(name);
}
public static bool IsMsDeployWellKnownLocationInfo(string name)
{
if (s_wellKnownNamesMsdeployDict == null)
{
string[] wellKnownNames =
{
"computerName",
"wmsvc",
"userName",
"password",
"includeAcls",
"encryptPassword",
"authType",
"prefetchPayload",
};
s_wellKnownNamesMsdeployDict = new Dictionary<string, string?>(wellKnownNames.GetLength(0), StringComparer.OrdinalIgnoreCase);
foreach (string wellKnownName in wellKnownNames)
{
s_wellKnownNamesMsdeployDict.Add(wellKnownName, null);
}
}
return s_wellKnownNamesMsdeployDict.ContainsKey(name);
}
static StringBuilder? s_stringBuilder = null;
/// <summary>
/// common utility for Clean share common builder
/// </summary>
private static StringBuilder StringBuilder
{
get
{
if (s_stringBuilder == null)
{
s_stringBuilder = new StringBuilder(1024);
}
return s_stringBuilder;
}
}
/// <summary>
/// This is the simple share clean build. Since this is an share instance
/// make sure you don't call this on complex operation or it will be zero out unexpectedly
/// Use this you need to be simple function which doesn't call any function that use this property
/// Sde dev10 bug 699893
/// </summary>
public static StringBuilder CleanStringBuilder
{
get
{
StringBuilder sb = StringBuilder;
sb.Remove(0, sb.Length);
return sb;
}
}
#if NET472
/// <summary>
/// Return the current machine's IIS version
/// </summary>
/// <returns></returns>
public static uint GetInstalledMajorIisVersion()
{
uint iisMajorVersion = 0;
using (Win32.RegistryKey registryKey = Win32.Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\Inetstp"))
{
if (registryKey != null)
{
iisMajorVersion = Convert.ToUInt16(registryKey.GetValue(@"MajorVersion", 0), CultureInfo.InvariantCulture);
}
}
return iisMajorVersion;
}
#endif
/// <summary>
/// verify it is in IIS6
/// </summary>
/// <param name="verFromTarget"></param>
/// <returns></returns>
public static bool IsIis6(string verFromTarget)
{
return (verFromTarget == "6");
}
/// <summary>
/// Main version of IIS
/// </summary>
public enum IisMainVersion
{
NonIis = 0,
Iis6 = 6,
Iis7 = 7
}
/// <summary>
/// Return true if MSDeploy is installed
/// </summary>
private static bool _isMSDeployInstalled = false;
private static string? _strErrorMessage = null;
public static bool IsMSDeployInstalled
{
get
{
if (_isMSDeployInstalled)
{
return true;
}
else if (_strErrorMessage != null)
{
return false;
}
else
{
try
{
_isMSDeployInstalled = CheckMSDeploymentVersion();
}
catch (FileNotFoundException ex)
{
_strErrorMessage = string.Format(CultureInfo.CurrentCulture, Resources.VSMSDEPLOY_MSDEPLOYLOADFAIL,
Resources.VSMSDEPLOY_MSDEPLOY32bit,
Resources.VSMSDEPLOY_MSDEPLOY64bit,
ex.Message);
_isMSDeployInstalled = false;
}
Debug.Assert(_isMSDeployInstalled || _strErrorMessage != null);
return _isMSDeployInstalled;
}
}
}
/// <summary>
/// Return true if MSDeploy is installed, and report an error to task.Log if it's not
/// </summary>
public static bool CheckMSDeploymentVersion(Utilities.TaskLoggingHelper log, out string? errorMessage)
{
errorMessage = null;
if (!IsMSDeployInstalled)
{
errorMessage = _strErrorMessage;
log.LogError(_strErrorMessage);
return false;
}
else
{
return true;
}
}
/// <summary>
/// Utility function to save the given XML document in UTF8 and indented
/// </summary>
/// <param name="document"></param>
public static void SaveDocument(XmlDocument document, string outputFileName, Encoding encode)
{
#if NET472
XmlTextWriter textWriter = new(outputFileName, encode)
{
Formatting = Formatting.Indented
};
document.Save(textWriter);
textWriter.Close();
#else
using (FileStream fs = new(outputFileName, FileMode.OpenOrCreate))
{
using (StreamWriter writer = new(fs, encode))
{
XmlDeclaration xmldecl;
xmldecl = document.CreateXmlDeclaration("1.0", null, null);
xmldecl.Encoding = "utf-8";
// Add the new node to the document.
XmlElement? root = document.DocumentElement;
document.InsertBefore(xmldecl, root);
document.Save(writer);
}
}
#endif
}
/// <summary>
/// Utility to check the MinimumVersion of Msdeploy
/// </summary>
static string? s_strMinimumVersion;
/// <summary>
/// Helper function to determine installed MSDeploy version
/// </summary>
private static bool CheckMSDeploymentVersion()
{
// Find the MinimumVersionRequirement
Version currentMinVersion;
if (!string.IsNullOrEmpty(s_strMinimumVersion))
{
currentMinVersion = new Version(s_strMinimumVersion);
}
else
{
currentMinVersion = new Version(7, 1, 614); // current drop
{
string strMinimumVersion = string.Empty;
#if NET472
using (Win32.RegistryKey registryKeyVs = Win32.Registry.CurrentUser.OpenSubKey(@"SOFTWARE\Microsoft\VisualStudio\11.0\WebDeploy"))
{
if (registryKeyVs != null)
{
s_strMinimumVersion = registryKeyVs.GetValue(@"MinimumMsDeployVersion", string.Empty).ToString();
}
else
{
using (Win32.RegistryKey registryKeyVsLM = Win32.Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\VisualStudio\11.0\WebDeploy"))
{
if (registryKeyVsLM != null)
{
s_strMinimumVersion = registryKeyVsLM.GetValue(@"MinimumMsDeployVersion", string.Empty).ToString();
}
}
}
}
#endif
if (!string.IsNullOrEmpty(s_strMinimumVersion))
{
currentMinVersion = new Version(strMinimumVersion);
}
else
{
s_strMinimumVersion = currentMinVersion.ToString();
}
}
}
Debug.Assert(MSWebDeploymentAssembly.DynamicAssembly != null && MSWebDeploymentAssembly.DynamicAssembly.Assembly != null);
if (MSWebDeploymentAssembly.DynamicAssembly != null && MSWebDeploymentAssembly.DynamicAssembly.Assembly != null)
{
AssemblyName assemblyName = MSWebDeploymentAssembly.DynamicAssembly.Assembly.GetName();
Version minVersion = new(currentMinVersion.Major, currentMinVersion.Minor);
Version? assemblyVersion = assemblyName.Version; // assembly version only accurate to the minor version
bool fMinVersionNotMeet = false;
if (assemblyVersion < minVersion)
{
fMinVersionNotMeet = true;
}
if (fMinVersionNotMeet)
{
_strErrorMessage = string.Format(CultureInfo.CurrentCulture, Resources.VSMSDEPLOY_MSDEPLOYLOADFAIL,
Resources.VSMSDEPLOY_MSDEPLOY32bit,
Resources.VSMSDEPLOY_MSDEPLOY64bit,
assemblyVersion,
currentMinVersion);
return false;
}
return true;
}
else
{
#if NET472
_strErrorMessage = string.Format(CultureInfo.CurrentCulture, Resources.VSMSDEPLOY_MSDEPLOYLOADFAIL,
Resources.VSMSDEPLOY_MSDEPLOY32bit,
Resources.VSMSDEPLOY_MSDEPLOY64bit,
new Version(),
currentMinVersion);
#else
_strErrorMessage = string.Format(CultureInfo.CurrentCulture, Resources.VSMSDEPLOY_MSDEPLOYLOADFAIL,
Resources.VSMSDEPLOY_MSDEPLOY32bit,
Resources.VSMSDEPLOY_MSDEPLOY64bit,
new System.Version(3, 6),
currentMinVersion);
#endif
return false;
}
}
#if NET472
/// <summary>
/// Return a search path for the data
/// </summary>
/// <param name="doc"></param>
/// <param name="xmlPath"></param>
/// <param name="defaultNamespace"></param>
/// <returns></returns>
public static string? GetNodeFromProjectFile(XmlDocument doc, XmlNamespaceManager xmlnsManager,
string xmlPath, string defaultNamespace)
{
if (doc == null)
return null;
string searchPath = xmlPath;
if (!string.IsNullOrEmpty(defaultNamespace))
{
RegularExpressions.Regex regex = new(@"([\w]+)");
searchPath = regex.Replace(xmlPath, defaultNamespace + @":$1");
}
XmlNode xmlNode = doc.SelectSingleNode(searchPath, xmlnsManager);
if (xmlNode != null)
{
return xmlNode.InnerText;
}
return null;
}
#endif
/// <summary>
/// Utility to help build the argument list from the enum type
/// </summary>
/// <param name="item"></param>
/// <param name="arguments"></param>
/// <param name="enumType"></param>
internal static void BuildArgumentsBaseOnEnumTypeName(Framework.ITaskItem item, List<string> arguments, Type enumType, string? valueQuote)
{
string[] enumNames = Enum.GetNames(enumType);
foreach (string enumName in enumNames)
{
string data = item.GetMetadata(enumName);
if (!string.IsNullOrEmpty(data))
{
string valueData = PutValueInQuote(data, valueQuote);
#if NET472
arguments.Add(string.Concat(enumName.ToLower(CultureInfo.InvariantCulture), "=", valueData));
#else
arguments.Add(string.Concat(enumName.ToLower(), "=", valueData));
#endif
}
}
}
internal static string AlternativeQuote(string? valueQuote)
{
if (string.IsNullOrEmpty(valueQuote) || valueQuote == "\"")
{
return "'";
}
else
{
return "\"";
}
}
public static char[] s_specialCharactersForCmd = @"&()[]{}^=;!'+,`~".ToArray();
internal static string PutValueInQuote(string value, string? quote)
{
if (string.IsNullOrEmpty(quote))
{
if (value is not null && value.IndexOfAny(s_specialCharactersForCmd) >= 0)
{
// any command line special characters, we use double quote by default
quote = "\"";
}
else
{
// otherwise we pick the smart one.
quote = AlternativeQuote(quote);
}
if (value is not null && value.Length != 0)
{
if (value.Contains(quote))
{
quote = AlternativeQuote(quote);
}
}
}
return string.Concat(quote, value, quote);
}
public static bool IsOneOf(string source, string[] listOfItems, StringComparison comparsion)
{
if (listOfItems is not null && !string.IsNullOrEmpty(source))
{
foreach (string item in listOfItems)
{
if (string.Compare(source, item, comparsion) == 0)
{
return true;
}
}
}
return false;
}
/// <summary>
/// Utility function to prompt common end of Execution message for msdeploy.exe
///
/// </summary>
/// <param name="bSuccess"></param>
/// <param name="destType"></param>
/// <param name="destRoot"></param>
/// <param name="Log"></param>
public static void MsDeployExeEndOfExecuteMessage(bool bSuccess, string destType, string destRoot, Utilities.TaskLoggingHelper Log)
{
bool fNeedUnpackageHelpLink = false;
string strSucceedFailMsg;
string[] packageArchivedir = new string[] { MSDeploy.Provider.ArchiveDir, MSDeploy.Provider.Package };
string[] ArchiveDirOnly = new string[] { MSDeploy.Provider.ArchiveDir };
if (bSuccess)
{
#if NET472
if (IsOneOf(destType, packageArchivedir, StringComparison.InvariantCultureIgnoreCase))
#else
if (IsOneOf(destType, packageArchivedir, StringComparison.OrdinalIgnoreCase))
#endif
{
//strip off the trailing slash, so IO.Path.GetDirectoryName/GetFileName will return values correctly
destRoot = StripOffTrailingSlashes(destRoot);
string dir = Path.GetDirectoryName(destRoot) ?? string.Empty;
string dirUri = ConvertAbsPhysicalPathToAbsUriPath(dir);
#if NET472
if (IsOneOf(destType, ArchiveDirOnly, StringComparison.InvariantCultureIgnoreCase))
#else
if (IsOneOf(destType, ArchiveDirOnly, StringComparison.OrdinalIgnoreCase))
#endif
strSucceedFailMsg = string.Format(CultureInfo.CurrentCulture, Resources.VSMSDEPLOY_SucceedArchiveDir, string.IsNullOrEmpty(dirUri) ? destRoot : dirUri);
else
strSucceedFailMsg = string.Format(CultureInfo.CurrentCulture, Resources.VSMSDEPLOY_SucceedPackage, Path.GetFileName(destRoot), string.IsNullOrEmpty(dirUri) ? destRoot : dirUri);
fNeedUnpackageHelpLink = true;
}
else
{
strSucceedFailMsg = Resources.VSMSDEPLOY_SucceedDeploy;
}
}
else
{
#if NET472
if (IsOneOf(destType, packageArchivedir, StringComparison.InvariantCultureIgnoreCase))
#else
if (IsOneOf(destType, packageArchivedir, StringComparison.OrdinalIgnoreCase))
#endif
{
strSucceedFailMsg = Resources.VSMSDEPLOY_FailedPackage;
}
else
{
strSucceedFailMsg = Resources.VSMSDEPLOY_FailedDeploy;
}
}
Log.LogMessage(Framework.MessageImportance.High, strSucceedFailMsg);
if (fNeedUnpackageHelpLink)
{
Log.LogMessage(Framework.MessageImportance.High, Resources.VSMSDEPLOY_WebPackageHelpLinkMessage);
Log.LogMessage(Framework.MessageImportance.High, Resources.VSMSDEPLOY_WebPackageHelpLink);
}
}
/// <summary>
/// Utility function to prompt common end of Execution message
/// </summary>
/// <param name="bSuccess"></param>
/// <param name="destType"></param>
/// <param name="destRoot"></param>
/// <param name="Log"></param>
public static void MsDeployEndOfExecuteMessage(bool bSuccess, string destType, string destRoot, Utilities.TaskLoggingHelper Log)
{
// Deployment.DeploymentWellKnownProvider wellKnownProvider = Deployment.DeploymentWellKnownProvider.Unknown;
Type? DeploymentWellKnownProviderType = MSWebDeploymentAssembly.DynamicAssembly?.GetType(MSDeploy.TypeName.DeploymentWellKnownProvider);
dynamic? wellKnownProvider = MSWebDeploymentAssembly.DynamicAssembly?.GetEnumValue(MSDeploy.TypeName.DeploymentWellKnownProvider, "Unknown");
#if NET472
if (string.Compare(destType, MSDeploy.Provider.DbDacFx, StringComparison.InvariantCultureIgnoreCase) != 0)
#else
if (string.Compare(destType, MSDeploy.Provider.DbDacFx, StringComparison.OrdinalIgnoreCase) != 0)
#endif
{
try
{
if (DeploymentWellKnownProviderType is not null)
{
wellKnownProvider = Enum.Parse(DeploymentWellKnownProviderType, destType, true);
}
}
catch
{
// don't cause the failure;
}
}
bool fNeedUnpackageHelpLink = false;
string strSucceedFailMsg;
if (bSuccess)
{
if (wellKnownProvider?.Equals(MSWebDeploymentAssembly.DynamicAssembly?.GetEnumValue(MSDeploy.TypeName.DeploymentWellKnownProvider, MSDeploy.Provider.ArchiveDir)) ?? false ||
wellKnownProvider?.Equals(MSWebDeploymentAssembly.DynamicAssembly?.GetEnumValue(MSDeploy.TypeName.DeploymentWellKnownProvider, MSDeploy.Provider.Package)) ?? false)
{
//strip off the trailing slash, so IO.Path.GetDirectoryName/GetFileName will return values correctly
destRoot = StripOffTrailingSlashes(destRoot);
string dir = Path.GetDirectoryName(destRoot) ?? string.Empty;
string dirUri = ConvertAbsPhysicalPathToAbsUriPath(dir);
if (wellKnownProvider?.Equals(MSWebDeploymentAssembly.DynamicAssembly?.GetEnumValue(MSDeploy.TypeName.DeploymentWellKnownProvider, MSDeploy.Provider.ArchiveDir)) ?? false)
strSucceedFailMsg = string.Format(CultureInfo.CurrentCulture, Resources.VSMSDEPLOY_SucceedArchiveDir, string.IsNullOrEmpty(dirUri) ? destRoot : dirUri);
else
strSucceedFailMsg = string.Format(CultureInfo.CurrentCulture, Resources.VSMSDEPLOY_SucceedPackage, Path.GetFileName(destRoot), string.IsNullOrEmpty(dirUri) ? destRoot : dirUri);
fNeedUnpackageHelpLink = true;
}
else
{
strSucceedFailMsg = Resources.VSMSDEPLOY_SucceedDeploy;
}
}
else
{
if (wellKnownProvider?.Equals(MSWebDeploymentAssembly.DynamicAssembly?.GetEnumValue(MSDeploy.TypeName.DeploymentWellKnownProvider, MSDeploy.Provider.ArchiveDir)) ?? false ||
wellKnownProvider?.Equals(MSWebDeploymentAssembly.DynamicAssembly?.GetEnumValue(MSDeploy.TypeName.DeploymentWellKnownProvider, MSDeploy.Provider.Package)) ?? false)
{
strSucceedFailMsg = Resources.VSMSDEPLOY_FailedPackage;
}
else
{
strSucceedFailMsg = Resources.VSMSDEPLOY_FailedDeploy;
}
}
Log.LogMessage(Framework.MessageImportance.High, strSucceedFailMsg);
if (fNeedUnpackageHelpLink)
{
Log.LogMessage(Framework.MessageImportance.High, Resources.VSMSDEPLOY_WebPackageHelpLinkMessage);
Log.LogMessage(Framework.MessageImportance.High, Resources.VSMSDEPLOY_WebPackageHelpLink);
}
}
public static string ConvertAbsPhysicalPathToAbsUriPath(string physicalPath)
{
string absUriPath = string.Empty;
try
{
Uri uri = new(physicalPath);
if (uri.IsAbsoluteUri)
absUriPath = uri.AbsoluteUri;
}
catch { }
return absUriPath;
}
// utility function to add the replace rule for the option
public static void AddReplaceRulesToOptions(/*Deployment.DeploymentRuleCollection*/ dynamic syncConfigRules, Framework.ITaskItem[] replaceRuleItems)
{
if (syncConfigRules is not null && replaceRuleItems is not null)// Dev10 bug 496639 foreach will throw the exception if the replaceRuleItem is null
{
foreach (Framework.ITaskItem item in replaceRuleItems)
{
string ruleName = item.ItemSpec;
string objectName = item.GetMetadata(ReplaceRuleMetadata.ObjectName.ToString());
string matchRegularExpression = item.GetMetadata(ReplaceRuleMetadata.Match.ToString());
string replaceWith = item.GetMetadata(ReplaceRuleMetadata.Replace.ToString());
string scopeAttributeName = item.GetMetadata(ReplaceRuleMetadata.ScopeAttributeName.ToString());
string scopeAttributeValue = item.GetMetadata(ReplaceRuleMetadata.ScopeAttributeValue.ToString());
string targetAttributeName = item.GetMetadata(ReplaceRuleMetadata.TargetAttributeName.ToString());
///*Deployment.DeploymentReplaceRule*/ dynamic replaceRule =
// new Deployment.DeploymentReplaceRule(ruleName, objectName, scopeAttributeName,
// scopeAttributeValue, targetAttributeName, matchRegularExpression, replaceWith);
/*Deployment.DeploymentReplaceRule*/
dynamic? replaceRule = MSWebDeploymentAssembly.DynamicAssembly?.CreateObject("Microsoft.Web.Deployment.DeploymentReplaceRule",
new object[]{ruleName, objectName, scopeAttributeName,
scopeAttributeValue, targetAttributeName, matchRegularExpression, replaceWith});
syncConfigRules.Add(replaceRule);
}
}
}
/// <summary>
/// utility function to enable the skip directive's enable state
/// </summary>
/// <param name="baseOptions"></param>
/// <param name="stringList"></param>
/// <param name="enabled"></param>
/// <param name="log"></param>
internal static void AdjustSkipDirectives(/*Deployment.DeploymentBaseOptions*/ dynamic baseOptions, List<string> stringList, bool enabled, Utilities.TaskLoggingHelper log)
{
if (stringList is not null && baseOptions is not null)
{
foreach (string name in stringList)
{
foreach (/*Deployment.DeploymentSkipDirective*/ dynamic skipDirective in baseOptions.SkipDirectives)
{
if (string.Compare(skipDirective.Name, name, StringComparison.OrdinalIgnoreCase) == 0)
{
if (skipDirective.Enabled != enabled)
{
skipDirective.Enabled = enabled;
}
log.LogMessage(string.Format(CultureInfo.CurrentCulture, Resources.VSMSDEPLOY_SkipDirectiveSetEnable, skipDirective.Name, enabled.ToString()));
}
}
log.LogWarning(string.Format(CultureInfo.CurrentCulture, Resources.VSMSDEPLOY_UnknownSkipDirective, name));
}
}
}
// utility function to add the skip rule for the option
public static void AddSkipDirectiveToBaseOptions(/*Deployment.DeploymentBaseOptions*/ dynamic baseOptions,
Framework.ITaskItem[] skipRuleItems,
List<string> enableSkipDirectiveList,
List<string> disableSkipDirectiveList,
Utilities.TaskLoggingHelper log)
{
if (baseOptions is not null && skipRuleItems is not null)
{
List<string> arguments = new(6);
foreach (Framework.ITaskItem item in skipRuleItems)
{
arguments.Clear();
BuildArgumentsBaseOnEnumTypeName(item, arguments, typeof(SkipRuleMetadata), "\"");
if (arguments.Count > 0)
{
string name = item.ItemSpec;
///*Deployment.DeploymentSkipDirective*/ dynamic skipDirective = new Microsoft.Web.Deployment.DeploymentSkipDirective(name, string.Join(",", arguments.ToArray()), true);
/*Deployment.DeploymentSkipDirective*/
dynamic? skipDirective = MSWebDeploymentAssembly.DynamicAssembly?.CreateObject("Microsoft.Web.Deployment.DeploymentSkipDirective", new object[] { name, string.Join(",", arguments.ToArray()), true });
baseOptions.SkipDirectives.Add(skipDirective);
}
}
AdjustSkipDirectives(baseOptions, enableSkipDirectiveList, true, log);
AdjustSkipDirectives(baseOptions, disableSkipDirectiveList, false, log);
}
}
/// <summary>
/// Utility to add single DeclareParameter to the list
/// </summary>
/// <param name="vSMSDeploySyncOption"></param>
/// <param name="item"></param>
public static void AddDeclareParameterToOptions(/*VSMSDeploySyncOption*/ dynamic vSMSDeploySyncOption, Framework.ITaskItem item)
{
if (item is not null && vSMSDeploySyncOption is not null)
{
string name = item.ItemSpec;
string element = item.GetMetadata(ExistingParameterValidationMetadata.Element.ToString());
if (string.IsNullOrEmpty(element))
element = "parameterEntry";
string kind = item.GetMetadata(DeclareParameterMetadata.Kind.ToString());
string scope = item.GetMetadata(DeclareParameterMetadata.Scope.ToString());
string matchRegularExpression = item.GetMetadata(DeclareParameterMetadata.Match.ToString());
string description = item.GetMetadata(DeclareParameterMetadata.Description.ToString());
string defaultValue = item.GetMetadata(DeclareParameterMetadata.DefaultValue.ToString());
string tags = item.GetMetadata(DeclareParameterMetadata.Tags.ToString());
dynamic? deploymentSyncParameter = null;
// the following have out argument, can't use dynamic on it
// vSMSDeploySyncOption.DeclaredParameters.TryGetValue(name, out deploymentSyncParameter);
MSWebDeploymentAssembly.DeploymentTryGetValueContains(vSMSDeploySyncOption.DeclaredParameters, name, out deploymentSyncParameter);
if (deploymentSyncParameter == null)
{
deploymentSyncParameter =
MSWebDeploymentAssembly.DynamicAssembly?.CreateObject("Microsoft.Web.Deployment.DeploymentSyncParameter", new object[] { name, description, defaultValue, tags });
vSMSDeploySyncOption.DeclaredParameters.Add(deploymentSyncParameter);
}
if (!string.IsNullOrEmpty(kind))
{
if (string.Compare(element, "parameterEntry", StringComparison.OrdinalIgnoreCase) == 0)
{
bool fAddEntry = true;
foreach (dynamic entry in deploymentSyncParameter?.Entries ?? Array.Empty<dynamic>())
{
if (scope.Equals(entry.Scope) &&
matchRegularExpression.Equals(entry.Match) &&
string.Compare(entry.Kind.ToString(), kind, StringComparison.OrdinalIgnoreCase) == 0)
{
fAddEntry = false;
}
}
if (fAddEntry)
{
dynamic? parameterEntry = MSWebDeploymentAssembly.DynamicAssembly?.CreateObject("Microsoft.Web.Deployment.DeploymentSyncParameterEntry",
new object[] { kind, scope, matchRegularExpression, string.Empty });
deploymentSyncParameter?.Add(parameterEntry);
}
}
else if (string.Compare(element, "parameterValidation", StringComparison.OrdinalIgnoreCase) == 0)
{
// this is bogus assertion because by default msdeploy always setup the validation which is never be null
// System.Diagnostics.Debug.Assert(deploymentSyncParameter.Validation == null, "deploymentSyncParameter.Validation is already set");
string validationString = item.GetMetadata(ExistingParameterValidationMetadata.ValidationString.ToString());
object? validationKindNone = MSWebDeploymentAssembly.DynamicAssembly?.GetEnumValue("Microsoft.Web.Deployment.DeploymentSyncParameterValidationKind", "None");
dynamic? validationKind = validationKindNone;
Type? validationKindType = validationKind?.GetType();
string[] validationKinds = kind.Split(new char[] { ',' });
foreach (string strValidationKind in validationKinds)
{
dynamic? currentValidationKind;
if (validationKindType is not null && (MSWebDeploymentAssembly.DynamicAssembly?.TryGetEnumValue("Microsoft.Web.Deployment.DeploymentSyncParameterValidationKind", strValidationKind, out currentValidationKind) ?? false))
{
validationKind = Enum.ToObject(validationKindType, ((int)(validationKind)) | ((int)(currentValidationKind)));
}
}
// dynamic doesn't compare, since this is enum, cast to int to compare
if (validationKind is not null && (int)validationKind != (int)(validationKindNone ?? 0))
{
// due to the reflection the we can't
// $exception {"Cannot implicitly convert type 'object' to 'Microsoft.Web.Deployment.DeploymentSyncParameterValidation'. An explicit conversion exists (are you missing a cast?)"} System.Exception {Microsoft.CSharp.RuntimeBinder.RuntimeBinderException}
object? parameterValidation =
MSWebDeploymentAssembly.DynamicAssembly?.CreateObject("Microsoft.Web.Deployment.DeploymentSyncParameterValidation", new object[] { validationKind, validationString });
SetDynamicProperty(deploymentSyncParameter, "Validation", parameterValidation);
}
}
}
}
}
/// <summary>
/// Utility function to avoid the reflection exception when assign to a strongtype property
/// // $exception {"Cannot implicitly convert type 'object' to 'Microsoft.Web.Deployment.DeploymentSyncParameterValidation'. An explicit conversion exists (are you missing a cast?)"} System.Exception {Microsoft.CSharp.RuntimeBinder.RuntimeBinderException}
/// </summary>
/// <param name="thisObj"></param>
/// <param name="propertyName"></param>
/// <param name="value"></param>
public static void SetDynamicProperty(dynamic? thisObj, string propertyName, object value)
{
thisObj?.GetType().GetProperty(propertyName).SetValue(thisObj, value, null);
}
/// <summary>
/// Utility function to add DeclareParameter in line
/// </summary>
/// <param name="vSMSDeploySyncOption"></param>
/// <param name="items"></param>
public static void AddDeclareParametersToOptions(/*VSMSDeploySyncOption*/ dynamic vSMSDeploySyncOption, Framework.ITaskItem[] originalItems, bool fOptimisticPickNextDefaultValue)
{
IList<Framework.ITaskItem> items = SortParametersTaskItems(originalItems, fOptimisticPickNextDefaultValue, DeclareParameterMetadata.DefaultValue.ToString());
if (vSMSDeploySyncOption is not null && items is not null)
{
foreach (Framework.ITaskItem item in items)
{
AddDeclareParameterToOptions(vSMSDeploySyncOption, item);
}
}
}
// MSDeploy change -- Deprecate
///// <summary>
///// Utility function to support DeclareParametersFromFile
///// </summary>
///// <param name="vSMSDeploySyncOption"></param>
///// <param name="items"></param>
public static void AddImportDeclareParametersFileOptions(/*VSMSDeploySyncOption*/ dynamic vSMSDeploySyncOption, Framework.ITaskItem[] items)
{
if (vSMSDeploySyncOption is not null && items is not null)
{
foreach (Framework.ITaskItem item in items)
{
string fileName = item.ItemSpec;
vSMSDeploySyncOption.DeclaredParameters.Load(fileName);
}
}
}
public static void AddSetParametersFilesToObject(/*Deployment.DeploymentObject*/ dynamic deploymentObject, IList<string> filenames, IVSMSDeployHost host)
{
if (deploymentObject is not null && filenames is not null)
{
foreach (string filename in filenames)
{
if (!string.IsNullOrEmpty(filename))
{
try
{
deploymentObject.SyncParameters.Load(filename);
}
catch (Exception e)
{
if (host != null)
host.Log.LogErrorFromException(e);
else
throw;
}
}
}
}
}
/// <summary>
/// Utility function to set SimpleSyncParameter Name/Value
/// </summary>
/// <param name="vSMSDeploySyncOption"></param>
/// <param name="items"></param>
public static void AddSimpleSetParametersVsMsDeployObject(VSMSDeployObject srcVsMsDeployobject, Framework.ITaskItem[]? originalItems, bool fOptimisticPickNextDefaultValue)
{
IList<Framework.ITaskItem> items = SortParametersTaskItems(originalItems, fOptimisticPickNextDefaultValue, SimpleSyncParameterMetadata.Value.ToString());
if (srcVsMsDeployobject is not null && items is not null)
{
string lastItemName = string.Empty;
foreach (Framework.ITaskItem item in items)
{
string name = item.ItemSpec;
if (string.CompareOrdinal(name, lastItemName) != 0)
{
string value = item.GetMetadata(SimpleSyncParameterMetadata.Value.ToString());
srcVsMsDeployobject.SyncParameter(name, value);
lastItemName = name;
}
}
}
}
public static void AddProviderOptions(/*Deployment.DeploymentProviderOptions*/ dynamic deploymentProviderOptions, IList<ProviderOption> providerOptions, IVSMSDeployHost host)
{
if (deploymentProviderOptions is not null && providerOptions is not null)
{
foreach (ProviderOption item in providerOptions)
{
string factoryName = item.FactoryName;
string name = item.Name;
string value = item.Value;
// Error handling is not required here if the providerOptions list is different from deploymentProviderOptions.ProviderSettings.
// providerOptions list contains metadata from MSBuild and this may be different from deploymentProviderOptions.ProviderSettings.
if (string.Compare(factoryName, deploymentProviderOptions.Factory.Name, StringComparison.OrdinalIgnoreCase) == 0)
{
dynamic? setting = null;
// deploymentProviderOptions.ProviderSettings.TryGetValue(name, out setting);
MSWebDeploymentAssembly.DeploymentTryGetValueForEach(deploymentProviderOptions.ProviderSettings, name, out setting);
if (setting != null)
{
setting.Value = value;
}
}
}
}
}
/// <summary>
/// Utility function to set SimpleSyncParameter Name/Value
/// </summary>
/// <param name="vSMSDeploySyncOption"></param>
/// <param name="items"></param>
public static void AddSimpleSetParametersToObject(/*Deployment.DeploymentObject*/ dynamic deploymentObject, IList<ParameterInfo> parameters, IVSMSDeployHost host)
{
if (deploymentObject is not null && parameters is not null)
{
Dictionary<string, string> nameValueDictionary = new(parameters.Count, StringComparer.OrdinalIgnoreCase);
foreach (ParameterInfo item in parameters)
{
string name = item.Name;
string? value;
if (!nameValueDictionary.TryGetValue(name, out value))
{
value = item.Value;
}
dynamic? parameter = null;
// deploymentObject.SyncParameters.TryGetValue(name, out parameter);
MSWebDeploymentAssembly.DeploymentTryGetValueContains(deploymentObject.SyncParameters, name, out parameter);
string msg = string.Format(CultureInfo.CurrentCulture, Resources.VSMSDEPLOY_AddParameterIntoObject, name, value, deploymentObject.Name);
host?.Log.LogMessage(msg);
if (parameter != null)
{
parameter.Value = value;
}
else
{
// Try to get error message to show.
StringBuilder sb = CleanStringBuilder;
foreach (dynamic param in deploymentObject.SyncParameters)
{
if (sb.Length != 0)
{
sb.Append(", ");
}
sb.Append(param.Name);
}
// To do, change this to resource
string errMessage = string.Format(CultureInfo.CurrentCulture, Resources.VSMSDEPLOY_UnknownParameter, name, sb.ToString());
if (host != null)
{
throw new InvalidOperationException(errMessage);
}
}
}
}
}
/// <summary>
/// Utility function to setParameters in type, scope, match, value of SyncParameter
/// </summary>
/// <param name="vSMSDeploySyncOption"></param>
/// <param name="items"></param>
public static void AddSetParametersToObject(/*Deployment.DeploymentObject*/ dynamic deploymentObject, IList<ParameterInfoWithEntry> parameters, IVSMSDeployHost host)
{
if (deploymentObject is not null && parameters is not null)
{
Dictionary<string, string> nameValueDictionary = new(parameters.Count, StringComparer.OrdinalIgnoreCase);
Dictionary<string, string?> entryIdentityDictionary = new(parameters.Count);
foreach (ParameterInfoWithEntry item in parameters)
{
try
{
string? data = null;
if (!nameValueDictionary.TryGetValue(item.Name, out data))
{
nameValueDictionary.Add(item.Name, item.Value);
data = item.Value;
}
dynamic? parameter = null;
dynamic? parameterEntry = null;
dynamic? parameterValidation = null;
if (!string.IsNullOrEmpty(item.Kind))
{
string identityString = string.Join(";", new string[] { item.Name, item.Kind, item.Scope, item.Match, item.Element, item.ValidationString });
if (!entryIdentityDictionary.ContainsKey(identityString))
{
if (string.Compare(item.Element, "parameterEntry", StringComparison.OrdinalIgnoreCase) == 0)
{
parameterEntry = MSWebDeploymentAssembly.DynamicAssembly?.CreateObject("Microsoft.Web.Deployment.DeploymentSyncParameterEntry",
new object[] { item.Kind, item.Scope, item.Match, string.Empty });
}
else if (string.Compare(item.Element, "parameterValidation", StringComparison.OrdinalIgnoreCase) == 0)
{
// this is bogus assertion because by default msdeploy always setup the validation which is never be null
// System.Diagnostics.Debug.Assert(deploymentSyncParameter.Validation == null, "deploymentSyncParameter.Validation is already set");
string validationString = item.ValidationString;
object? validationKindNone = MSWebDeploymentAssembly.DynamicAssembly?.GetEnumValue("Microsoft.Web.Deployment.DeploymentSyncParameterValidationKind", "None");
dynamic? validationKind = validationKindNone;
Type? validationKindType = validationKind?.GetType();
dynamic? currentvalidationKind = validationKindNone;
string[] validationKinds = item.Kind.Split(new char[] { ',' });
foreach (string strValidationKind in validationKinds)
{
if (validationKindType is not null && (MSWebDeploymentAssembly.DynamicAssembly?.TryGetEnumValue("Microsoft.Web.Deployment.DeploymentSyncParameterValidationKind", strValidationKind, out currentvalidationKind) ?? false))
{
validationKind = Enum.ToObject(validationKindType, ((int)(validationKind)) | ((int)(currentvalidationKind)));
}
}
// dynamic doesn't compare, since this is enum, cast to int to compare
if (validationKind is not null && (int)validationKind != (int)(validationKindNone ?? 0))
{
parameterValidation =
MSWebDeploymentAssembly.DynamicAssembly?.CreateObject("Microsoft.Web.Deployment.DeploymentSyncParameterValidation", new object[] { validationKind, validationString });
}
}
entryIdentityDictionary.Add(identityString, null);
}
}
if (!MSWebDeploymentAssembly.DeploymentTryGetValueContains(deploymentObject.SyncParameters, item.Name, out parameter))
{
parameter = MSWebDeploymentAssembly.DynamicAssembly?.CreateObject("Microsoft.Web.Deployment.DeploymentSyncParameter",
new object[] { item.Name, item.Description, item.DefaultValue, item.Tags });
deploymentObject.SyncParameters.Add(parameter);
if (parameter is not null)
{
parameter.Value = data;
}
}
if (parameterEntry != null)
{
parameter?.Add(parameterEntry);
}
if (parameterValidation != null)
{
// due to the reflection, compiler complain on assign a object to type without explicit conversion
// parameter.Validation = parameterValidation;
SetDynamicProperty(parameter, "Validation", parameterValidation);
}
}
catch (Exception e)
{
if (host != null)
host.Log.LogErrorFromException(e);
else
throw;
}
}
}
}
/// <summary>
/// Utility function to setParameters in type, scope, match, value of SyncParameter
/// </summary>
/// <param name="vSMSDeploySyncOption"></param>
/// <param name="items"></param>
public static void AddSetParametersVsMsDeployObject(VSMSDeployObject srcVsMsDeployobject, Framework.ITaskItem[]? originalItems, bool fOptimisticPickNextDefaultValue)
{
IList<Framework.ITaskItem> items = SortParametersTaskItems(originalItems, fOptimisticPickNextDefaultValue, SyncParameterMetadata.DefaultValue.ToString());
if (srcVsMsDeployobject is not null && items is not null)
{
foreach (Framework.ITaskItem item in items)
{
string name = item.ItemSpec;
string kind = item.GetMetadata(SyncParameterMetadata.Kind.ToString());
string scope = item.GetMetadata(SyncParameterMetadata.Scope.ToString());
string matchRegularExpression = item.GetMetadata(SyncParameterMetadata.Match.ToString());
string value = item.GetMetadata(SyncParameterMetadata.Value.ToString());
string description = item.GetMetadata(SyncParameterMetadata.Description.ToString());
string defaultValue = item.GetMetadata(SyncParameterMetadata.DefaultValue.ToString());
string tags = item.GetMetadata(SyncParameterMetadata.Tags.ToString());
string element = item.GetMetadata(ExistingParameterValidationMetadata.Element.ToString());
if (string.IsNullOrEmpty(element))
element = "parameterEntry";
string validationString = item.GetMetadata(ExistingParameterValidationMetadata.ValidationString.ToString());
if (string.IsNullOrEmpty(value))
{
value = defaultValue;
}
srcVsMsDeployobject.SyncParameter(name, value, kind, scope, matchRegularExpression, description, defaultValue, tags, element, validationString);
}
}
}
public static void AddSetParametersFilesVsMsDeployObject(VSMSDeployObject srcVsMsDeployobject, Framework.ITaskItem[]? items)
{
if (srcVsMsDeployobject is not null && items is not null)
{
foreach (Framework.ITaskItem item in items)
{
string filename = item.ItemSpec;
srcVsMsDeployobject.SyncParameterFile(filename);
}
}
}
public static string DumpITaskItem(Framework.ITaskItem iTaskItem)
{
StringBuilder sb = CleanStringBuilder;
string itemSpec = iTaskItem.ItemSpec;
sb.Append("<Item Name=\"");
sb.Append(itemSpec);
sb.Append("\">");
foreach (string name in iTaskItem.MetadataNames)
{
string value = iTaskItem.GetMetadata(name);
sb.Append(@"<");
sb.Append(name);
sb.Append(@">");
sb.Append(value);
sb.Append(@"</");
sb.Append(name);
sb.Append(@">");
}
sb.Append(@"</Item>");
return sb.ToString();
}
public static bool IsDeploymentWellKnownProvider(string strProvider)
{
#if NET472
if (string.Compare(strProvider, MSDeploy.Provider.DbDacFx, StringComparison.InvariantCultureIgnoreCase) == 0)
#else
if (string.Compare(strProvider, MSDeploy.Provider.DbDacFx, StringComparison.OrdinalIgnoreCase) == 0)
#endif
{
return true;
}
object? DeploymentWellKnownProviderUnknown = MSWebDeploymentAssembly.DynamicAssembly?.GetEnumValue(MSDeploy.TypeName.DeploymentWellKnownProvider, MSDeploy.Provider.Unknown);
object? deploymentProvider = DeploymentWellKnownProviderUnknown;
try
{
deploymentProvider = MSWebDeploymentAssembly.DynamicAssembly?.GetEnumValueIgnoreCase(MSDeploy.TypeName.DeploymentWellKnownProvider, strProvider);
}
catch (Exception)
{
}
return deploymentProvider != DeploymentWellKnownProviderUnknown;
}
/// <summary>
/// Utility function to remove all Empty Directory
/// </summary>
/// <param name="dirPath"></param>
internal static void RemoveAllEmptyDirectories(string dirPath, Utilities.TaskLoggingHelper Log)
{
if (!string.IsNullOrEmpty(dirPath) && Directory.Exists(dirPath))
{
DirectoryInfo dirInfo = new(dirPath);
RemoveAllEmptyDirectories(dirInfo, Log);
}
}
internal static void RemoveAllEmptyDirectories(DirectoryInfo dirinfo, Utilities.TaskLoggingHelper log)
{
if (dirinfo is not null && dirinfo.Exists)
{
//Depth first search.
foreach (DirectoryInfo subDirInfo in dirinfo.GetDirectories())
{
RemoveAllEmptyDirectories(subDirInfo, log);
}
if (dirinfo.GetFileSystemInfos().GetLength(0) == 0)
{
dirinfo.Delete();
if (log != null)
{
log.LogMessage(Framework.MessageImportance.Normal, string.Format(CultureInfo.CurrentCulture, Resources.BUILDTASK_RemoveEmptyDirectories_Deleting, dirinfo.FullName));
}
}
}
}
static PriorityIndexComparer? s_PriorityIndexComparer = null;
internal static PriorityIndexComparer ParameterTaskComparer
{
get
{
if (s_PriorityIndexComparer == null)
{
s_PriorityIndexComparer = new PriorityIndexComparer();
}
return s_PriorityIndexComparer;
}
}
public static IList<Framework.ITaskItem> SortParametersTaskItems(Framework.ITaskItem[]? taskItems, bool fOptimisticPickNextNonNullDefaultValue, string PropertyName)
{
IList<Framework.ITaskItem> sortedList = SortTaskItemsByPriority(taskItems);
if (!fOptimisticPickNextNonNullDefaultValue || string.IsNullOrEmpty(PropertyName) || taskItems == null || taskItems.GetLength(0) <= 0)
{
return sortedList;
}
else
{
List<Framework.ITaskItem> optimizedValueList = new(sortedList);
Dictionary<string, bool> FoundDictionary = new(optimizedValueList.Count, StringComparer.OrdinalIgnoreCase);
int maxCount = sortedList.Count;
int i = 0;
while (i < maxCount)
{
int currentItemIndex = i;
Framework.ITaskItem item = optimizedValueList[i++];
string itemSpec = item.ItemSpec;
if (FoundDictionary.ContainsKey(itemSpec))
{
continue; // already scanned, move on to the next
}
else
{
bool fIsCurrentItemEmpty = string.IsNullOrEmpty(item.GetMetadata(PropertyName));
if (!fIsCurrentItemEmpty)
{
FoundDictionary[itemSpec] = true;
continue;
}
else
{
int next = i;
bool found = false;
while (next < maxCount)
{
Framework.ITaskItem nextItem = optimizedValueList[next++];
if (string.Compare(itemSpec, nextItem.ItemSpec, StringComparison.OrdinalIgnoreCase) == 0)
{
string itemData = nextItem.GetMetadata(PropertyName);
if (!string.IsNullOrEmpty(itemData))
{
// Get the data from the next best data
Utilities.TaskItem newItem = new(item);
newItem.SetMetadata(PropertyName, itemData);
optimizedValueList[currentItemIndex] = newItem;
FoundDictionary[itemSpec] = true; // mark that we already fond teh item;
found = true;
break;
}
}
}
if (!found)
{
FoundDictionary[itemSpec] = false; // mark that we scan through the item and not found anything
}
}
}
}
return optimizedValueList;
}
}
static string strMsdeployFwlink1 = @"http://go.microsoft.com/fwlink/?LinkId=178034";
static string strMsdeployFwlink2 = @"http://go.microsoft.com/fwlink/?LinkId=178035";
static string strMsdeployFwlink3 = @"http://go.microsoft.com/fwlink/?LinkId=178036";
static string strMsdeployFwlink4 = @"http://go.microsoft.com/fwlink/?LinkId=178587";
static string strMsdeployFwlink5 = @"http://go.microsoft.com/fwlink/?LinkId=178589";
internal static string strMsdeployInstallationFwdLink = @"http://go.microsoft.com/?linkid=9278654";
static string[] strMsdeployFwlinks = { strMsdeployFwlink1, strMsdeployFwlink2, strMsdeployFwlink3, strMsdeployFwlink4, strMsdeployFwlink5 };
static int ContainMsdeployFwlink(string errorMessage, out string? provider)
{
int index = -1;
provider = null;
string[][] strMsDeployFwlinksArray = { strMsdeployFwlinks };
foreach (string[] Fwlinks in strMsDeployFwlinksArray)
{
for (int i = 0; i < Fwlinks.Length; i++)
{
string fwlink = Fwlinks[i];
int lastIndexOfFwLink = -1;
if ((lastIndexOfFwLink = errorMessage.LastIndexOf(fwlink, StringComparison.OrdinalIgnoreCase)) >= 0)
{
index = i;
if (i == 0)
{
string subError = errorMessage.Substring(0, lastIndexOfFwLink);
subError = subError.Trim();
if ((lastIndexOfFwLink = subError.LastIndexOf(" ", StringComparison.Ordinal)) >= 0)
{
provider = subError.Substring(lastIndexOfFwLink + 1);
}
}
return index; // break out
}
}
}
return index;
}
internal static bool IsType(Type type, Type? checkType)
{
#if NET472
if (checkType != null && (type == checkType || type.IsSubclassOf(checkType)))
{
return true;
}
#endif
return false;
}
internal static string? EnsureTrailingSlash(string str)
{
if (str != null && !str.EndsWith("/", StringComparison.Ordinal))
{
str += "/";
}
return str;
}
internal static string? EnsureTrailingBackSlash(string str)
{
if (str != null && !str.EndsWith("\\", StringComparison.Ordinal))
{
str += "\\";
}
return str;
}
// Utility to log VsMsdeploy Exception
internal static void LogVsMsDeployException(Utilities.TaskLoggingHelper Log, Exception e)
{
if (e is TargetInvocationException)
{
if (e.InnerException != null)
e = e.InnerException;
}
StringBuilder strBuilder = new(e.Message.Length * 4);
Type t = e.GetType();
if (IsType(t, MSWebDeploymentAssembly.DynamicAssembly?.GetType(MSDeploy.TypeName.DeploymentEncryptionException)))
{
// dev10 695263 OGF: Encryption Error message needs more information for packaging
strBuilder.Append(Resources.VSMSDEPLOY_EncryptionExceptionMessage);
}
else if (IsType(t, MSWebDelegationAssembly.DynamicAssembly?.GetType(MSDeploy.TypeName.DeploymentException)))
{
Exception rootException = e;
dynamic lastDeploymentException = e;
while (rootException != null && rootException.InnerException != null)
{
rootException = rootException.InnerException;
if (IsType(rootException.GetType(), MSWebDelegationAssembly.DynamicAssembly?.GetType(MSDeploy.TypeName.DeploymentException)))
lastDeploymentException = rootException;
}
#if NET472
bool isWebException = rootException is System.Net.WebException;
if (isWebException)
{
System.Net.WebException? webException = rootException as System.Net.WebException;
// 404 come in as ProtocolError
if (webException?.Status == System.Net.WebExceptionStatus.ProtocolError)
{
if (webException.Message.LastIndexOf("401", StringComparison.Ordinal) >= 0)
{
strBuilder.Append(Resources.VSMSDEPLOY_WebException401Message);
}
else if (webException.Message.LastIndexOf("404", StringComparison.Ordinal) >= 0)
{
strBuilder.Append(Resources.VSMSDEPLOY_WebException404Message);
}
else if (webException.Message.LastIndexOf("502", StringComparison.Ordinal) >= 0)
{
strBuilder.Append(Resources.VSMSDEPLOY_WebException502Message);
}
else if (webException.Message.LastIndexOf("550", StringComparison.Ordinal) >= 0)
{
strBuilder.Append(Resources.VSMSDEPLOY_WebException550Message);
}
else if (webException.Message.LastIndexOf("551", StringComparison.Ordinal) >= 0)
{
strBuilder.Append(Resources.VSMSDEPLOY_WebException551Message);
}
}
else if (webException?.Status == System.Net.WebExceptionStatus.ConnectFailure)
{
strBuilder.Append(Resources.VSMSDEPLOY_WebExceptionConnectFailureMessage);
}
}
else if (rootException is System.Net.Sockets.SocketException)
{
strBuilder.Append(Resources.VSMSDEPLOY_WebExceptionConnectFailureMessage);
}
else
{
string strMsg = lastDeploymentException.Message;
string? provider;
int index = ContainMsdeployFwlink(strMsg, out provider);
if (index >= 0)
{
object? DeploymentWellKnownProviderUnknown = MSWebDeploymentAssembly.DynamicAssembly?.GetEnumValue(MSDeploy.TypeName.DeploymentWellKnownProvider, MSDeploy.Provider.Unknown);
dynamic? wellKnownProvider = DeploymentWellKnownProviderUnknown;
// fwdlink1
if (index == 0)
{
string srErrorMessage = Resources.VSMSDEPLOY_MsDeployExceptionFwlink1Message;
if (provider?.LastIndexOf("sql", StringComparison.OrdinalIgnoreCase) >= 0)
{
srErrorMessage = Resources.VSMSDEPLOY_MsDeployExceptionFwlink1SQLMessage;
}
else
{
try
{
if (provider is not null)
{
wellKnownProvider = MSWebDeploymentAssembly.DynamicAssembly?.GetEnumValueIgnoreCase(MSDeploy.TypeName.DeploymentWellKnownProvider, provider);
}
}
catch
{
// don't cause the failure;
}
if (wellKnownProvider?.Equals(MSWebDeploymentAssembly.DynamicAssembly?.GetEnumValue(MSDeploy.TypeName.DeploymentWellKnownProvider, MSDeploy.Provider.MetaKey)) ?? false
|| wellKnownProvider?.Equals(MSWebDeploymentAssembly.DynamicAssembly?.GetEnumValue(MSDeploy.TypeName.DeploymentWellKnownProvider, MSDeploy.Provider.AppHostConfig)) ?? false)
{
srErrorMessage = Resources.VSMSDEPLOY_MsDeployExceptionFwlink1SiteMessage;
}
}
strBuilder.Append(string.Format(CultureInfo.CurrentCulture,srErrorMessage, provider));
}
else if (index == 1)
{
strBuilder.Append(Resources.VSMSDEPLOY_MsDeployExceptionFwlink2Message);
}
else if (index == 2)
{
strBuilder.Append(Resources.VSMSDEPLOY_MsDeployExceptionFwlink3Message);
}
else if (index == 3)
{
strBuilder.Append(Resources.VSMSDEPLOY_MsDeployExceptionFwlink4Message);
}
else
{
Debug.Assert(false, "fwdlink5 and above is not implemented");
}
}
}
#endif
}
if (e.InnerException == null)
{
strBuilder.Append(e.Message);
Log.LogError(string.Format(CultureInfo.CurrentCulture, Resources.VSMSDEPLOY_FailedWithException, strBuilder.ToString()));
}
else
{
// Dev10 bug we sometime need better error message to show user what do do
Exception? currentException = e;
while (currentException != null)
{
strBuilder.Append(Environment.NewLine);
strBuilder.Append(currentException.Message);
currentException = currentException.InnerException;
}
Log.LogError(string.Format(CultureInfo.CurrentCulture, Resources.VSMSDEPLOY_FailedWithExceptionWithDetail, e.Message, strBuilder.ToString()));
}
strBuilder.Append(Environment.NewLine);
strBuilder.Append(e.StackTrace);
Log.LogMessage(Framework.MessageImportance.Low, strBuilder.ToString());
}
public static IList<Framework.ITaskItem> SortTaskItemsByPriority(Framework.ITaskItem[]? taskItems)
{
int count = taskItems != null ? taskItems.GetLength(0) : 0;
SortedList<KeyValuePair<int, int>, Framework.ITaskItem> sortedList = new(count, ParameterTaskComparer);
for (int i = 0; i < count; i++)
{
if (taskItems is not null)
{
Framework.ITaskItem iTaskItem = taskItems[i];
string priority = iTaskItem.GetMetadata("Priority");
int iPriority = string.IsNullOrEmpty(priority) ? 0 : Convert.ToInt32(priority, CultureInfo.InvariantCulture);
sortedList.Add(new KeyValuePair<int, int>(iPriority, i), iTaskItem);
}
}
return sortedList.Values;
}
internal class PriorityIndexComparer : IComparer<KeyValuePair<int, int>>
{
public int Compare(KeyValuePair<int, int> x, KeyValuePair<int, int> y)
{
if (x.Key == y.Key)
{
return x.Value - y.Value;
}
else
{
return x.Key - y.Key;
}
}
}
public static string StripOffTrailingSlashes(string str)
{
if (!string.IsNullOrEmpty(str))
{
while (str.EndsWith("\\", StringComparison.Ordinal) || str.EndsWith("/", StringComparison.Ordinal))
str = str.Substring(0, str.Length - 1);
}
return str;
}
public static string EnsureTrailingSlashes(string rootPath, char slash)
{
string directorySeparator = new(slash, 1);
string rootPathWithSlash = string.Concat(rootPath, rootPath.EndsWith(directorySeparator, StringComparison.Ordinal) ? string.Empty : directorySeparator);
return rootPathWithSlash;
}
public static string? GetFilePathResolution(string? source, string sourceRootPath)
{
if (source is null || Path.IsPathRooted(source) || string.IsNullOrEmpty(sourceRootPath))
return source;
else
return Path.Combine(sourceRootPath, source);
}
/// <summary>
/// Utility to generate the Ipv6 string address to match with the ServerBinding string
/// Ipv6 need the have
/// </summary>
/// <param name="iPAddress"></param>
/// <returns></returns>
internal static string? GetIPAddressString(System.Net.IPAddress iPAddress)
{
if (iPAddress != null)
{
if (iPAddress.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork)
return iPAddress.ToString();
else if (iPAddress.AddressFamily == System.Net.Sockets.AddressFamily.InterNetworkV6)
{
StringBuilder stringBuilder = CleanStringBuilder;
stringBuilder.Append("[");
stringBuilder.Append(iPAddress.ToString());
stringBuilder.Append("]");
return stringBuilder.ToString();
}
}
return null;
}
/// <summary>
/// Utility function to match the IPAddress with the string in IIS ServerBinding's IPAddress
/// </summary>
/// <param name="IISBindingIPString"></param>
/// <param name="iPAddresses"></param>
/// <returns></returns>
internal static bool MatchOneOfIPAddress(string IISBindingIPString, System.Net.IPAddress[] iPAddresses)
{
if (!string.IsNullOrEmpty(IISBindingIPString))
{
if (IISBindingIPString.Trim() == "*")
return true;
foreach (System.Net.IPAddress iPAddress in iPAddresses)
{
if (string.Compare(GetIPAddressString(iPAddress), IISBindingIPString, StringComparison.OrdinalIgnoreCase) == 0)
return true;
}
}
return false;
}
internal static void SetupMSWebDeployDynamicAssemblies(string? strVersionsToTry, Task task)
{
// Mark the assembly version.
// System.Version version1_1 = new System.Version("7.1");
Dictionary<string, string> versionsList = new();
if (strVersionsToTry is not null && strVersionsToTry.Length != 0)
{
foreach (string str in strVersionsToTry.Split(';'))
{
versionsList[str] = str;
}
}
const string MSDeploymentDllFallback = "9.0";
versionsList[MSDeploymentDllFallback] = MSDeploymentDllFallback;
Version[] versionArray = versionsList.Values.Select(p => new Version(p)).ToArray();
Array.Sort(versionArray);
for (int i = versionArray.GetLength(0) - 1; i >= 0; i--)
{
Version version = versionArray[i];
try
{
MSWebDeploymentAssembly.SetVersion(version);
Version webDelegationAssemblyVersion = version;
#if NET472
if (MSWebDeploymentAssembly.DynamicAssembly != null && MSWebDeploymentAssembly.DynamicAssembly.Assembly != null)
{
foreach (AssemblyName assemblyName in MSWebDeploymentAssembly.DynamicAssembly.Assembly.GetReferencedAssemblies())
{
if (string.Compare(assemblyName.Name, 0 , MSWebDelegationAssembly.AssemblyName, 0, MSWebDelegationAssembly.AssemblyName.Length, StringComparison.OrdinalIgnoreCase) == 0)
{
webDelegationAssemblyVersion = assemblyName.Version;
break;
}
}
}
#endif
MSWebDelegationAssembly.SetVersion(webDelegationAssemblyVersion);
task.Log.LogMessage(Framework.MessageImportance.Low, string.Format(CultureInfo.CurrentCulture, Resources.VSMSDEPLOY_MSDEPLOYVERSIONLOAD, task.ToString(), MSWebDeploymentAssembly.DynamicAssembly?.AssemblyFullName));
task.Log.LogMessage(Framework.MessageImportance.Low, string.Format(CultureInfo.CurrentCulture, Resources.VSMSDEPLOY_MSDEPLOYVERSIONLOAD, task.ToString(), MSWebDelegationAssembly.DynamicAssembly?.AssemblyFullName));
return;
}
catch (Exception e)
{
task.Log.LogMessage(Framework.MessageImportance.Low, string.Format(CultureInfo.CurrentCulture, Resources.BUILDTASK_FailedToLoadThisVersionMsDeployTryingTheNext, versionArray[i], e.Message));
}
}
// if it not return by now, it is definite a error
throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, Resources.VSMSDEPLOY_MSDEPLOYASSEMBLYLOAD_FAIL, task.ToString()));
}
public static string? EscapeTextForMSBuildVariable(string? text)
{
if (!string.IsNullOrEmpty(text) && text?.IndexOfAny(@"$%".ToArray()) >= 0)
{
StringBuilder stringBuilder = new(text.Length * 2);
char[] chars = text.ToCharArray();
int i = 0;
for (i = 0; i < chars.Count() - 2; i++)
{
char ch = chars[i];
char nextch1 = chars[i + 1];
char nextch2 = chars[i + 2];
bool fAlreadyHandled = false;
switch (ch)
{
case '$':
if (nextch1 == '(')
{
stringBuilder.Append("%24");
fAlreadyHandled = true;
}
break;
case '%':
if (nextch1 == '(' || ("0123456789ABCDEFabcdef".IndexOf(nextch1) >= 0 && "0123456789ABCDEFabcdef".IndexOf(nextch2) >= 0))
{
stringBuilder.Append("%25");
fAlreadyHandled = true;
}
break;
}
if (!fAlreadyHandled)
{
stringBuilder.Append(ch);
}
}
for (; i < chars.Count(); i++)
stringBuilder.Append(chars[i]);
return stringBuilder.ToString();
}
return text;
}
/// <summary>
/// Given a user agent string, it appends :WTE<version> to it if
/// the string is not null.
/// </summary>
public static string? GetFullUserAgentString(string? userAgent)
{
#if NET472
if(string.IsNullOrEmpty(userAgent))
return null;
try
{
object[] o = typeof(Utility).Assembly.GetCustomAttributes(typeof(AssemblyFileVersionAttribute), false);
if (o.Length > 0 && o[0] is AssemblyFileVersionAttribute)
{
return string.Concat(userAgent, ":WTE", ((AssemblyFileVersionAttribute)o[0]).Version);
}
}
catch
{
Debug.Assert(false, "Error getting WTE version");
}
#endif
return userAgent;
}
}
internal static class ItemFilter
{
public delegate bool ItemMetadataFilter(Framework.ITaskItem iTaskItem);
public static bool ItemFilterPipelineMetadata(Framework.ITaskItem item, string metadataName, string metadataValue, bool fIgnoreCase)
{
#if NET472
return (string.Compare(item.GetMetadata(metadataName), metadataValue, fIgnoreCase, CultureInfo.InvariantCulture) == 0);
#else
return (string.Compare(item.GetMetadata(metadataName), metadataValue, fIgnoreCase) == 0);
#endif
}
public static bool ItemFilterExcludeTrue(Framework.ITaskItem iTaskItem)
{
string metadataName = PipelineMetadata.Exclude.ToString();
return ItemFilterPipelineMetadata(iTaskItem, metadataName, "true", true);
}
}
}
|