public async Task <int> ExecuteCore(bool generateOnly) { if (!OutputDirectory.HasValue()) { OutputDirectory.TryParse($"_output"); } var logsPath = Path.Combine(OutputDirectory.Required(), "logs"); if (Directory.Exists(logsPath)) { foreach (var file in Directory.EnumerateFiles(logsPath)) { File.Delete(file); } } var blueprint = _blueprintManager.GetBlueprintPackage(Blueprint.Required()); if (blueprint == null) { throw new ApplicationException($"Unable to locate blueprint {Blueprint.Required()}"); } var templateEngine = _templateEngineFactory.Create(new TemplateEngineOptions { FileSystem = new BlueprintPackageFileSystem(blueprint) }); var eachValues = new List <object>(); if (blueprint.Exists("values.yaml")) { using (var reader = blueprint.OpenText("values.yaml")) { eachValues.Add(_serializers.YamlDeserializer.Deserialize(reader)); } } var defaultValuesFiles = File.Exists("atlas-values.yaml") ? new[] { "atlas-values.yaml" } : File.Exists("values.yaml") ? new[] { "values.yaml" } : new string[0]; foreach (var valuesFile in Values.OptionalMany(defaultValuesFiles)) { using (var reader = File.OpenText(valuesFile)) { eachValues.Add(_serializers.YamlDeserializer.Deserialize(reader)); } } if (Set.HasValue()) { var setValues = new Dictionary <object, object>(); foreach (var set in Set.Values) { var parts = set.Split('=', 2); if (parts.Length == 1) { throw new ApplicationException("Equal sign required when using the option --set name=value"); } var name = parts[0]; var value = parts[1]; var segments = name.Split('.'); if (segments.Any(segment => string.IsNullOrEmpty(segment))) { throw new ApplicationException("Name must not have empty segments when using the option --set name=value"); } var cursor = (IDictionary <object, object>)setValues; foreach (var segment in segments.Reverse().Skip(1).Reverse()) { if (cursor.TryGetValue(segment, out var child) && child is IDictionary <object, object> ) { cursor = (IDictionary <object, object>)child; } else { child = new Dictionary <object, object>(); cursor[segment] = child; cursor = (IDictionary <object, object>)child; } } cursor[segments.Last()] = value; } eachValues.Add(setValues); } IDictionary <object, object> values = new Dictionary <object, object>(); foreach (var addValues in eachValues) { values = (IDictionary <object, object>)MergeUtils.Merge(addValues, values) ?? values; } object model; var modelTemplate = "model.yaml"; var modelExists = blueprint.Exists(modelTemplate); if (modelExists) { model = templateEngine.Render <object>(modelTemplate, values); } else { model = values; } var workflowTemplate = "workflow.yaml"; var workflowContents = new StringBuilder(); using (var workflowWriter = new StringWriter(workflowContents)) { templateEngine.Render(workflowTemplate, model, workflowWriter); } // NOTE: the workflow is rendered BEFORE writing these output files because it may contain // calls to the "secret" helper which will redact tokens that might have been provided in values // write values to output folder GenerateOutput("values.yaml", writer => _serializers.YamlSerializer.Serialize(writer, values)); if (modelExists) { // write normalized values to output folder GenerateOutput(modelTemplate, writer => templateEngine.Render(modelTemplate, values, writer)); } // write workflow to output folder GenerateOutput("workflow.yaml", writer => writer.Write(workflowContents.ToString())); var workflow = _serializers.YamlDeserializer.Deserialize <WorkflowModel>(new StringReader(workflowContents.ToString())); var patternMatcher = _patternMatcherFactory.Create(Target.Values.Any() ? Target.Values : new List <string>() { "/**" }); if (generateOnly == false) { var context = new ExecutionContext(templateEngine, patternMatcher, null); context.AddValuesIn(ProcessValues(workflow.values, context.Values)); var resultOut = await ExecuteOperations(context, workflow.operations); if (workflow.output != null) { context.AddValuesOut(ProcessValues(workflow.output, MergeUtils.Merge(resultOut, context.Values) ?? context.Values)); } else { context.AddValuesOut(resultOut); } if (context.ValuesOut != null) { GenerateOutput("output.yaml", writer => _serializers.YamlSerializer.Serialize(writer, context.ValuesOut)); using (var writer = _secretTracker.FilterTextWriter(_console.Out)) { _serializers.YamlSerializer.Serialize(writer, context.ValuesOut); } } } return(0); }
public (ITemplateEngine templateEngine, WorkflowModel workflow, object effectiveValues) Load(IBlueprintPackage blueprint, object values, Action <string, Action <TextWriter> > generateOutput) { var templateEngine = _templateEngineFactory.Create(new TemplateEngineOptions { FileSystem = new BlueprintPackageFileSystem(blueprint) }); var providedValues = values; if (blueprint.Exists("values.yaml")) { using (var reader = blueprint.OpenText("values.yaml")) { var defaultValues = _serializers.YamlDeserializer.Deserialize(reader); if (values == null) { values = defaultValues; } else { values = MergeUtils.Merge(values, defaultValues); } } } var premodelValues = values; if (blueprint.Exists("model.yaml")) { var model = templateEngine.Render <object>("model.yaml", values); if (model != null) { values = MergeUtils.Merge(model, values); } } var workflowContents = new StringBuilder(); using (var workflowWriter = new StringWriter(workflowContents)) { templateEngine.Render("workflow.yaml", values, workflowWriter); } // NOTE: the workflow is rendered BEFORE writing these output files because it may contain // calls to the "secret" helper which will redact tokens that might have been provided in values // write values to output folder generateOutput("values.yaml", writer => _serializers.YamlSerializer.Serialize(writer, values)); // write workflow to output folder generateOutput("workflow.yaml", writer => writer.Write(workflowContents.ToString())); var workflow = _serializers.YamlDeserializer.Deserialize <WorkflowModel>(new StringReader(workflowContents.ToString())); foreach (var generatedFile in blueprint.GetGeneratedPaths()) { using (var generatedContent = blueprint.OpenText(generatedFile)) { generateOutput($"generated/{generatedFile}", writer => writer.Write(generatedContent.ReadToEnd())); } } return(templateEngine, workflow, values); }