Exemplo n.º 1
0
        /// <summary>
        /// Reads an qualified object name from its defining element. Outputs an error if the name is missing.
        /// </summary>
        /// <param name="Element">Element to read the name for</param>
        /// <param name="QualifiedName">Output variable to receive the name of the object</param>
        /// <returns>True if the object had a valid name (assigned to the Name variable), false if the name was invalid or missing.</returns>
        bool TryReadQualifiedObjectName(ScriptElement Element, out string[] QualifiedName)
        {
            // Check the name attribute is present
            if (!Element.HasAttribute("Name"))
            {
                LogError(Element, "Missing 'Name' attribute");
                QualifiedName = null;
                return(false);
            }

            // Get the value of it, strip any leading or trailing whitespace, and make sure it's not empty
            string[] Values = ReadAttribute(Element, "Name").Split('.');
            foreach (string Value in Values)
            {
                if (!ValidateName(Element, Value))
                {
                    QualifiedName = null;
                    return(false);
                }
            }

            // Return it
            QualifiedName = Values;
            return(true);
        }
Exemplo n.º 2
0
        /// <summary>
        /// Checks that the given name is valid syntax
        /// </summary>
        /// <param name="Element">The element that contains the name</param>
        /// <param name="Name">The name to check</param>
        /// <returns>True if the name is valid</returns>
        bool ValidateName(ScriptElement Element, string Name)
        {
            // Check it's not empty
            if (Name.Length == 0)
            {
                LogError(Element, "Name is empty");
                return(false);
            }

            // Check there are no invalid characters
            for (int Idx = 0; Idx < Name.Length; Idx++)
            {
                if (Idx > 0 && Name[Idx] == ' ' && Name[Idx - 1] == ' ')
                {
                    LogError(Element, "Consecutive spaces in object name");
                    return(false);
                }
                if (!Char.IsLetterOrDigit(Name[Idx]) && Name[Idx] != '_' && Name[Idx] != ' ')
                {
                    LogError(Element, "Invalid character in object name - '{0}'", Name[Idx]);
                    return(false);
                }
            }
            return(true);
        }
Exemplo n.º 3
0
 /// <summary>
 /// Checks that the given name does not already used to refer to a node, and print an error if it is.
 /// </summary>
 /// <param name="Element">Xml element to read from</param>
 /// <param name="Name">Name of the alias</param>
 /// <param name="Nodes">Array of nodes that this name should resolve to</param>
 /// <returns>True if the name was registered correctly, false otherwise.</returns>
 bool CheckNameIsUnique(ScriptElement Element, string Name)
 {
     // Get the nodes that it maps to
     if (Graph.ContainsName(Name))
     {
         LogError(Element, "'{0}' is already defined; cannot add a second time", Name);
         return(false);
     }
     return(true);
 }
Exemplo n.º 4
0
        /// <summary>
        /// Reads the definition for an aggregate, and adds it to the given agent group
        /// </summary>
        /// <param name="Element">Xml element to read the definition from</param>
        void ReadAggregate(ScriptElement Element)
        {
            string Name;

            if (EvaluateCondition(Element) && TryReadObjectName(Element, out Name) && CheckNameIsUnique(Element, Name))
            {
                string[] RequiredNames = ReadListAttribute(Element, "Requires");
                Graph.AggregateNameToNodes.Add(Name, ResolveReferences(Element, RequiredNames).ToArray());
            }
        }
Exemplo n.º 5
0
 /// <summary>
 /// Reads a property assignment.
 /// </summary>
 /// <param name="Element">Xml element to read the definition from</param>
 void ReadProperty(ScriptElement Element)
 {
     if (EvaluateCondition(Element))
     {
         string Name = ReadAttribute(Element, "Name");
         if (ValidateName(Element, Name))
         {
             GlobalProperties[Name] = ReadAttribute(Element, "Value");
         }
     }
 }
