/*! * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express * or implied. See the License for the specific language governing * permissions and limitations under the License. */ import DirectedGraph from 'nfvo-utils/DirectedGraph.js'; function findCycles( graph, node, id, visited = {}, visitedConnections = {}, recursionStack = {}, connectionsWithCycle = {} ) { visited[node] = true; recursionStack[node] = true; if (id) { visitedConnections[id] = true; } for (let edge of graph.getEdges(node)) { if (!visited[edge.target]) { findCycles( graph, edge.target, edge.id, visited, visitedConnections, recursionStack, connectionsWithCycle ); } else if (recursionStack[edge.target]) { visitedConnections[edge.id] = true; for (let connection in visitedConnections) { connectionsWithCycle[connection] = true; } } } recursionStack[node] = false; return { visitedNodes: visited, connectionsWithCycle: connectionsWithCycle }; } export function checkCyclesAndMarkDependencies(dependenciesList) { let overallVisitedNodes = {}; let overallConnectionsWithCycles = {}; let g = new DirectedGraph(); for (let dependency of dependenciesList) { if (dependency.sourceId !== null && dependency.targetId !== null) { g.addEdge(dependency.sourceId, dependency.targetId, { id: dependency.id }); } } for (let node in g.nodes) { if (!overallVisitedNodes.node) { let { visitedNodes, connectionsWithCycle } = findCycles( g, node, undefined ); overallVisitedNodes = { ...overallVisitedNodes, ...visitedNodes }; overallConnectionsWithCycles = { ...overallConnectionsWithCycles, ...connectionsWithCycle }; } } return dependenciesList.map(dependency => ({ ...dependency, hasCycle: dependency.sourceId && dependency.targetId ? overallConnectionsWithCycles.hasOwnProperty(dependency.id) : undefined })); }