Esempio n. 1
0
        public void Update(IVariables variables)
        {
            bool VariableNameIsMappedPath(string v)
            {
                if (v.StartsWith("Octopus", StringComparison.OrdinalIgnoreCase) &&
                    !v.StartsWith("Octopus:", StringComparison.OrdinalIgnoreCase))
                {
                    // Only include variables starting with 'Octopus'
                    // if it also has a colon (:)
                    return(false);
                }
                return(map.ContainsKey(v));
            }

            var replaced = 0;

            foreach (var name in variables.GetNames().Where(VariableNameIsMappedPath))
            {
                try
                {
                    log.Verbose(StructuredConfigMessages.StructureFound(name));
                    replaced++;
                    map[name](variables.Get(name));
                }
                catch (Exception e)
                {
                    log.WarnFormat("Unable to set value for {0}. The following error occurred: {1}", name, e.Message);
                }
            }

            if (replaced == 0)
            {
                log.Info(StructuredConfigMessages.NoStructuresFound);
            }
        }
        ITopLevelExpression TryReplaceValue(ITopLevelExpression expr, IVariables variables)
        {
            switch (expr)
            {
            case KeyValuePairExpression pair:
                var logicalName = pair.Key?.Text?.LogicalValue ?? "";
                if (!IsOctopusVariableName(logicalName) && variables.IsSet(logicalName))
                {
                    log.Verbose(StructuredConfigMessages.StructureFound(logicalName));

                    var logicalValue = variables.Get(logicalName);
                    var encodedValue = Encode.Value(logicalValue);
                    var newValueExpr = new ValueExpression(new StringValue(logicalValue, encodedValue));

                    // In cases where a key was specified with neither separator nor value
                    // we have to add a separator, otherwise the value becomes part of the key.
                    var separator = pair.Separator ?? new SeparatorExpression(":");
                    return(new KeyValuePairExpression(pair.Key, separator, newValueExpr));
                }
                else
                {
                    return(expr);
                }

            default:
                return(expr);
            }
        }
        public void ModifyFile(string filePath, IVariables variables)
        {
            try
            {
                void LogReplacement(string key)
                => log.Verbose(StructuredConfigMessages.StructureFound(key));

                var replaced       = 0;
                var variablesByKey = variables
                                     .Where(v => !OctopusReservedVariablePattern.IsMatch(v.Key))
                                     .DistinctBy(v => v.Key)
                                     .ToDictionary <KeyValuePair <string, string>, string, Func <string?> >(v => v.Key,
                                                                                                            v => () =>
                {
                    LogReplacement(v.Key);
                    replaced++;
                    return(variables.Get(v.Key));
                },
                                                                                                            StringComparer.OrdinalIgnoreCase);

                // Read and transform the input file
                var fileText   = fileSystem.ReadFile(filePath, out var encoding);
                var lineEnding = fileText.GetMostCommonLineEnding();

                var outputEvents   = new List <ParsingEvent>();
                var indentDetector = new YamlIndentDetector();

                using (var reader = new StringReader(fileText))
                {
                    var scanner    = new Scanner(reader, false);
                    var parser     = new Parser(scanner);
                    var classifier = new YamlEventStreamClassifier();
                    (IYamlNode startEvent, string?replacementValue)? structureWeAreReplacing = null;
                    while (parser.MoveNext())
                    {
                        var ev = parser.Current;
                        if (ev == null)
                        {
                            continue;
                        }

                        indentDetector.Process(ev);

                        if (ev is Comment c)
                        {
                            ev = c.RestoreLeadingSpaces();
                        }

                        var node = classifier.Process(ev);

                        if (structureWeAreReplacing == null)
                        {
                            // Not replacing: searching for things to replace, copying events to output.

                            if (node is YamlNode <Scalar> scalar &&
                                variablesByKey.TryGetValue(scalar.Path, out var newValue))
                            {
                                outputEvents.Add(scalar.Event.ReplaceValue(newValue()));
                            }
                            else if (node is YamlNode <MappingStart> mappingStart &&
                                     variablesByKey.TryGetValue(mappingStart.Path, out var mappingReplacement))
                            {
                                structureWeAreReplacing = (mappingStart, mappingReplacement());
                            }
                            else if (node is YamlNode <SequenceStart> sequenceStart &&
                                     variablesByKey.TryGetValue(sequenceStart.Path, out var sequenceReplacement))
                            {
                                structureWeAreReplacing = (sequenceStart, sequenceReplacement());
                            }
Esempio n. 4
0
        public void ModifyFile(string filePath, IVariables variables)
        {
            var encodingPrecedence = new List <Encoding>(CalamariPhysicalFileSystem.DefaultInputEncodingPrecedence);

            var fileBytes = fileSystem.ReadAllBytes(filePath);

            if (TryGetDeclaredEncoding(fileBytes) is {} declaredEncoding)
            {
                encodingPrecedence.Insert(0, declaredEncoding);
            }

            var fileText   = fileSystem.ReadAllText(fileBytes, out var encoding, encodingPrecedence);
            var lineEnding = fileText.GetMostCommonLineEnding();

            var doc = new XmlDocument();

            try
            {
                doc.LoadXml(fileText);
            }
            catch (XmlException e)
            {
                throw new StructuredConfigFileParseException(e.Message, e);
            }

            var nsManager = BuildNsManagerFromDocument(doc);
            var navigator = doc.CreateNavigator();

            var replaced = 0;

            foreach (var variable in variables)
            {
                if (TryGetXPathFromVariableKey(variable.Key, nsManager) is {} xPathExpression)
                {
                    var selectedNodes = navigator.XPath2SelectNodes(xPathExpression, nsManager);
                    var variableValue = variables.Get(variable.Key);

                    foreach (XPathNavigator selectedNode in selectedNodes)
                    {
                        log.Verbose(StructuredConfigMessages.StructureFound(variable.Key));
                        replaced++;

                        switch (selectedNode.UnderlyingObject)
                        {
                        case XmlText text:
                            text.Data = variableValue;
                            break;

                        case XmlAttribute attribute:
                            attribute.Value = variableValue;
                            break;

                        case XmlComment comment:
                            comment.Data = variableValue;
                            break;

                        case XmlElement element:
                            if (element.ChildNodes.Count == 1 && element.ChildNodes[0].NodeType == XmlNodeType.CDATA)
                            {
                                // Try to preserve CDatas in the output.
                                element.ChildNodes[0].Value = variableValue;
                            }
                            else if (ContainsElements(element))
                            {
                                TrySetInnerXml(element, variable.Key, variableValue);
                            }
                            else
                            {
                                element.InnerText = variableValue;
                            }
                            break;

                        case XmlCharacterData cData:
                            cData.Data = variableValue;
                            break;

                        case XmlProcessingInstruction processingInstruction:
                            processingInstruction.Data = variableValue;
                            break;

                        case XmlNode node:
                            log.Warn($"XML Node of type '{node.NodeType}' is not supported");
                            break;

                        default:
                            log.Warn($"XPath returned an object of type '{selectedNode.GetType().FullName}', which is not supported");
                            break;
                        }
                    }
                }
            }
            if (replaced == 0)
            {
                log.Info(StructuredConfigMessages.NoStructuresFound);
            }

            fileSystem.OverwriteFile(filePath,
                                     textWriter =>
            {
                var xmlWriterSettings = new XmlWriterSettings
                {
                    Indent             = true,
                    NewLineChars       = lineEnding == StringExtensions.LineEnding.Dos ? "\r\n" : "\n",
                    OmitXmlDeclaration = doc.FirstChild.NodeType != XmlNodeType.XmlDeclaration
                };
                using (var writer = XmlWriter.Create(textWriter, xmlWriterSettings))
                {
                    doc.Save(writer);
                    writer.Close();
                }
            },
                                     encoding);
        }