Exemplo n.º 6
0
 /// <summary>
 /// Reads a local property assignment.
 /// </summary>
 /// <param name="Element">Xml element to read the definition from</param>
 void ReadLocalProperty(ScriptElement Element)
 {
     if (EvaluateCondition(Element))
     {
         string Name = ReadAttribute(Element, "Name");
         if (ValidateName(Element, Name))
         {
             ScopedProperties[ScopedProperties.Count - 1][Name] = ReadAttribute(Element, "Value");
         }
     }
 }
Exemplo n.º 7
0
 /// <summary>
 /// Read an include directive, and the contents of the target file
 /// </summary>
 /// <param name="Element">Xml element to read the definition from</param>
 /// <param name="BaseDir">Base directory to resolve relative include paths from </param>
 void ReadInclude(ScriptElement Element, DirectoryReference BaseDir)
 {
     if (EvaluateCondition(Element))
     {
         FileReference Script = FileReference.Combine(BaseDir, Element.GetAttribute("Script"));
         if (Script.Exists())
         {
             TryRead(Script);
         }
         else
         {
             LogError(Element, "Cannot find included script '{0}'", Script.FullName);
         }
     }
 }
Exemplo n.º 8
0
        /// <summary>
        /// Reads a warning from the given element, evaluates the condition on it, and writes it to the log if the condition passes.
        /// </summary>
        /// <param name="Element">Xml element to read the definition from</param>
        /// <param name="EventType">The diagnostic event type</param>
        /// <param name="EnclosingObject">The enclosing object instance</param>
        void ReadDiagnostic(ScriptElement Element, LogEventType EventType, Node EnclosingNode, AgentGroup EnclosingGroup, ManualTrigger EnclosingTrigger)
        {
            if (EvaluateCondition(Element))
            {
                string Message = ReadAttribute(Element, "Message");

                GraphDiagnostic Diagnostic = new GraphDiagnostic();
                Diagnostic.EventType        = EventType;
                Diagnostic.Message          = String.Format("{0}({1}): {2}", Element.File.FullName, Element.LineNumber, Message);
                Diagnostic.EnclosingNode    = EnclosingNode;
                Diagnostic.EnclosingGroup   = EnclosingGroup;
                Diagnostic.EnclosingTrigger = EnclosingTrigger;
                Graph.Diagnostics.Add(Diagnostic);
            }
        }
Exemplo n.º 9
0
        /// <summary>
        /// Reads an attribute from the given XML element, expands any properties in it, and parses it as an enum of the given type.
        /// </summary>
        /// <typeparam name="T">The enum type to parse the attribute as</typeparam>
        /// <param name="Element">Element to read the attribute from</param>
        /// <param name="Name">Name of the attribute</param>
        /// <param name="DefaultValue">Default value for the enum, if the attribute is missing</param>
        /// <returns>The value of the attribute field</returns>
        T ReadEnumAttribute <T>(ScriptElement Element, string Name, T DefaultValue) where T : struct
        {
            T Result = DefaultValue;

            if (Element.HasAttribute(Name))
            {
                string Value = ReadAttribute(Element, Name).Trim();

                T EnumValue;
                if (Enum.TryParse(Value, true, out EnumValue))
                {
                    Result = EnumValue;
                }
                else
                {
                    LogError(Element, "Invalid value '{0}' - expected {1}", Value, String.Join("/", Enum.GetNames(typeof(T))));
                }
            }
            return(Result);
        }
Exemplo n.º 10
0
        /// <summary>
        /// Evaluates the (optional) conditional expression on a given XML element via the If="..." attribute, and returns true if the element is enabled.
        /// </summary>
        /// <param name="Element">The element to check</param>
        /// <returns>True if the element's condition evaluates to true (or doesn't have a conditional expression), false otherwise</returns>
        bool EvaluateCondition(ScriptElement Element)
        {
            // Check if the element has a conditional attribute
            const string AttributeName = "If";

            if (!Element.HasAttribute(AttributeName))
            {
                return(true);
            }

            // If it does, try to evaluate it.
            try
            {
                string Text = ExpandProperties(Element.GetAttribute("If"));
                return(Condition.Evaluate(Text));
            }
            catch (ConditionException Ex)
            {
                LogError(Element, "Error in condition: {0}", Ex.Message);
                return(false);
            }
        }
