public static async Task GenerateCode()

in codegen/src/Azure.Iot.Operations.ProtocolCompiler/CommandHandler.cs [21:179]


        public static async Task<int> GenerateCode(OptionContainer options)
        {
            try
            {
                bool isModelSpecified = options.ModelFiles.Length > 0;
                if (!isModelSpecified && options.GenNamespace == null)
                {
                    Console.WriteLine("You must specify at least one modelFile or a namespace.");
                    Console.WriteLine("In the absence of a modelFile, code will be generated from schema definitions in the workingDir, bypassing DTDL.");
                    Console.WriteLine("Use option --help for a full list of options");
                    return 1;
                }

                WarnOnSuspiciousOption("workingDir", options.WorkingDir);
                WarnOnSuspiciousOption("sdkPath", options.SdkPath);
                WarnOnSuspiciousOption("namespace", options.GenNamespace);
                WarnOnSuspiciousOption("shared", options.SharedPrefix);
                if (!options.OutDir.Exists)
                {
                    WarnOnSuspiciousOption("outDir", options.OutDir.Name);
                }

                if (!SupportedLanguages.Contains(options.Lang))
                {
                    Console.WriteLine($"language \"{options.Lang}\" not recognized.  Language must be {string.Join(" or ", SupportedLanguages.Select(l => $"'{l}'"))}");
                    return 1;
                }

                if (options.ClientOnly && options.ServerOnly)
                {
                    Console.WriteLine("options --clientOnly and --serverOnly are mutually exclusive");
                    return 1;
                }

                if (options.SharedPrefix != null && !LanguageInfos[options.Lang].SupportsSharing)
                {
                    Console.WriteLine($"option --shared is not compatible with --lang {options.Lang}");
                    return 1;
                }

                CodeName? genNamespace = options.GenNamespace != null ? new(options.GenNamespace) : null;

                Dtmi? sharedDtmi = null;
                if (options.SharedPrefix != null && (!Dtmi.TryCreateDtmi(options.SharedPrefix, out sharedDtmi) || sharedDtmi.MajorVersion != 0))
                {
                    Console.WriteLine($"shared prefix \"{options.SharedPrefix}\" must parse as a valid versionless DTMI, e.g. 'dtmi:foo:bar'");
                    return 1;
                }

                CodeName? sharedPrefix = sharedDtmi != null ? new(sharedDtmi) : null;

                string genRoot = Path.Combine(options.OutDir.FullName, options.NoProj ? string.Empty : LanguageInfos[options.Lang].GenSubdir);
                string projectName = LegalizeName(options.OutDir.Name);

                string workingPathResolved =
                    options.WorkingDir == null ? Path.Combine(options.OutDir.FullName, LanguageInfos[options.Lang].DefaultWorkingPath) :
                    Path.IsPathRooted(options.WorkingDir) ? options.WorkingDir :
                    Path.Combine(options.OutDir.FullName, options.WorkingDir);
                DirectoryInfo workingDir = new(workingPathResolved);

                if (isModelSpecified)
                {
                    if (options.ModelFiles.Any(mf => !mf.Exists))
                    {
                        Console.WriteLine("All modelFiles must exist.  Non-existent files specified:");
                        foreach (FileInfo f in options.ModelFiles.Where(mf => !mf.Exists))
                        {
                            Console.WriteLine($"  {f.FullName}");
                        }
                        return 1;
                    }

                    Dtmi? modelDtmi = null;
                    if (options.ModelId != null && !Dtmi.TryCreateDtmi(options.ModelId, out modelDtmi))
                    {
                        Console.WriteLine($"modelId \"{options.ModelId}\" is not a valid DTMI");
                        return 1;
                    }

                    string[] modelTexts = options.ModelFiles.Select(mf => mf.OpenText().ReadToEnd()).ToArray();
                    string[] modelNames = options.ModelFiles.Select(mf => mf.Name).ToArray();
                    ModelSelector.ContextualizedInterface contextualizedInterface = await ModelSelector.GetInterfaceAndModelContext(modelTexts, modelNames, modelDtmi, Console.WriteLine);

                    if (contextualizedInterface.InterfaceId == null)
                    {
                        return 1;
                    }

                    if (genNamespace == null)
                    {
                        genNamespace = new(contextualizedInterface.InterfaceId);
                    }

                    ThingGenerator thingGenerator = new ThingGenerator(contextualizedInterface.ModelDict!, contextualizedInterface.InterfaceId, contextualizedInterface.MqttVersion);

                    if (options.ThingOnly)
                    {
                        return thingGenerator.GenerateThing(options.OutDir) ? 0 : 1;
                    }

                    thingGenerator.GenerateThing(workingDir);

                    if (!SchemaGenerator.GenerateSchemas(contextualizedInterface.ModelDict!, contextualizedInterface.InterfaceId, contextualizedInterface.MqttVersion, projectName, workingDir, genNamespace, sharedPrefix))
                    {
                        return 1;
                    }
                }

                string schemaFolder = Path.Combine(workingDir.FullName, genNamespace!.GetFolderName(TargetLanguage.Independent));

                if (!Directory.Exists(schemaFolder))
                {
                    Console.WriteLine($"No '{genNamespace!.GetFolderName(TargetLanguage.Independent)}' folder found in working directory {workingDir.FullName}");
                    return 1;
                }

                foreach (string schemaFileName in Directory.GetFiles(schemaFolder))
                {
                    TypesGenerator.GenerateType(options.Lang, LanguageInfos[options.Lang].Language, projectName, schemaFileName, workingDir, genRoot, genNamespace!);
                }

                if (sharedPrefix != null)
                {
                    string sharedSchemaFolder = new(Path.Combine(workingDir.FullName, sharedPrefix.GetFolderName(TargetLanguage.Independent)));
                    if (Directory.Exists(sharedSchemaFolder))
                    {
                        foreach (string schemaFileName in Directory.GetFiles(sharedSchemaFolder))
                        {
                            TypesGenerator.GenerateType(options.Lang, LanguageInfos[options.Lang].Language, projectName, schemaFileName, workingDir, genRoot, sharedPrefix);
                        }
                    }
                }

                string[] annexFiles = Directory.GetFiles(schemaFolder, $"*.annex.json");
                switch (annexFiles.Length)
                {
                    case 0:
                        Console.WriteLine("No annex file present in working directory, so no envoy files generated");
                        break;
                    case 1:
                        EnvoyGenerator.GenerateEnvoys(options.Lang, projectName, annexFiles.First(), options.OutDir, workingDir, genRoot, genNamespace!, sharedPrefix, options.SdkPath, !options.ServerOnly, !options.ClientOnly, options.DefaultImpl, !options.NoProj);
                        break;
                    default:
                        Console.WriteLine("Multiple annex files in working directory. To generate envoy files, remove all but one annex file:");
                        foreach (string annexFile in annexFiles)
                        {
                            Console.WriteLine($"  {annexFile}");
                        }
                        return 1;
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine($"Code generation failed with exception: {ex.Message}");
                return 1;
            }

            return 0;
        }