Пример #1
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);
                }
            }
        }
Пример #2
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);
            }
        }
Пример #3
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();
            }
        }