Exemplo n.º 11
0
        /// <summary>
        /// Reads an attribute from the given XML element, expands any properties in it, and parses it as a boolean.
        /// </summary>
        /// <param name="Element">Element to read the attribute from</param>
        /// <param name="Name">Name of the attribute</param>
        /// <param name="DefaultValue">Default value if the attribute is missing</param>
        /// <returns>The value of the attribute field</returns>
        bool ReadBooleanAttribute(ScriptElement Element, string Name, bool bDefaultValue)
        {
            bool bResult = bDefaultValue;

            if (Element.HasAttribute(Name))
            {
                string Value = ReadAttribute(Element, Name).Trim();
                if (Value.Equals("true", StringComparison.InvariantCultureIgnoreCase))
                {
                    bResult = true;
                }
                else if (Value.Equals("false", StringComparison.InvariantCultureIgnoreCase))
                {
                    bResult = false;
                }
                else
                {
                    LogError(Element, "Invalid boolean value '{0}' - expected 'true' or 'false'", Value);
                }
            }
            return(bResult);
        }
Exemplo n.º 12
0
        /// <summary>
        /// Resolve a list of references to a set of nodes
        /// </summary>
        /// <param name="Element">Element used to locate any errors</param>
        /// <param name="ReferenceNames">Sequence of names to look up</param>
        /// <returns>Set of all the nodes included by the given names</returns>
        HashSet <NodeOutput> ResolveInputReferences(ScriptElement Element, IEnumerable <string> ReferenceNames)
        {
            HashSet <NodeOutput> Inputs = new HashSet <NodeOutput>();

            foreach (string ReferenceName in ReferenceNames)
            {
                NodeOutput[] ReferenceInputs;
                if (Graph.TryResolveInputReference(ReferenceName, out ReferenceInputs))
                {
                    Inputs.UnionWith(ReferenceInputs);
                }
                else if (!ReferenceName.StartsWith("#") && Graph.NameToNodeOutput.ContainsKey(ReferenceName))
                {
                    LogError(Element, "Reference to '{0}' cannot be resolved; did you mean '#{0}'?", ReferenceName);
                }
                else
                {
                    LogError(Element, "Reference to '{0}' cannot be resolved; check it has been defined.", ReferenceName);
                }
            }
            return(Inputs);
        }
Exemplo n.º 13
0
        /// <summary>
        /// Reads an object name from its defining element. Outputs an error if the name is missing.
        /// </summary>
        /// <param name="Element">Element to read the name for</param>
        /// <param name="Name">Output variable to receive the name of the object</param>
        /// <returns>True if the object had a valid name (assigned to the Name variable), false if the name was invalid or missing.</returns>
        bool TryReadObjectName(ScriptElement Element, out string Name)
        {
            // Check the name attribute is present
            if (!Element.HasAttribute("Name"))
            {
                LogError(Element, "Missing 'Name' attribute");
                Name = null;
                return(false);
            }

            // Get the value of it, strip any leading or trailing whitespace, and make sure it's not empty
            string Value = ReadAttribute(Element, "Name");

            if (!ValidateName(Element, Value))
            {
                Name = null;
                return(false);
            }

            // Return it
            Name = Value;
            return(true);
        }
Exemplo n.º 14
0
 /// <summary>
 /// Expands any properties and reads an attribute.
 /// </summary>
 /// <param name="Element">Element to read the attribute from</param>
 /// <param name="Name">Name of the attribute</param>
 /// <returns>Array of names, with all leading and trailing whitespace removed</returns>
 string ReadAttribute(ScriptElement Element, string Name)
 {
     return(ExpandProperties(Element.GetAttribute(Name)));
 }
Exemplo n.º 15
0
 /// <summary>
 /// Outputs an error message to the log and increments the number of errors, referencing the file and line number of the element that caused it.
 /// </summary>
 /// <param name="Element">The script element causing the error</param>
 /// <param name="Format">Standard String.Format()-style format string</param>
 /// <param name="Args">Optional arguments</param>
 void LogError(ScriptElement Element, string Format, params object[] Args)
 {
     CommandUtils.LogError("{0}({1}): {2}", Element.File.FullName, Element.LineNumber, String.Format(Format, Args));
     NumErrors++;
 }
