Skip to content

Instantly share code, notes, and snippets.

@dktapps
Forked from SOF3/depGraph.php
Created December 6, 2020 22:02
Show Gist options
  • Save dktapps/47460abd9ac3fda705abae31650ac135 to your computer and use it in GitHub Desktop.
Save dktapps/47460abd9ac3fda705abae31650ac135 to your computer and use it in GitHub Desktop.
<?php
$opts = getopt("", ["directed", "path:"]);
$directed = isset($opts["directed"]);
$nodes = [];
class Node{
public $name;
public function __construct(string $name){
if($name[0] === "\\") $name = "pocketmine" . $name;
$this->name = $name;
}
public $in = [];
public $out = [];
public function cleanName(): string { return str_replace("\\", "\\\\", $this->name); }
public function fancyName(): string { return str_replace("\\", "\\n", $this->name); }
public function shortName(): string { return substr($this->name, strrpos($this->name, "\\") + 1); }
public function namespace(): string { return implode("\\", array_slice(explode("\\", $this->name), 0, -1)); }
public function nsColorRgb(): string { return crc32($this->namespace()) & 0xFFFFFF; }
public function nsColor(): string { return "#" . str_pad(dechex($this->nsColorRgb()), 6, "0", STR_PAD_LEFT); }
public function isNsLight(): bool {
$rgb = $this->nsColorRgb();
$r = ($rgb >> 16) & 0xFF;
$g = ($rgb >> 8) & 0xFF;
$b = $rgb & 0xFF;
$light = 0.299 * $r + 0.587 * $g + 0.114 * $b;
return $light > 152.0;
}
public function nsFgColor() : string { return $this->isNsLight() ? "#000000" : "#ffffff"; }
public function depends(string $library){
$node = getNode($library);
global $directed;
if($directed){
$this->in[$node->cleanName()] = $node;
}else{
$this->out[$node->cleanName()] = $node;
}
$node->out[$this->cleanName()] = $this;
}
public function edges(): int { return count($this->in) + count($this->out); }
}
function getNode(string $name): Node{
global $nodes;
if(!isset($nodes[$name])) $nodes[$name] = new Node($name);
return $nodes[$name];
}
define("SRC_PATH", $opts["path"] ?? (__DIR__ . "/PocketMine-MP/src/"));
foreach(new RecursiveIteratorIterator(new RecursiveDirectoryIterator(SRC_PATH)) as $file){
$file = (string) $file;
if(substr($file, -4) !== ".php") continue;
$uses = findClassRefs(file_get_contents($file));
$name = str_replace("/", "\\", $file);
$name = substr($name, strlen(SRC_PATH));
$name = substr($name, 0, -4);
$node = getNode("pocketmine\\" . $name);
foreach($uses as $use) $node->depends($use);
}
if($directed){
$graph = "digraph";
$link = "->";
}else{
$graph = "graph";
$link = "--";
}
echo "$graph DepTree {\n";
foreach($nodes as $node){
if(isVerbose($node->cleanName())) continue;
$need = false;
foreach($node->in as $node2 => $_){
if(!isVerbose($node2)){
$need = true;
break;
}
}
foreach($node->out as $node2 => $_){
if(!isVerbose($node2)){
$need = true;
break;
}
}
if(!$need) continue;
printf("\t" . '"%s" [shape="box" label="%s" style="filled" color="%s" fontcolor="%s"]' . "\n", $node->cleanName(), $node->shortName(), $node->nsColor(), $node->nsFgColor());
}
$i = 0;
usort($nodes, function($l, $r){
return $r->edges() <=> $l->edges();
});
foreach($nodes as $node){
$node1 = $node->cleanName();
if(isVerbose($node1)) continue;
uksort($nodes, function ($l, $r) use($nodes){
return $nodes[$r]->edges() <=> $nodes[$l]->edges();
});
foreach($node->out as $node2 => $_){
if(isVerbose($node2)) continue;
if(!$directed && $node2 < $node1) continue;
$i++;
# if(($i++) >= 1200) continue;
printf("\t\"%1\$s\" %3\$s \"%2\$s\" [color = \"green;0.5:red\"]\n", $node2, $node1, $link);
}
}
echo "}\n";
fwrite(fopen("php://stderr", "w"), "Totally $i edges\n");
function isVerbose(string $name){
foreach([
# "pocketmine\\block\\",
# "pocketmine\\item\\",
"pocketmine\\network\\protocol\\",
"pocketmine\\network\\mcpe\\protocol\\",] as $ns){
if(strpos($name, str_replace("\\", "\\\\", $ns)) === 0) return true;
}
# if(strpos($name, "pocketmine\\\\event\\\\") === 0 && substr_count($name, "\\\\") >= 3) return true;
return false;
}
function findClassRefs(string $php) : Generator{
preg_match_all('/^use ([^;]+);$/m', $php, $matches);
foreach($matches[1] as $match) {
$pieces = explode(" ", $match);
$result = $pieces[0];
if($result !== "const" && $result !== "function") yield $pieces[0];
}
}
#!/bin/bash
version=$1
if [ -z "$version" ]; then
echo "Usage: ./make.sh \$version"
exit 1
fi
(cd PocketMine-MP && git checkout ${version})
function gen {
version=$1
directed=$2
file_name=${version}-${directed}
path=${file_name}.svg
echo Making ${file_name}
php depGraph.php --${directed} | \
unflatten | \
tee ${file_name}.dot | \
time dot -Tsvg -o $path
curl -T $path https://transfer.sh/${file_name}.svg
echo
}
gen $version directed &
gen $version undirected &
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment