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;
}