Exemplo n.º 16
0
        /// <summary>
        /// Reads the definition for an agent group.
        /// </summary>
        /// <param name="Element">Xml element to read the definition from</param>
        void ReadTrigger(ScriptElement Element)
        {
            string[] QualifiedName;
            if (EvaluateCondition(Element) && TryReadQualifiedObjectName(Element, out QualifiedName))
            {
                // Validate all the parent triggers
                ManualTrigger ParentTrigger = null;
                for (int Idx = 0; Idx < QualifiedName.Length - 1; Idx++)
                {
                    ManualTrigger NextTrigger;
                    if (!Graph.NameToTrigger.TryGetValue(QualifiedName[Idx], out NextTrigger))
                    {
                        LogError(Element, "Unknown trigger '{0}'", QualifiedName[Idx]);
                        return;
                    }
                    if (NextTrigger.Parent != ParentTrigger)
                    {
                        LogError(Element, "Qualified name of trigger '{0}' is '{1}'", NextTrigger.Name, NextTrigger.QualifiedName);
                        return;
                    }
                    ParentTrigger = NextTrigger;
                }

                // Get the name of the new trigger
                string Name = QualifiedName[QualifiedName.Length - 1];

                // Create the new trigger
                ManualTrigger Trigger;
                if (!Graph.NameToTrigger.TryGetValue(Name, out Trigger))
                {
                    Trigger = new ManualTrigger(ParentTrigger, Name);
                    Graph.NameToTrigger.Add(Name, Trigger);
                }
                else if (Trigger.Parent != ParentTrigger)
                {
                    LogError(Element, "Conflicting parent for '{0}' - previously declared as '{1}', now '{2}'", Name, Trigger.QualifiedName, new ManualTrigger(ParentTrigger, Name).QualifiedName);
                    return;
                }

                // Read the root BuildGraph element
                EnterScope();
                foreach (ScriptElement ChildElement in Element.ChildNodes.OfType <ScriptElement>())
                {
                    switch (ChildElement.Name)
                    {
                    case "Property":
                        ReadProperty(ChildElement);
                        break;

                    case "Local":
                        ReadLocalProperty(ChildElement);
                        break;

                    case "Agent":
                        ReadAgent(ChildElement, Trigger);
                        break;

                    case "Aggregate":
                        ReadAggregate(ChildElement);
                        break;

                    case "Notifier":
                        ReadNotifier(ChildElement);
                        break;

                    case "Warning":
                        ReadDiagnostic(ChildElement, LogEventType.Warning, null, null, Trigger);
                        break;

                    case "Error":
                        ReadDiagnostic(ChildElement, LogEventType.Error, null, null, Trigger);
                        break;

                    default:
                        LogError(ChildElement, "Invalid element '{0}'", ChildElement.Name);
                        break;
                    }
                }
                LeaveScope();
            }
        }
