/// <summary> /// Generates Go code for service client. /// </summary> /// <param name="serviceClient"></param> /// <returns></returns> public override async Task Generate(CodeModel cm) { var folder = Path.GetFullPath(Settings.Instance.Host.GetValue <string>("output-folder").Result).Replace('\\', '/'); // check if the namespace contains illegal characters var ns = Settings.Instance.Host.GetValue <string>("namespace").Result; if (Settings.Instance.Host.GetValue <bool>("namespace-chk").Result) { NamespaceCheck(ns); } // if preview-chk:true is specified verify that preview swagger is output under a preview subdirectory. // this is a bit of a hack until we have proper support for this in the swagger->sdk bot so it's opt-in. if (Settings.Instance.Host.GetValue <bool>("preview-chk").Result) { PreviewCheck(folder); } var codeModel = cm as CodeModelGo; if (codeModel == null) { throw new Exception("Code model is not a Go Code Model"); } // unfortunately there is an ordering issue here. during model generation we might // flatten some types (but not all depending on type). then during client generation // the validation codegen needs to know if a type was flattened so it can generate // the correct code, so we need to generate models before clients. // Models var modelsTemplate = new ModelsTemplate { Model = codeModel }; await Write(modelsTemplate, FormatFileName("models")); // Enums - while initially enums should be part of the models, to decrease the size of the models.go file, // we separate the enums definitions out of the models.go file var enums = codeModel.EnumTypes.Cast <EnumTypeGo>().ToList(); if (enums.Any()) { var enumsTemplate = new EnumsTemplate { Model = codeModel }; await Write(enumsTemplate, FormatFileName("enums")); } // Service client var serviceClientTemplate = new ServiceClientTemplate { Model = codeModel }; await Write(serviceClientTemplate, FormatFileName("client")); // by convention the methods in the method group with an empty // name go into the client template so skip them here. HashSet <string> ReservedFiles = new HashSet <string>(StringComparer.OrdinalIgnoreCase) { "models", "client", "version", "interfaces", "enums", }; foreach (var methodGroup in codeModel.MethodGroups.Where(mg => !string.IsNullOrEmpty(mg.Name))) { if (ReservedFiles.Contains(methodGroup.Name.Value)) { methodGroup.Name += "group"; } ReservedFiles.Add(methodGroup.Name); var methodGroupTemplate = new MethodGroupTemplate { Model = methodGroup }; await Write(methodGroupTemplate, FormatFileName(methodGroup.Name).ToLowerInvariant()); } // interfaces var interfacesTemplate = new InterfacesTemplate { Model = codeModel }; await Write(interfacesTemplate, FormatFileName($"{CodeNamerGo.InterfacePackageName(codeModel.Namespace)}/interfaces")); // Version var versionTemplate = new VersionTemplate { Model = codeModel }; await Write(versionTemplate, FormatFileName("version")); // go.mod file, opt-in by specifying the gomod-root arg var modRoot = Settings.Instance.Host.GetValue <string>("gomod-root").Result; if (!string.IsNullOrWhiteSpace(modRoot)) { var i = folder.IndexOf(modRoot); if (i == -1) { throw new Exception($"didn't find module root '{modRoot}' in output path '{folder}'"); } var goVersion = Settings.Instance.Host.GetValue <string>("go-version").Result; if (string.IsNullOrWhiteSpace(goVersion)) { goVersion = defaultGoVersion; } // module name is everything to the right of the start of the module root var gomodTemplate = new GoModTemplate { Model = new GoMod(folder.Substring(i), goVersion) }; await Write(gomodTemplate, $"{StagingDir()}go.mod"); } // metadata var metadataOutputFolder = Settings.Instance.Host.GetValue <string>("metadata-output-folder").Result; if (!string.IsNullOrWhiteSpace(metadataOutputFolder)) { var metadataTemplate = new MetadataTemplate { Model = new MetadataGo(Settings.Instance.Host.GetValue <string[]>("input-file").Result, folder, ns) }; var tag = Settings.Instance.Host.GetValue <string>("tag").Result; await Write(metadataTemplate, $"{metadataOutputFolder}/{tag}.json"); } }
/// <summary> /// Generates Go code for service client. /// </summary> /// <param name="serviceClient"></param> /// <returns></returns> public override async Task Generate(CodeModel cm) { // if preview-chk:true is specified verify that preview swagger is output under a preview subdirectory. // this is a bit of a hack until we have proper support for this in the swagger->sdk bot so it's opt-in. if (Settings.Instance.Host.GetValue <bool>("preview-chk").Result) { const string previewSubdir = "/preview/"; var files = await Settings.Instance.Host.GetValue <string[]>("input-file"); // only evaluate composite builds if all swaggers are preview as we don't have a well-defined model for mixed preview/stable swaggers if (files.All(file => file.IndexOf(previewSubdir) > -1) && Settings.Instance.Host.GetValue <string>("output-folder").Result.IndexOf(previewSubdir) == -1) { throw new InvalidOperationException($"codegen for preview swagger {files[0]} must be under a preview subdirectory"); } } var codeModel = cm as CodeModelGo; if (codeModel == null) { throw new Exception("Code model is not a Go Code Model"); } // unfortunately there is an ordering issue here. during model generation we might // flatten some types (but not all depending on type). then during client generation // the validation codegen needs to know if a type was flattened so it can generate // the correct code, so we need to generate models before clients. // Models var modelsTemplate = new ModelsTemplate { Model = codeModel }; await Write(modelsTemplate, FormatFileName("models")); // Service client var serviceClientTemplate = new ServiceClientTemplate { Model = codeModel }; await Write(serviceClientTemplate, FormatFileName("client")); // by convention the methods in the method group with an empty // name go into the client template so skip them here. HashSet <string> ReservedFiles = new HashSet <string>(StringComparer.OrdinalIgnoreCase) { "models", "client", "version", "interfaces", }; foreach (var methodGroup in codeModel.MethodGroups.Where(mg => !string.IsNullOrEmpty(mg.Name))) { if (ReservedFiles.Contains(methodGroup.Name.Value)) { methodGroup.Name += "group"; } ReservedFiles.Add(methodGroup.Name); var methodGroupTemplate = new MethodGroupTemplate { Model = methodGroup }; await Write(methodGroupTemplate, FormatFileName(methodGroup.Name).ToLowerInvariant()); } // interfaces var interfacesTemplate = new InterfacesTemplate { Model = codeModel }; await Write(interfacesTemplate, FormatFileName($"{CodeNamerGo.InterfacePackageName(codeModel.Namespace)}/interfaces")); // Version var versionTemplate = new VersionTemplate { Model = codeModel }; await Write(versionTemplate, FormatFileName("version")); // go.mod file, opt-in by specifying the gomod-root arg var modRoot = Settings.Instance.Host.GetValue <string>("gomod-root").Result; if (!string.IsNullOrWhiteSpace(modRoot)) { var normalized = Settings.Instance.Host.GetValue <string>("output-folder").Result.Replace('\\', '/'); var i = normalized.IndexOf(modRoot); if (i == -1) { throw new Exception($"didn't find module root '{modRoot}' in output path '{normalized}'"); } // module name is everything to the right of the start of the module root var gomodTemplate = new GoModTemplate { Model = new GoMod(normalized.Substring(i)) }; await Write(gomodTemplate, $"{StagingDir()}go.mod"); } }