|
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
///--------------------------------------------------------------------------------------------
/// VSMSDeployObject.cs
///
/// Common utility function
///
/// Copyright(c) 2006 Microsoft Corporation
///--------------------------------------------------------------------------------------------
using Microsoft.NET.Sdk.Publish.Tasks.Properties;
using Diagnostics = System.Diagnostics;
// using Deployment = Microsoft.Web.Deployment;
using RegularExpressions = System.Text.RegularExpressions;
// we need to think of a way to split the MSDeployment to other dll
// using VSMSDeploySyncOption = Deployment.DeploymentSyncOptions;
namespace Microsoft.NET.Sdk.Publish.Tasks.MsDeploy
{
static class VSMSDeployObjectFactory
{
/// <summary>
/// Create a object base on msbuild task item
/// </summary>
/// <param name="taskItem"></param>
/// <returns></returns>
public static VSMSDeployObject CreateVSMSDeployObject(Build.Framework.ITaskItem taskItem)
{
VSMSDeployObject src = new(taskItem);
return src;
}
/// <summary>
/// Create a simple object (no password)
/// </summary>
/// <param name="provider"></param>
/// <param name="path"></param>
/// <returns></returns>
public static VSMSDeployObject CreateVSMSDeployObject(string provider, string path)
{
VSMSDeployObject src = new(provider, path);
return src;
}
}
/// <summary>
/// Utility class to abstract the multiple MSDeploy object for various scenario
/// It also make sure the Dispose is called properly for MSDeploy object
/// </summary>
internal static class MSDeployUtility
{
/// <summary>
/// Utility function to create DeploymentBaseOptions base on current vsMsDeployObject
/// </summary>
/// <param name="vSMSDeployObject"></param>
/// <returns></returns>
public static /*Deployment.DeploymentBaseOptions*/ dynamic? CreateBaseOptions(VSMSDeployObject vSMSDeployObject)
{
// /*Deployment.DeploymentBaseOptions*/dynamic baseOptions = new Microsoft.Web.Deployment.DeploymentBaseOptions();
/*Deployment.DeploymentBaseOptions*/
dynamic? baseOptions = MSWebDeploymentAssembly.DynamicAssembly?.CreateObject("Microsoft.Web.Deployment.DeploymentBaseOptions");
if (baseOptions is not null)
{
if (vSMSDeployObject.IsLocal)
{
// do nothing
}
else if (!vSMSDeployObject.UseSeparatedCredential)
{
baseOptions.ComputerName = vSMSDeployObject.ComputerName;
}
else
{
baseOptions.ComputerName = vSMSDeployObject.ComputerName;
baseOptions.UserName = vSMSDeployObject.UserName;
baseOptions.Password = vSMSDeployObject.Password;
}
baseOptions.PrefetchPayload = vSMSDeployObject.PrefetchPayload;
baseOptions.IncludeAcls = vSMSDeployObject.IncludeAcls;
if (!string.IsNullOrEmpty(vSMSDeployObject.AuthenticationType))
{
baseOptions.AuthenticationType = vSMSDeployObject.AuthenticationType;
}
if (string.Equals(Guid.Empty.ToString(), vSMSDeployObject.UserName, StringComparison.OrdinalIgnoreCase))
{
baseOptions.AuthenticationType = "Bearer";
}
if (!string.IsNullOrEmpty(vSMSDeployObject.EncryptPassword))
baseOptions.EncryptPassword = vSMSDeployObject.EncryptPassword;
if (!string.IsNullOrEmpty(vSMSDeployObject.WebServerManifest))
baseOptions.WebServerConfiguration.WebServerManifest = Path.GetFileName(vSMSDeployObject.WebServerManifest);
if (!string.IsNullOrEmpty(vSMSDeployObject.WebServerDirectory))
baseOptions.WebServerConfiguration.WebServerDirectory = vSMSDeployObject.WebServerDirectory;
if (!string.IsNullOrEmpty(vSMSDeployObject.WebServerAppHostConfigDirectory))
baseOptions.WebServerConfiguration.ConfigurationDirectory = vSMSDeployObject.WebServerAppHostConfigDirectory;
if (vSMSDeployObject.RetryInterval >= 0)
baseOptions.RetryInterval = vSMSDeployObject.RetryInterval;
if (vSMSDeployObject.RetryAttempts >= 0)
baseOptions.RetryAttempts = vSMSDeployObject.RetryAttempts;
if (!string.IsNullOrEmpty(vSMSDeployObject.UserAgent))
baseOptions.UserAgent = vSMSDeployObject.UserAgent;
//remove duplicate items appearing in both "EnableLinks" and "DisableLinks" caused by the default value set by publish target file
List<string> enabledLinkList = ConvertStringIntoList(vSMSDeployObject.EnableLinks);
List<string> disabledLinkList = ConvertStringIntoList(vSMSDeployObject.DisableLinks);
foreach (string link in disabledLinkList)
{
if (LinkContainedInTheCollection(link, enabledLinkList))
enabledLinkList.Remove(link);
}
ChangeLinkExtensionEnableStatue(baseOptions, disabledLinkList, false);
ChangeLinkExtensionEnableStatue(baseOptions, enabledLinkList, true);
}
return baseOptions;
}
/// <summary>
/// Utility function to convert a string passed in from target file into a list
/// </summary>
/// <param name="linkExtensionsString"></param>
/// <returns></returns>
internal static List<string> ConvertStringIntoList(string? linkExtensionsString)
{
if (linkExtensionsString is not null && linkExtensionsString.Length != 0)
{
string linkExtensionsInfo = linkExtensionsString;
string[] linksArray = linkExtensionsInfo.Split(new char[] { ';' });
List<string> linksList = new(linksArray);
return linksList;
}
else
return new List<string>(0);
}
/// <summary>
/// we can't use the method of List<string>.Contains, as it is case sensitive, so have to write a separate comparison routine
/// </summary>
/// <param name="link"></param>
/// <param name="linkCollection"></param>
/// <returns></returns>
internal static bool LinkContainedInTheCollection(string link, List<string> linkCollection)
{
foreach (string l in linkCollection)
if (string.Compare(l, link, StringComparison.OrdinalIgnoreCase) == 0)
return true;
return false;
}
/// <summary>
/// Utility function to enable a list of LinkExtensions
/// </summary>
/// <param name="baseOptions"></param>
/// <param name="listOfLinkExtensions"></param>
/// <param name="enable"></param>
public static void ChangeLinkExtensionEnableStatue(/*Deployment.DeploymentBaseOptions*/ dynamic baseOptions, string listOfLinkExtensions, bool enable)
{
if (!string.IsNullOrEmpty(listOfLinkExtensions))
{
List<string> linkExtensionList = ConvertStringIntoList(listOfLinkExtensions);
ChangeLinkExtensionEnableStatue(baseOptions, linkExtensionList, enable);
}
}
/// <summary>
/// Utility function to enable a list of LinkExtensions
/// </summary>
/// <param name="baseOptions"></param>
/// <param name="linkExtensions"></param>
/// <param name="enable"></param>
public static void ChangeLinkExtensionEnableStatue(/*Deployment.DeploymentBaseOptions*/ dynamic baseOptions, List<string> linkExtensions, bool enable)
{
if (linkExtensions is not null && linkExtensions.Count != 0)
{
foreach (string linkExtObj in linkExtensions)
{
RegularExpressions.Regex match = new(linkExtObj, RegularExpressions.RegexOptions.IgnoreCase);
List<object> matchedList = new();
foreach (/*Deployment.DeploymentLinkExtension*/dynamic linkExtension in baseOptions.LinkExtensions)
{
if (match.IsMatch(linkExtension.Name))
{
matchedList.Add(linkExtension);
}
}
if (matchedList.Count > 0)
{
foreach (/*Deployment.DeploymentLinkExtension*/dynamic extension in matchedList)
{
extension.Enabled = enable;
}
}
else
{
// throw new DeploymentException(Resources.UnknownLinkExtension, disableLink);
//$Todo lmchen
//Diagnostics.Debug.Assert(false, "NYI, we should prompt user for invalid LinkExtension");
throw new InvalidOperationException("UnknowLinkExtension");
}
}
}
}
}
/// <summary>
/// Abstract interface to allow homogeneous SynTo() operation to work regardless of the object
/// </summary>
internal class VSMSDeployObject
{
public VSMSDeployObject(string provider, string root)
{
m_NameValueDictionary.Clear();
m_root = string.IsNullOrEmpty(root) ? string.Empty : root;
// our code path should only take a well known provider
Diagnostics.Debug.Assert(Utility.IsDeploymentWellKnownProvider(provider));
m_provider = provider;
// maybe we should show the "secure data to display"
// for now just suppress it.
#if NET472
if (0 == string.Compare(m_provider, MSWebDeploymentAssembly.DynamicAssembly?.GetEnumValue(MSDeploy.TypeName.DeploymentWellKnownProvider, MSDeploy.Provider.DBFullSql)?.ToString(), StringComparison.InvariantCultureIgnoreCase)
|| 0 == string.Compare(m_provider, MSDeploy.Provider.DbDacFx , StringComparison.InvariantCultureIgnoreCase))
m_fNoDisplayRoot = true;
#else
if (0 == string.Compare(m_provider, MSWebDeploymentAssembly.DynamicAssembly?.GetEnumValue(MSDeploy.TypeName.DeploymentWellKnownProvider, MSDeploy.Provider.DBFullSql)?.ToString())
|| 0 == string.Compare(m_provider, MSDeploy.Provider.DbDacFx, StringComparison.OrdinalIgnoreCase))
m_fNoDisplayRoot = true;
#endif
}
public VSMSDeployObject(Build.Framework.ITaskItem taskItem)
{
Diagnostics.Debug.Assert(taskItem != null);
if (taskItem is null)
{
// This constructor would spectacularly fail if taskItem is null. Just get out in this situation.
return;
}
m_provider = taskItem.ItemSpec;
m_root = taskItem.GetMetadata("Path");
if (string.IsNullOrEmpty(m_root))
m_root = string.Empty;
// our code path should only take a well known provider
Diagnostics.Debug.Assert(Utility.IsDeploymentWellKnownProvider(m_provider));
// maybe we should show the "secure data to display"
// for now just suppress it.
if (0 == string.Compare(m_provider, MSWebDeploymentAssembly.DynamicAssembly?.GetEnumValue(MSDeploy.TypeName.DeploymentWellKnownProvider, MSDeploy.Provider.DBFullSql)?.ToString(), StringComparison.OrdinalIgnoreCase))
m_fNoDisplayRoot = true;
m_NameValueDictionary.Clear();
foreach (string name in taskItem.MetadataNames)
{
if (!Utility.IsInternalMsdeployWellKnownItemMetadata(name))
{
string value = taskItem.GetMetadata(name);
if (!string.IsNullOrEmpty(value))
{
if (Utility.IsMsDeployWellKnownLocationInfo(name))
{
m_NameValueDictionary.Add(name, value);
}
else
{
// these are provider option
SetProviderOption(m_provider, name, value);
}
}
}
else
{
Utility.IISExpressMetadata expressMetadata;
if (Enum.TryParse(name, out expressMetadata))
{
string value = taskItem.GetMetadata(name);
if (!string.IsNullOrEmpty(value))
{
m_NameValueDictionary.Add(expressMetadata.ToString(), value);
}
}
}
}
}
public VSMSDeployObject(Build.Framework.ITaskItem taskItem, bool fNoDisplayRoot)
: this(taskItem)
{
m_fNoDisplayRoot = fNoDisplayRoot;
}
private string? GetDictionaryValue(string name)
{
string? value = null;
if (m_NameValueDictionary != null)
{
m_NameValueDictionary.TryGetValue(name, out value);
}
return value;
}
private void SetDictionaryValue(string name, string? value)
{
Diagnostics.Debug.Assert(m_NameValueDictionary != null);
if (m_NameValueDictionary is not null && m_NameValueDictionary.ContainsKey(name))
{
m_NameValueDictionary[name] = value;
}
else
{
m_NameValueDictionary?.Add(name, value);
}
}
protected string m_root = string.Empty;
protected string m_disableLinks = string.Empty;
protected string m_enableLinks = string.Empty;
protected string m_provider = "Package";
protected bool m_fNoDisplayRoot = false;
protected int m_retryInterval = -1;
protected int m_retryAttempts = -1;
IList<ParameterInfo> m_iListParameter = new List<ParameterInfo>();
IList<ProviderOption> m_iListProviderOption = new List<ProviderOption>();
IList<ParameterInfoWithEntry> m_iListParameterWithEntry = new List<ParameterInfoWithEntry>();
IList<string> m_iListSetParametersFiles = new List<string>();
private Dictionary<string, string?> m_NameValueDictionary = new(10, StringComparer.OrdinalIgnoreCase);
protected /*Deployment.DeploymentBaseOptions*/ dynamic? m_deploymentBaseOptions = null;
public override string ToString()
{
string root = m_fNoDisplayRoot ? "******" : m_root;
return string.Format(System.Globalization.CultureInfo.CurrentCulture, Resources.VSMSDEPLOY_ObjectIdentity, m_provider.ToString(), root);
}
// property used to call Deployment.DeploymentManager.CreateObject
public virtual string Root
{
get { return m_root; }
set { m_root = value; }
}
public virtual string Provider
{
get { return m_provider; }
set { m_provider = value; }
}
// property use to create the LocationInfo
public virtual bool IsLocal
{
get { return string.IsNullOrEmpty(ComputerName) && string.IsNullOrEmpty(MSDeployServiceUrl); }
}
public virtual bool UseSeparatedCredential
{
get { return !string.IsNullOrEmpty(UserName); }
}
public virtual string DisableLinks
{
get { return m_disableLinks; }
set { m_disableLinks = value; }
}
public virtual string EnableLinks
{
get { return m_enableLinks; }
set { m_enableLinks = value; }
}
// <ComputerName></ComputerName>
//<Wmsvc></Wmsvc> -------------------------// bugbug, not supported yet
//<UserName></UserName>
//<Password></Password>
//<EncryptPassword></EncryptPassword>
//<IncludeAcls></IncludeAcls>
//<authType></authType>
//<prefetchPayload></prefetchPayload>
public virtual string? ComputerName
{
get { return GetDictionaryValue("computerName"); }
set { SetDictionaryValue("computerName", value); }
}
public virtual string? UserName
{
get { return GetDictionaryValue("userName"); }
set { SetDictionaryValue("userName", value); }
}
public virtual string? Password
{
get { return GetDictionaryValue("password"); }
set { SetDictionaryValue("password", value); }
}
// Note this support is still broken for vsmsdeploy
public string? MSDeployServiceUrl
{
get
{
string? value = GetDictionaryValue("wmsvc");
Diagnostics.Debug.Assert(string.IsNullOrEmpty(value), "Not yet implement");
return value;
}
set
{
Diagnostics.Debug.Assert(false, "Not yet implement");
SetDictionaryValue("wmsvc", value);
}
}
public string? AuthenticationType
{
get
{
string? authType = GetDictionaryValue("authType");
if (string.IsNullOrEmpty(authType))
{
if (!string.IsNullOrEmpty(MSDeployServiceUrl) && string.IsNullOrEmpty(ComputerName))
{
authType = "Basic";
}
}
return authType;
}
set { SetDictionaryValue("authType", value); }
}
public string? EncryptPassword
{
get { return GetDictionaryValue("encryptPassword"); }
set { SetDictionaryValue("encryptPassword", value); }
}
public bool IncludeAcls
{
get { return Convert.ToBoolean(GetDictionaryValue("includeAcls"), System.Globalization.CultureInfo.InvariantCulture); }
set { SetDictionaryValue("includeAcls", value.ToString()); }
}
public bool PrefetchPayload
{
get { return Convert.ToBoolean(GetDictionaryValue("prefetchPayload"), System.Globalization.CultureInfo.InvariantCulture); }
set { SetDictionaryValue("prefetchPayload", value.ToString()); }
}
public string? WebServerAppHostConfigDirectory
{
get { return GetDictionaryValue("WebServerAppHostConfigDirectory"); }
set { SetDictionaryValue("WebServerAppHostConfigDirectory", value); }
}
public string? WebServerDirectory
{
get { return GetDictionaryValue("WebServerDirectory"); }
set { SetDictionaryValue("WebServerDirectory", value); }
}
public string? WebServerManifest
{
get { return GetDictionaryValue("WebServerManifest"); }
set { SetDictionaryValue("WebServerManifest", value); }
}
public int RetryAttempts
{
get { return m_retryAttempts; }
set { m_retryAttempts = value; }
}
public int RetryInterval
{
get { return m_retryInterval; }
set { m_retryInterval = value; }
}
public string? UserAgent { get; set; }
public IList<ParameterInfo> Parameters
{
get { return m_iListParameter; }
}
public IList<ProviderOption> ProviderOptions
{
get { return m_iListProviderOption; }
}
public void SetProviderOption(string factoryName, string parameterName, string parameterStringValue)
{
m_iListProviderOption.Add(new ProviderOption(factoryName, parameterName, parameterStringValue));
}
public void SyncParameter(string parameterName, string parameterStringValue)
{
m_iListParameter.Add(new ParameterInfo(parameterName, parameterStringValue));
}
public IList<ParameterInfoWithEntry> EntryParameters
{
get { return m_iListParameterWithEntry; }
}
public IList<string> SetParametersFiles
{
get { return m_iListSetParametersFiles; }
}
public void SyncParameter(string name, string value, string type, string scope, string matchRegularExpression, string description, string defaultValue, string tags, string element, string validationString)
{
m_iListParameterWithEntry.Add(new ParameterInfoWithEntry(name, value, type, scope, matchRegularExpression, description, defaultValue, tags, element, validationString));
}
public void SyncParameterFile(string filename)
{
m_iListSetParametersFiles.Add(filename);
}
public void ResetBaseOptions()
{
m_deploymentBaseOptions = null;
}
public /*Deployment.DeploymentBaseOptions*/ dynamic? BaseOptions
{
get
{
if (m_deploymentBaseOptions == null)
{
m_deploymentBaseOptions = MSDeployUtility.CreateBaseOptions(this);
}
return m_deploymentBaseOptions;
}
}
public void SyncTo(VSMSDeployObject destObject, /*VSMSDeploySyncOption*/ dynamic syncOptions, IVSMSDeployHost _host)
{
#if NET472
//$BUGBUG lmchen, there is only set to source provider?
// set up the provider setting
/*Deployment.DeploymentProviderOptions*/
dynamic? srcProviderConfig = MSWebDeploymentAssembly.DynamicAssembly?.CreateObject("Microsoft.Web.Deployment.DeploymentProviderOptions", new object[]{Provider.ToString()});
if (srcProviderConfig is null)
{
return;
}
srcProviderConfig.Path = Root;
Utility.AddProviderOptions(srcProviderConfig, ProviderOptions, _host);
if (BaseOptions is null)
{
return;
}
using (/*Deployment.DeploymentObject*/ dynamic? srcObj = MSWebDeploymentAssembly.DynamicAssembly?.CallStaticMethod("Microsoft.Web.Deployment.DeploymentManager", "CreateObject", new object[]{srcProviderConfig, BaseOptions}))
{
//$BUGBUG lmchen, there is only set to source provider?
// set up the parameter
Utility.AddSetParametersFilesToObject(srcObj, SetParametersFiles, _host);
Utility.AddSimpleSetParametersToObject(srcObj, Parameters, _host);
Utility.AddSetParametersToObject(srcObj, EntryParameters, _host);
/*Deployment.DeploymentProviderOptions*/ dynamic? destProviderConfig = MSWebDeploymentAssembly.DynamicAssembly?.CreateObject("Microsoft.Web.Deployment.DeploymentProviderOptions", new object[]{destObject.Provider.ToString()});
if (destProviderConfig is null)
{
return;
}
destProviderConfig.Path = destObject.Root;
// Setup Destination Provider option
Utility.AddProviderOptions(destProviderConfig, destObject.ProviderOptions, _host);
srcObj?.SyncTo(destProviderConfig, destObject.BaseOptions, syncOptions);
}
#endif
}
}
}
|