341 lines
13 KiB
JavaScript
341 lines
13 KiB
JavaScript
(function() {
|
|
'use strict';
|
|
|
|
let diameter = 1280;
|
|
let radius = diameter / 2;
|
|
let innerRadius = radius - 240;
|
|
|
|
let cluster = d3.cluster();
|
|
cluster.size([ 360, innerRadius ]);
|
|
|
|
let line = d3.radialLine();
|
|
line.curve(d3.curveBundle.beta(0.85));
|
|
line.radius(function(d) { return d.y; });
|
|
line.angle(function(d) { return d.x / 180 * Math.PI; });
|
|
|
|
let link;
|
|
let node;
|
|
let selectedNode;
|
|
let selectedSubNode;
|
|
|
|
function init() {
|
|
let domListCol = document.createElement("div");
|
|
domListCol.id = "violate_list_column";
|
|
let domGraphCol = document.createElement("div");
|
|
domGraphCol.id = "dep_graph_column";
|
|
let domResetBtn = document.createElement("button");
|
|
domResetBtn.id = "reset_btn";
|
|
domResetBtn.innerHTML = "Reset";
|
|
domGraphCol.appendChild(domResetBtn);
|
|
|
|
document.body.appendChild(domListCol);
|
|
document.body.appendChild(domGraphCol);
|
|
|
|
let canvas = d3.select("#dep_graph_column").append("svg");
|
|
canvas.attr("width", diameter + 200);
|
|
canvas.attr("height", diameter);
|
|
|
|
let svg = canvas.append("g");
|
|
svg.attr("transform", "translate(" + (radius + 100) + "," + radius + ")");
|
|
|
|
link = svg.append("g").selectAll(".link");
|
|
node = svg.append("g").selectAll(".node");
|
|
|
|
showResult(depData, violatedLibs);
|
|
}
|
|
|
|
function showList(depMap, violatedLibs) {
|
|
function makeTitle(tagName) {
|
|
let domTitle = document.createElement("div");
|
|
let domText = document.createElement("h3");
|
|
domText.innerHTML = tagName;
|
|
domTitle.appendChild(domText);
|
|
return domTitle;
|
|
}
|
|
function makeButton(libName, count) {
|
|
let domButton = document.createElement("button");
|
|
domButton.className = "violate";
|
|
domButton.innerHTML = libName + " (" + count + ")";
|
|
domButton.onclick = function() {
|
|
this.classList.toggle("active");
|
|
let currentList = this.nextElementSibling;
|
|
if (currentList.style.display === "block") {
|
|
currentList.style.display = "none";
|
|
selectedNode = undefined;
|
|
if (selectedSubNode) {
|
|
selectedSubNode.classList.toggle("active");
|
|
selectedSubNode.nextElementSibling.style.display = "none";
|
|
selectedSubNode = undefined;
|
|
}
|
|
resetclicked();
|
|
} else {
|
|
currentList.style.display = "block";
|
|
for (let i = 1; i < currentList.childElementCount; i += 2) {
|
|
currentList.childNodes[i].style.display = "none";
|
|
}
|
|
if (selectedNode) {
|
|
selectedNode.classList.toggle("active");
|
|
selectedNode.nextElementSibling.style.display = "none";
|
|
if (selectedSubNode) {
|
|
selectedSubNode.classList.toggle("active");
|
|
selectedSubNode.nextElementSibling.style.display = "none";
|
|
selectedSubNode = undefined;
|
|
}
|
|
}
|
|
selectedNode = domButton;
|
|
mouseclicked(depMap[libName]);
|
|
}
|
|
};
|
|
return domButton;
|
|
}
|
|
function makeSubButton(libName, count) {
|
|
let domButton = document.createElement("button");
|
|
domButton.className = "violate-list";
|
|
domButton.innerHTML = libName + " (" + count + ")";
|
|
domButton.onclick = function() {
|
|
this.classList.toggle("active");
|
|
let currentSubList = this.nextElementSibling;
|
|
if (currentSubList.style.display === "block") {
|
|
currentSubList.style.display = "none";
|
|
selectedSubNode = undefined;
|
|
} else {
|
|
currentSubList.style.display = "block";
|
|
for (let i = 0; i < currentSubList.childElementCount; i++) {
|
|
if (currentSubList.childNodes[i].childElementCount > 0) {
|
|
currentSubList.childNodes[i].childNodes[1].style.display = "none";
|
|
}
|
|
}
|
|
if (selectedSubNode) {
|
|
selectedSubNode.classList.toggle("active");
|
|
selectedSubNode.nextElementSibling.style.display = "none";
|
|
}
|
|
selectedSubNode = domButton;
|
|
}
|
|
};
|
|
return domButton;
|
|
}
|
|
function changeFormat(symbol) {
|
|
let res = "";
|
|
let i;
|
|
for (i = 0; i < symbol.length; i++) {
|
|
if (symbol.charAt(i) >= '0' && symbol.charAt(i) <= '9') {
|
|
break;
|
|
}
|
|
}
|
|
while (i < symbol.length) {
|
|
if (symbol.charAt(i) < '0' || symbol.charAt(i) > '9') {
|
|
break;
|
|
}
|
|
let len = parseInt(symbol.substr(i, symbol.length));
|
|
let count = 1;
|
|
if (len < 10) {
|
|
count = 0;
|
|
}
|
|
res = res + "::" + symbol.substr(i + 1 + count, len);
|
|
i = i + 1 + count + len;
|
|
}
|
|
return res.substr(2, res.length);
|
|
}
|
|
function makeList(domList, list)
|
|
{
|
|
for (let i = 0; i < list.length; i++) {
|
|
domList.appendChild(makeButton(list[i][0], list[i][1]));
|
|
let domDepList = document.createElement("div");
|
|
let depItem = depMap[list[i][0]];
|
|
let violates = depItem.data.violates;
|
|
for (let j = 0; j < violates.length; j++) {
|
|
let domDepLib = document.createElement("div");
|
|
let tag = depMap[violates[j][0]].data.tag;
|
|
let symbols = violates[j][1];
|
|
let domDepButton = makeSubButton(violates[j][0] + " ["
|
|
+ tag.substring(tag.lastIndexOf(".") + 1) + "]", symbols.length);
|
|
for (let k = 0; k < symbols.length; k++) {
|
|
let domDepSym = document.createElement("div");
|
|
domDepSym.className = "violate-list-sym";
|
|
domDepSym.innerHTML = symbols[k];
|
|
if (symbols[k].indexOf("_Z") === 0) {
|
|
let cplusplusSym = document.createElement("span");
|
|
cplusplusSym.className = "cplusplus-sym";
|
|
cplusplusSym.innerHTML =
|
|
changeFormat(symbols[k].substr(2, symbols[k].length));
|
|
domDepSym.appendChild(cplusplusSym);
|
|
domDepSym.onmouseover = function(e) {
|
|
e.currentTarget.style.position = "relative";
|
|
e.currentTarget.childNodes[1].style.display = "block";
|
|
};
|
|
domDepSym.onmouseout = function(e) {
|
|
e.currentTarget.style.position = "static";
|
|
e.currentTarget.childNodes[1].style.display = "none";
|
|
};
|
|
}
|
|
domDepLib.appendChild(domDepSym);
|
|
}
|
|
domDepList.appendChild(domDepButton);
|
|
domDepList.appendChild(domDepLib);
|
|
}
|
|
domList.appendChild(domDepList);
|
|
domDepList.style.display = "none";
|
|
}
|
|
}
|
|
|
|
let domViolatedList = document.getElementById("violate_list_column");
|
|
if ("vendor.private.bin" in violatedLibs) {
|
|
let list = violatedLibs["vendor.private.bin"];
|
|
domViolatedList.appendChild(makeTitle("VENDOR (" + list.length + ")"));
|
|
makeList(domViolatedList, list);
|
|
}
|
|
for (let tag in violatedLibs) {
|
|
if (tag === "vendor.private.bin")
|
|
continue;
|
|
let list = violatedLibs[tag];
|
|
if (tag === "system.private.bin")
|
|
tag = "SYSTEM";
|
|
else
|
|
tag = tag.substring(tag.lastIndexOf(".") + 1).toUpperCase();
|
|
domViolatedList.appendChild(makeTitle(tag + " (" + list.length + ")"));
|
|
makeList(domViolatedList, list);
|
|
}
|
|
}
|
|
|
|
function showResult(depDumps, violatedLibs) {
|
|
let root = tagHierarchy(depDumps).sum(function(d) { return 1; });
|
|
cluster(root);
|
|
|
|
let libsDepData = libsDepends(root.leaves());
|
|
showList(libsDepData[1], violatedLibs);
|
|
link = link.data(libsDepData[0])
|
|
.enter()
|
|
.append("path")
|
|
.each(function(d) { d.source = d[0], d.target = d[d.length - 1]; })
|
|
.attr("class", function(d) { return d.allow ? "link" : "link--violate" })
|
|
.attr("d", line);
|
|
|
|
node = node.data(root.leaves())
|
|
.enter()
|
|
.append("text")
|
|
.attr("class",
|
|
function(d) {
|
|
return d.data.parent.parent.parent.key == "system" ?
|
|
(d.data.parent.parent.key == "system.public" ?
|
|
"node--sys-pub" :
|
|
"node--sys-pri") :
|
|
"node";
|
|
})
|
|
.attr("dy", "0.31em")
|
|
.attr("transform",
|
|
function(d) {
|
|
return "rotate(" + (d.x - 90) + ")translate(" + (d.y + 8) + ",0)" +
|
|
(d.x < 180 ? "" : "rotate(180)");
|
|
})
|
|
.attr("text-anchor", function(d) { return d.x < 180 ? "start" : "end"; })
|
|
.text(function(d) { return d.data.key; })
|
|
.on("click", mouseclicked);
|
|
document.getElementById("reset_btn").onclick = resetclicked;
|
|
}
|
|
|
|
function resetclicked() {
|
|
if (selectedNode) {
|
|
selectedNode.classList.toggle("active");
|
|
selectedNode.nextElementSibling.style.display = "none";
|
|
if (selectedSubNode) {
|
|
selectedSubNode.classList.toggle("active");
|
|
selectedSubNode.nextElementSibling.style.display = "none";
|
|
selectedSubNode = undefined;
|
|
}
|
|
selectedNode = undefined;
|
|
}
|
|
link.classed("link--target", false)
|
|
.classed("link--source", false);
|
|
node.classed("node--target", false)
|
|
.classed("node--source", false)
|
|
.classed("node--selected", false);
|
|
}
|
|
|
|
function mouseclicked(d) {
|
|
node.each(function(n) { n.target = n.source = false; });
|
|
|
|
link.classed("link--target",
|
|
function(l) {
|
|
if (l.target === d) {
|
|
l.source.source = true;
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
})
|
|
.classed("link--source",
|
|
function(l) {
|
|
if (l.source === d) {
|
|
l.target.target = true;
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
})
|
|
.filter(function(l) { return l.target === d || l.source === d; })
|
|
.raise();
|
|
|
|
node.classed("node--target",
|
|
function(n) {
|
|
return n.target;
|
|
})
|
|
.classed("node--source",
|
|
function(n) { return n.source; })
|
|
.classed("node--selected",
|
|
function(n) {
|
|
return n === d;
|
|
});
|
|
}
|
|
|
|
function tagHierarchy(depDumps) {
|
|
let map = {};
|
|
|
|
function find(name, tag, data) {
|
|
let node = map[name], i;
|
|
if (!node) {
|
|
node = map[name] = data || { name : name, children : [] };
|
|
if (name.length) {
|
|
node.parent = find(tag, tag.substring(0, tag.lastIndexOf(".")));
|
|
node.parent.children.push(node);
|
|
node.key = name;
|
|
}
|
|
}
|
|
return node;
|
|
}
|
|
|
|
depDumps.forEach(function(d) { find(d.name, d.tag, d); });
|
|
|
|
return d3.hierarchy(map[""]);
|
|
}
|
|
|
|
function libsDepends(nodes) {
|
|
let map = {}, depends = [];
|
|
|
|
// Compute a map from name to node.
|
|
nodes.forEach(function(d) { map[d.data.name] = d; });
|
|
|
|
// For each dep, construct a link from the source to target node.
|
|
nodes.forEach(function(d) {
|
|
if (d.data.depends)
|
|
d.data.depends.forEach(function(i) {
|
|
let l = map[d.data.name].path(map[i]);
|
|
l.allow = true;
|
|
depends.push(l);
|
|
});
|
|
if (d.data.violates.length) {
|
|
map[d.data.name].not_allow = true;
|
|
d.data.violates.forEach(function(i) {
|
|
map[i[0]].not_allow = true;
|
|
let l = map[d.data.name].path(map[i[0]]);
|
|
l.allow = false;
|
|
depends.push(l);
|
|
});
|
|
}
|
|
});
|
|
|
|
return [ depends, map ];
|
|
}
|
|
|
|
window.onload = init;
|
|
})();
|