Exemplo n.º 17
0
        /// <summary>
        /// Reads the definition for an email notifier
        /// </summary>
        /// <param name="Element">Xml element to read the definition from</param>
        void ReadNotifier(ScriptElement Element)
        {
            if (EvaluateCondition(Element))
            {
                string[] TargetNames         = ReadListAttribute(Element, "Targets");
                string[] ExceptNames         = ReadListAttribute(Element, "Except");
                string[] IndividualNodeNames = ReadListAttribute(Element, "Nodes");
                string[] TriggerNames        = ReadListAttribute(Element, "Triggers");
                string[] Users      = ReadListAttribute(Element, "Users");
                string[] Submitters = ReadListAttribute(Element, "Submitters");
                bool?    bWarnings  = Element.HasAttribute("Warnings")? (bool?)ReadBooleanAttribute(Element, "Warnings", true) : null;

                // Find the list of targets which are included, and recurse through all their dependencies
                HashSet <Node> Nodes = new HashSet <Node>();
                if (TargetNames != null)
                {
                    HashSet <Node> TargetNodes = ResolveReferences(Element, TargetNames);
                    foreach (Node Node in TargetNodes)
                    {
                        Nodes.Add(Node);
                        Nodes.UnionWith(Node.InputDependencies);
                    }
                }

                // Add all the individually referenced nodes
                if (IndividualNodeNames != null)
                {
                    HashSet <Node> IndividualNodes = ResolveReferences(Element, IndividualNodeNames);
                    Nodes.UnionWith(IndividualNodes);
                }

                // Exclude all the exceptions
                if (ExceptNames != null)
                {
                    HashSet <Node> ExceptNodes = ResolveReferences(Element, ExceptNames);
                    Nodes.ExceptWith(ExceptNodes);
                }

                // Update all the referenced nodes with the settings
                foreach (Node Node in Nodes)
                {
                    if (Users != null)
                    {
                        Node.NotifyUsers.UnionWith(Users);
                    }
                    if (Submitters != null)
                    {
                        Node.NotifySubmitters.UnionWith(Submitters);
                    }
                    if (bWarnings.HasValue)
                    {
                        Node.bNotifyOnWarnings = bWarnings.Value;
                    }
                }

                // Add the users to the list of triggers
                if (TriggerNames != null)
                {
                    foreach (string TriggerName in TriggerNames)
                    {
                        ManualTrigger Trigger;
                        if (Graph.NameToTrigger.TryGetValue(TriggerName, out Trigger))
                        {
                            Trigger.NotifyUsers.UnionWith(Users);
                        }
                        else
                        {
                            LogError(Element, "Trigger '{0}' has not been defined", TriggerName);
                        }
                    }
                }
            }
        }
Exemplo n.º 18
0
        /// <summary>
        /// Reads a task definition from the given element, and add it to the given list
        /// </summary>
        /// <param name="Element">Xml element to read the definition from</param>
        /// <param name="Tasks">List of tasks to add to</param>
        void ReadTask(ScriptElement Element, List <CustomTask> Tasks)
        {
            if (EvaluateCondition(Element))
            {
                // Get the reflection info for this element
                ScriptTask Task;
                if (!Schema.TryGetTask(Element.Name, out Task))
                {
                    LogError(Element, "Unknown task '{0}'", Element.Name);
                    return;
                }

                // Check all the required parameters are present
                bool bHasRequiredAttributes = true;
                foreach (ScriptTaskParameter Parameter in Task.NameToParameter.Values)
                {
                    if (!Parameter.bOptional && !Element.HasAttribute(Parameter.Name))
                    {
                        LogError(Element, "Missing required attribute - {0}", Parameter.Name);
                        bHasRequiredAttributes = false;
                    }
                }

                // Read all the attributes into a parameters object for this task
                object ParametersObject = Activator.CreateInstance(Task.ParametersClass);
                foreach (XmlAttribute Attribute in Element.Attributes)
                {
                    if (String.Compare(Attribute.Name, "If", StringComparison.InvariantCultureIgnoreCase) != 0)
                    {
                        // Get the field that this attribute should be written to in the parameters object
                        ScriptTaskParameter Parameter;
                        if (!Task.NameToParameter.TryGetValue(Attribute.Name, out Parameter))
                        {
                            LogError(Element, "Unknown attribute '{0}'", Attribute.Name);
                            continue;
                        }

                        // Expand variables in the value
                        string ExpandedValue = ExpandProperties(Attribute.Value);

                        // Parse it and assign it to the parameters object
                        object Value;
                        if (Parameter.FieldInfo.FieldType.IsEnum)
                        {
                            Value = Enum.Parse(Parameter.FieldInfo.FieldType, ExpandedValue);
                        }
                        else if (Parameter.FieldInfo.FieldType == typeof(Boolean))
                        {
                            Value = Condition.Evaluate(ExpandedValue);
                        }
                        else
                        {
                            Value = Convert.ChangeType(ExpandedValue, Parameter.FieldInfo.FieldType);
                        }
                        Parameter.FieldInfo.SetValue(ParametersObject, Value);
                    }
                }

                // Construct the task
                if (bHasRequiredAttributes)
                {
                    Tasks.Add((CustomTask)Activator.CreateInstance(Task.TaskClass, ParametersObject));
                }
            }
        }
