using ServiceClientGenerator.Endpoints; using ServiceClientGenerator.Endpoints.Tests; using System; using System.Collections.Generic; using System.IO; using System.Text; namespace ServiceClientGenerator { /// /// Represents the information for generating the code for a service /// public class ServiceConfiguration { private const string amazonDotPrefix = "Amazon."; private string _modelPath; private string _paginatorsPath; /// /// The name of the model, taken from the "model" entry in the service models /// manifest. /// public string ModelName { get; set; } /// /// Path to the model that is represented by these attributes /// public string ModelPath { get { return this._modelPath; } set { this._serviceModel = null; this._modelPath = value; } } /// /// Path to the paginators for a service /// public string PaginatorsPath { get { return this._paginatorsPath; } set { this._paginatorsPath = value; } } ServiceModel _serviceModel; /// /// The ServiceModel object, used to parse information inside of the model*.normal.json file as well as any customizations /// public ServiceModel ServiceModel { get { if (this._serviceModel == null) { this._serviceModel = this._paginatorsPath != null ? new ServiceModel(this.ModelPath, this.CustomizationsPath, this._paginatorsPath) : new ServiceModel(this.ModelPath, this.CustomizationsPath); } return this._serviceModel; } } string _customizationsPath; /// /// Path to the file used for customizations /// public string CustomizationsPath { get { return this._customizationsPath; } set { // Cause the service model to reload with customizations this._serviceModel = null; this._customizationsPath = value; } } private static string SanitizeStringForClassName(string name) { if (null == name) return null; string className = name; className = className.Replace("AWS", ""); className = className.Replace("Amazon", ""); // concatenate all the words by removing whitespace. className = System.Text.RegularExpressions.Regex.Replace(className, @"[^a-zA-Z0-9]", ""); return className.ToUpperFirstCharacter(); } private string _className; /// /// The base name used in the client and the top level request class for a service /// public string ClassName { get { if (!string.IsNullOrEmpty(_className)) { return _className; } if (ClassNameOverride != null) { _className = ClassNameOverride; } else if (!string.IsNullOrEmpty(this.LegacyServiceId)) { //Use legacy service class name calculation if (this.ServiceModel.ServiceAbbreviation != null) { _className = SanitizeStringForClassName(_serviceModel.ServiceAbbreviation); } else if (this.ServiceModel.ServiceFullName != null) { _className = SanitizeStringForClassName(_serviceModel.ServiceFullName); } else { throw new InvalidDataException("Generator was not able to determine the ClassName for a service."); } } else { //All new services will not have a legacy-service-id metadata property value which indicates that they //must use the ServiceId for the class name. if (string.IsNullOrEmpty(this.ServiceId)) { throw new InvalidDataException( "Generator was not able to determine the ClassName for a service."); } _className = SanitizeStringForClassName(this.ServiceId); } return _className; } } /// /// Classname can be overriden by setting "base-name" in metadata.json /// public string ClassNameOverride { get; set; } string _namespace; /// /// The namespace of the service, if not specified it is Amazon.ClassName /// public string Namespace { get { if (string.IsNullOrEmpty(this._namespace)) return amazonDotPrefix + this.ClassName; return this._namespace; } set { this._namespace = value; } } // Base name in the manifest is not a reliable source of info, as if append-service // is set 'Service' gets appended and in the case of IAM then sends us to the wrong folder. // Instead we'll use the namespace and rip off any Amazon. prefix. This also helps us // handle versioned namespaces too. public string ServiceFolderName { get { var serviceNameRoot = this.Namespace.StartsWith("Amazon.", StringComparison.Ordinal) ? this.Namespace.Substring(7) : this.Namespace; return serviceNameRoot; } } public string TestCategory { get { return ServiceFolderName; } } public string AssemblyTitle { get { return this.Namespace.Replace(amazonDotPrefix, "AWSSDK."); } } public string AssemblyDescription( string versionIdentifier = "", bool includePreamble = true, bool includeBody = true, bool includePostamble = true) { if (!string.IsNullOrEmpty(versionIdentifier) && !versionIdentifier.StartsWith("(")) versionIdentifier = $"({versionIdentifier})"; var preamble = includePreamble ? $"The Amazon Web Services SDK for .NET {versionIdentifier} - " : ""; string body = ""; if (includeBody) { body = !string.IsNullOrEmpty(ServiceModel.ServiceFullName) ? $"{ServiceModel.ServiceFullName}. " : $"{ServiceId}. "; } var postamble = includePostamble ? $"{ (!string.IsNullOrEmpty(Synopsis) ? Synopsis : ServiceId) }" : ""; return $"{preamble}{body}{postamble}"; } public string BaseException { get { var baseException = string.Format("Amazon{0}Exception", this.IsChildConfig ? this.ParentConfig.ClassName : this.ClassName); return baseException; } } /// /// An option suffix added on to the end of the Nuget package title. /// public string NugetPackageTitleSuffix { get; set; } // Base name in the manifest is not a reliable source of info, as if append-service // is set 'Service' gets appended and in the case of IAM then sends us to the wrong folder. // Instead we'll use the namespace and rip off any Amazon. prefix. This also helps us // handle versioned namespaces too. public string ServiceNameRoot { get { var serviceNameRoot = this.Namespace.StartsWith(amazonDotPrefix, StringComparison.Ordinal) ? this.Namespace.Substring(amazonDotPrefix.Length) : this.Namespace; return serviceNameRoot; } } public bool InPreview {get; set;} public bool HasOverrideNamespace { get { return !string.IsNullOrEmpty(this._namespace); } } public string RegionLookupName { get { return this.ServiceModel.EndpointPrefix; } } public string LegacyServiceId { get; set; } public string ServiceId { get { if (!string.IsNullOrEmpty(ServiceModel.ServiceId)) return ServiceModel.ServiceId; //ServiceID is required, but there are a few services that were created before that requirement if(!string.IsNullOrEmpty(LegacyServiceId)) { return LegacyServiceId; } //If it's a newer service, then the ServiceId field is required throw new Exception($"Invalid Service Model: Missing required {ServiceModel.ServiceIdKey}"); } } public string AuthenticationServiceName { get { return this.ServiceModel.SigningName != null ? this.ServiceModel.SigningName : this.ServiceModel.EndpointPrefix; } } public int? OverrideMaxRetries { get; set; } public string DefaultRegion { get; set; } public bool GenerateConstructors { get; set; } public string LockedApiVersion { get; set; } public string Synopsis { get; set; } public Dictionary ServiceDependencies { get; set; } public string LicenseUrl { get; set; } public bool RequireLicenseAcceptance { get; set; } public Dictionary> ReferenceDependencies { get; set; } public Dictionary> NugetDependencies { get; set; } public List Tags { get; set; } public bool NetStandardSupport { get; set; } public bool GeneratedEventStreamException { get; set; } public string ServiceVersion { get { if (!string.IsNullOrEmpty(this.ServiceAssemblyVersionOverride)) { return ServiceAssemblyVersionOverride; } return Utils.GetVersion(ServiceFileVersion); } } public string ServiceFileVersion { get; set; } /// /// If specified this overrides the AssemblyVersion for the service package in AssemblyInfo.cs. /// Assembly version defaults to x.y of ServiceFileVersion if this is not specified. /// public string ServiceAssemblyVersionOverride { get; set; } public bool SkipV1 { get; set; } public bool IsChildConfig { get { return this.ParentConfig != null; } } private ServiceConfiguration _parentConfig; public ServiceConfiguration ParentConfig { get { return _parentConfig; } set { _parentConfig = value; ServiceModel.ParentModel = value.ServiceModel; } } public string ServiceDirectoryName { get { var directory = Path.GetDirectoryName(ModelPath); var directoryName = Path.GetFileName(directory); return directoryName; } } public string DisplayModelPath { get { return Path.GetFileName(ModelPath); } } public bool IsTestService { get; set; } public RuleSet EndpointsRuleSet { get; set; } public EndpointTests EndpointTests { get; set; } public override string ToString() { return string.Format("{0} - {1}", this.Namespace, this.ModelPath); } } public class Dependency { public string Name { get; set; } public string Version { get; set; } public string HintPath { get; set; } public static Dependency ParseJson(Json.LitJson.JsonData data) { return new Dependency { Name = data.SafeGetString("name"), Version = data.SafeGetString("version"), HintPath = data.SafeGetString("hintPath"), }; } } }