using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Linq; using System.Management.Automation; using System.Reflection; using System.Text; using System.Threading.Tasks; namespace PSReleaseNotesGenerator { public class Cmdlet { internal const string AWSCmdletAttribute = "Amazon.PowerShell.Common.AWSCmdletAttribute"; internal const string AWSCmdletAttribute_Operation = "Operation"; internal const string AWSClientCmdletAttribute = "Amazon.PowerShell.Common.AWSClientCmdletAttribute"; internal const string AWSClientCmdletAttribute_ServiceName = "ServiceName"; internal const string AWSClientCmdletAttribute_ServicePrefix = "ServicePrefix"; private static readonly object[] NoParameters = new object[0]; public readonly Type Type; public readonly string Name; public readonly IEnumerable OutputTypes; public readonly IEnumerable Operations; public readonly string ServiceName; public readonly string ServicePrefix; public readonly string DefaultParameterSet; public readonly bool SupportsShouldProcess; public readonly ConfirmImpact ConfirmImpact; public readonly IEnumerable Parameters; public Cmdlet(Type type) { Type = type; Name = GetName(); OutputTypes = GetOutputTypes(); Operations = GetOperations(); ServiceName = GetServiceName(); ServicePrefix = GetServicePrefix(); DefaultParameterSet = GetDefaultParameterSet(); SupportsShouldProcess = GetSupportsShouldProcess(); ConfirmImpact = GetConfirmImpact(); Parameters = GetParameters(); } private string GetName() { var cmdletAttribute = Type.GetCustomAttribute(); return $"{cmdletAttribute.VerbName}-{cmdletAttribute.NounName}"; } private IEnumerable GetOutputTypes() { var outputTypes = Type.GetCustomAttributes() .SelectMany(attribute => attribute.Type) .Select(psTypeName => psTypeName.Name ?? psTypeName.Type?.FullName) .ToArray(); return new ReadOnlyCollection(outputTypes); } private IEnumerable GetOperations() { var operations = Type.GetCustomAttributes() .Where(attribute => attribute.GetType().FullName == AWSCmdletAttribute) .Select(attribute => GetProperty(attribute, AWSCmdletAttribute_Operation)) .Where(operation => operation != null) .SelectMany(operation => operation) .ToArray(); return new ReadOnlyCollection(operations); } private string GetServiceName() { var awsClientCmdletAttribute = RecursiveGetCustomAttributes(Type).FirstOrDefault(attribute => attribute.GetType().FullName == AWSClientCmdletAttribute); if (awsClientCmdletAttribute == null) return null; return FixServiceName(GetProperty(awsClientCmdletAttribute, AWSClientCmdletAttribute_ServiceName)); } private string GetServicePrefix() { var awsClientCmdletAttribute = RecursiveGetCustomAttributes(Type).FirstOrDefault(attribute => attribute.GetType().FullName == AWSClientCmdletAttribute); if (awsClientCmdletAttribute == null) return null; return GetProperty(awsClientCmdletAttribute, AWSClientCmdletAttribute_ServicePrefix); } private string GetDefaultParameterSet() { var cmdletAttribute = Type.GetCustomAttribute(); return cmdletAttribute.DefaultParameterSetName; } private bool GetSupportsShouldProcess() { var cmdletAttribute = Type.GetCustomAttribute(); return cmdletAttribute.SupportsShouldProcess; } private ConfirmImpact GetConfirmImpact() { var cmdletAttribute = Type.GetCustomAttribute(); return cmdletAttribute.ConfirmImpact; } private IEnumerable GetParameters() { var parameters = Type.GetProperties() .Where(property => { try { return property.GetCustomAttributes().Any(attribute => attribute.GetType().FullName == CmdletParameter.ParameterAttribute); } catch (TypeLoadException e) { //This is to take care of the exception resulting from the type of a property being removed from //a service assembly. Returning false here is not ideal because it effects the correctness of //the release notes. return false; } }) .Select(property => new CmdletParameter(property)) .ToList(); return new ReadOnlyCollection(parameters); } internal static T GetProperty(object o, string propertyName) { return (T) o.GetType().GetProperty(propertyName).GetGetMethod().Invoke(o, NoParameters); } private static IEnumerable RecursiveGetCustomAttributes(Type type) { while (type != null) { foreach (var attribute in type.GetCustomAttributes()) { yield return attribute; } type = type.BaseType; } } private static string FixServiceName(string name) { const string serviceNamePrefix = "Amazon "; if (name == null) return null; if (name.StartsWith("AWS ", StringComparison.OrdinalIgnoreCase)) return serviceNamePrefix + name.Substring(4); if (!name.StartsWith(serviceNamePrefix)) return serviceNamePrefix + name; return name; } } }