Exemplo n.º 19
0
        /// <summary>
        /// Reads the definition for a node, and adds it to the given agent group
        /// </summary>
        /// <param name="Element">Xml element to read the definition from</param>
        /// <param name="Group">Group for the node to be added to</param>
        /// <param name="ControllingTrigger">The controlling trigger for this node</param>
        void ReadNode(ScriptElement Element, AgentGroup Group, ManualTrigger ControllingTrigger)
        {
            string Name;

            if (EvaluateCondition(Element) && TryReadObjectName(Element, out Name))
            {
                string[] RequiresNames = ReadListAttribute(Element, "Requires");
                string[] ProducesNames = ReadListAttribute(Element, "Produces");
                string[] AfterNames    = ReadListAttribute(Element, "After");

                // Resolve all the inputs we depend on
                HashSet <NodeOutput> Inputs = ResolveInputReferences(Element, RequiresNames);

                // Gather up all the input dependencies, and check they're all upstream of the current node
                HashSet <Node> InputDependencies = new HashSet <Node>();
                foreach (Node InputDependency in Inputs.Select(x => x.ProducingNode).Distinct())
                {
                    if (InputDependency.ControllingTrigger != null && InputDependency.ControllingTrigger != ControllingTrigger && !InputDependency.ControllingTrigger.IsUpstreamFrom(ControllingTrigger))
                    {
                        LogError(Element, "'{0}' is dependent on '{1}', which is behind a different controlling trigger ({2})", Name, InputDependency.Name, InputDependency.ControllingTrigger.QualifiedName);
                    }
                    else
                    {
                        InputDependencies.Add(InputDependency);
                    }
                }

                // Recursively include all their dependencies too
                foreach (Node InputDependency in InputDependencies.ToArray())
                {
                    InputDependencies.UnionWith(InputDependency.InputDependencies);
                }

                // Add the name of the node itself to the list of outputs.
                List <string> OutputNames = new List <string>();
                foreach (string ProducesName in ProducesNames)
                {
                    if (ProducesName.StartsWith("#"))
                    {
                        OutputNames.Add(ProducesName.Substring(1));
                    }
                    else
                    {
                        LogError(Element, "Output tag names must begin with a '#' character ('{0}')", ProducesName);
                    }
                }
                OutputNames.Add(Name);

                // Gather up all the order dependencies
                HashSet <Node> OrderDependencies = new HashSet <Node>(InputDependencies);
                OrderDependencies.UnionWith(ResolveReferences(Element, AfterNames));

                // Recursively include all their order dependencies too
                foreach (Node OrderDependency in OrderDependencies.ToArray())
                {
                    OrderDependencies.UnionWith(OrderDependency.OrderDependencies);
                }

                // Check that we're not dependent on anything completing that is declared after the initial declaration of this group.
                int GroupIdx = Graph.Groups.IndexOf(Group);
                for (int Idx = GroupIdx + 1; Idx < Graph.Groups.Count; Idx++)
                {
                    foreach (Node Node in Graph.Groups[Idx].Nodes.Where(x => OrderDependencies.Contains(x)))
                    {
                        LogError(Element, "Node '{0}' has a dependency on '{1}', which was declared after the initial definition of '{2}'.", Name, Node.Name, Group.Name);
                    }
                }

                // Construct and register the node
                if (CheckNameIsUnique(Element, Name))
                {
                    // Add it to the node lookup
                    Node NewNode = new Node(Name, Inputs.ToArray(), OutputNames.ToArray(), InputDependencies.ToArray(), OrderDependencies.ToArray(), ControllingTrigger);
                    Graph.NameToNode.Add(Name, NewNode);

                    // Register each of the outputs as a reference to this node
                    foreach (NodeOutput Output in NewNode.Outputs)
                    {
                        if (Output.Name == Name || CheckNameIsUnique(Element, Output.Name))
                        {
                            Graph.NameToNodeOutput.Add(Output.Name, Output);
                        }
                    }

                    // Add all the tasks
                    EnterScope();
                    foreach (ScriptElement ChildElement in Element.ChildNodes.OfType <ScriptElement>())
                    {
                        switch (ChildElement.Name)
                        {
                        case "Property":
                            ReadProperty(ChildElement);
                            break;

                        case "Local":
                            ReadLocalProperty(ChildElement);
                            break;

                        case "Warning":
                            ReadDiagnostic(ChildElement, LogEventType.Warning, NewNode, Group, ControllingTrigger);
                            break;

                        case "Error":
                            ReadDiagnostic(ChildElement, LogEventType.Error, NewNode, Group, ControllingTrigger);
                            break;

                        default:
                            ReadTask(ChildElement, NewNode.Tasks);
                            break;
                        }
                    }
                    LeaveScope();

                    // Add it to the current agent group
                    Group.Nodes.Add(NewNode);
                }
            }
        }
