/******************************************************************************* * Copyright 2012-2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. * Licensed under the Apache License, Version 2.0 (the "License"). You may not use * this file except in compliance with the License. A copy of the License is located at * * http://aws.amazon.com/apache2.0 * * or in the "license" file accompanying this file. * This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR * CONDITIONS OF ANY KIND, either express or implied. See the License for the * specific language governing permissions and limitations under the License. * ***************************************************************************** * * AWS Tools for Windows (TM) PowerShell (TM) * */ using System; using System.Collections.Generic; using System.Reflection; using Amazon.Util.Internal; using System.Collections.ObjectModel; namespace Amazon.PowerShell.Common { [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = true)] public class AWSCmdletAttribute : Attribute { public string Synopsis { get; private set; } public string[] Operation { get; set; } public string LegacyAlias { get; set; } public Type SelectReturnType { get; set; } public AWSCmdletAttribute(string synopsis) { if (string.IsNullOrEmpty(synopsis)) throw new ArgumentNullException("synopsis"); Synopsis = synopsis; } public static AWSCmdletAttribute GetAttributeInstanceOnType(Type t, bool inherit) { var attributeTypeInfo = TypeFactory.GetTypeInfo(typeof(AWSCmdletAttribute)); var customAttributes = TypeFactory.GetTypeInfo(t).GetCustomAttributes(attributeTypeInfo, inherit); if (customAttributes.Length != 1) return null; #if CORECLR // later versions of PowerShell 6 fixed the reflection-only context issue and we can cast directly // as the attribute type (attempting to cast to CustomAttributeData fails with a null exception in // those later versions) var awsCmdletAttributeInstance = customAttributes[0] as AWSCmdletAttribute; if (awsCmdletAttributeInstance != null) return awsCmdletAttributeInstance; return ConstructFromReflectionOnlyContext(customAttributes[0] as CustomAttributeData); #else return customAttributes[0] as AWSCmdletAttribute; #endif } #if CORECLR /// /// Reflection-only contexts (as in coreclr reflection) do not allow us to cast a CustomAttributeData /// instance to the actual attribute type (whereas full framework environments do). This helper /// does the work of extracting the values supplied to the constructor and instantiates an instance /// based on those values so outer reflection code can work with the real attribute type. /// /// /// private static AWSCmdletAttribute ConstructFromReflectionOnlyContext(CustomAttributeData cad) { var ctorArgs = cad.ConstructorArguments; var synopsis = ctorArgs[0].Value.ToString(); List operations = new List(); var namedArguments = cad.NamedArguments; foreach (var namedArgument in namedArguments) { if (namedArgument.MemberName.Equals("Operation", StringComparison.Ordinal)) { var tv = namedArgument.TypedValue; foreach (CustomAttributeTypedArgument v in (ReadOnlyCollection)tv.Value) { operations.Add(v.ToString().Trim('"')); } break; } } return new AWSCmdletAttribute(synopsis) { Operation = operations.ToArray() }; } #endif } [AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited = true)] public class AWSCmdletOutputAttribute : Attribute { public string ReturnType { get; set; } public string Description { get; set; } public AWSCmdletOutputAttribute(string returnType, string description) { this.ReturnType = returnType; this.Description = description; } public AWSCmdletOutputAttribute(string returnType, params string[] descriptions) { this.ReturnType = returnType; this.Description = string.Join(Environment.NewLine, descriptions); } } [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)] public class AWSClientCmdletAttribute : Attribute { public string ServiceName { get; private set; } public string ServicePrefix { get; private set; } public string Version { get; private set; } public string ModuleName { get; private set; } public AWSClientCmdletAttribute(string serviceName, string servicePrefix, string version, string moduleName) { if (string.IsNullOrEmpty(serviceName)) throw new ArgumentNullException("serviceName"); if (string.IsNullOrEmpty(servicePrefix)) throw new ArgumentNullException("servicePrefix"); if (string.IsNullOrEmpty(moduleName)) throw new ArgumentNullException("moduleName"); ServiceName = serviceName; ServicePrefix = servicePrefix; Version = version; ModuleName = moduleName; } public static AWSClientCmdletAttribute GetAttributeInstanceOnType(Type t, bool inherit) { var attributeTypeInfo = TypeFactory.GetTypeInfo(typeof(AWSClientCmdletAttribute)); var customAttributes = TypeFactory.GetTypeInfo(t).GetCustomAttributes(attributeTypeInfo, inherit); if (customAttributes.Length != 1) return null; #if CORECLR // later versions of PowerShell 6 fixed the reflection-only context issue and we can cast directly // as the attribute type (attempting to cast to CustomAttributeData fails with a null exception in // those later versions) var awsClientCmdletAttributeInstance = customAttributes[0] as AWSClientCmdletAttribute; if (awsClientCmdletAttributeInstance != null) return awsClientCmdletAttributeInstance; return ConstructFromReflectionOnlyContext(customAttributes[0] as CustomAttributeData); #else return customAttributes[0] as AWSClientCmdletAttribute; #endif } #if CORECLR /// /// Reflection-only contexts (as in coreclr reflection) do not allow us to cast a CustomAttributeData /// instance to the actual attribute type (whereas full framework environments do). This helper /// does the work of extracting the values supplied to the constructor and instantiates an instance /// based on those values so outer reflection code can work with the real attribute type. /// /// /// private static AWSClientCmdletAttribute ConstructFromReflectionOnlyContext(CustomAttributeData cad) { var ctorArgs = cad.ConstructorArguments; var serviceName = ctorArgs[0].Value.ToString(); var servicePrefix = ctorArgs[1].Value.ToString(); var version = ctorArgs[2].Value.ToString(); var moduleName = ctorArgs[3].Value.ToString(); return new AWSClientCmdletAttribute(serviceName, servicePrefix, version, moduleName); } #endif } /// /// /// Attribute used to tag parameters that expose ConstantClass-derived types, for which /// parameter intellisense could be provided via either ValidateSet attribution or /// parameter argument completion. /// /// /// Generated cmdlets do not use the actual attribute since we know the parameter type at /// generation time and can therefore easily emit the ValidateSet attribution or parameter /// completer. For hand-coded cmdlets we have no reflected property type and don't want /// to write a C# parser! In thus scenario this attribute (a) is used to point the generator /// at the SDK type we should use to obtain the values and (b) easily marks parameters for /// our textual parser to spot. /// /// [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false, Inherited = true)] public class AWSConstantClassSourceAttribute : Attribute { /// /// The type name of the class derived from ConstantClass that contains the /// valid values according to the service model for the parameter value. /// public string ConstantClassType { get; set; } public AWSConstantClassSourceAttribute(string constantClassType) { if (string.IsNullOrEmpty(constantClassType)) throw new ArgumentNullException("constantClassType"); ConstantClassType = constantClassType; } } [AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = true)] public class AWSRequiredParameterAttribute : Attribute { public string[] ParameterSets { get; set; } } }