Exemplo n.º 20
0
        /// <summary>
        /// Reads the definition for an agent group.
        /// </summary>
        /// <param name="Element">Xml element to read the definition from</param>
        /// <param name="Trigger">The controlling trigger for nodes in this group</param>
        void ReadAgent(ScriptElement Element, ManualTrigger Trigger)
        {
            string Name;

            if (EvaluateCondition(Element) && TryReadObjectName(Element, out Name))
            {
                // Read the valid agent types. This may be omitted if we're continuing an existing group.
                string[] Types = ReadListAttribute(Element, "Type");

                // Create the group object, or continue an existing one
                AgentGroup Group;
                if (NameToGroup.TryGetValue(Name, out Group))
                {
                    if (Types.Length > 0 && Group.PossibleTypes.Length > 0)
                    {
                        string[] NewTypes = Group.PossibleTypes.Intersect(Types, StringComparer.InvariantCultureIgnoreCase).ToArray();
                        if (NewTypes.Length == 0)
                        {
                            LogError(Element, "No common agent types with previous agent definition");
                        }
                        Group.PossibleTypes = NewTypes;
                    }
                }
                else
                {
                    if (Types.Length == 0)
                    {
                        LogError(Element, "Missing agent type for group '{0}'", Name);
                    }
                    Group = new AgentGroup(Name, Types);
                    NameToGroup.Add(Name, Group);
                    Graph.Groups.Add(Group);
                }

                // Process all the child elements.
                EnterScope();
                foreach (ScriptElement ChildElement in Element.ChildNodes.OfType <ScriptElement>())
                {
                    switch (ChildElement.Name)
                    {
                    case "Property":
                        ReadProperty(ChildElement);
                        break;

                    case "Local":
                        ReadLocalProperty(ChildElement);
                        break;

                    case "Node":
                        ReadNode(ChildElement, Group, Trigger);
                        break;

                    case "Aggregate":
                        ReadAggregate(ChildElement);
                        break;

                    case "Warning":
                        ReadDiagnostic(ChildElement, LogEventType.Warning, null, Group, Trigger);
                        break;

                    case "Error":
                        ReadDiagnostic(ChildElement, LogEventType.Error, null, Group, Trigger);
                        break;

                    default:
                        LogError(ChildElement, "Unexpected element type '{0}'", ChildElement.Name);
                        break;
                    }
                }
                LeaveScope();
            }
        }
Exemplo n.º 21
0
        /// <summary>
        /// Expands any properties and reads a list of strings from an attribute, separated by semi-colon characters
        /// </summary>
        /// <param name="Element"></param>
        /// <param name="Name"></param>
        /// <returns>Array of names, with all leading and trailing whitespace removed</returns>
        string[] ReadListAttribute(ScriptElement Element, string Name)
        {
            string Value = ReadAttribute(Element, Name);

            return(Value.Split(new char[] { ';' }).Select(x => x.Trim()).Where(x => x.Length > 0).ToArray());
        }