Last active
August 29, 2015 13:57
-
-
Save shoghicp/9380277 to your computer and use it in GitHub Desktop.
Tool used on PocketMine-MP to autogenerate Namespace use importing, with automatic collision detection. Abuses PCRE
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/* | |
* | |
* ____ _ _ __ __ _ __ __ ____ | |
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \ | |
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) | | |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/ | |
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_| | |
* | |
* This program is free software: you can redistribute it and/or modify | |
* it under the terms of the GNU Lesser General Public License as published by | |
* the Free Software Foundation, either version 3 of the License, or | |
* (at your option) any later version. | |
* | |
* @author PocketMine Team | |
* @link http://www.pocketmine.net/ | |
* | |
* | |
*/ | |
function getNamespace($str){ | |
if(preg_match("/^namespace ([A-Za-z0-9_\\\\]{1,});/m", $str, $matches) > 0){ | |
return $matches[1]; | |
} | |
return false; | |
} | |
function getUse($str, array &$as){ | |
$use = array(); | |
if(preg_match_all("/^use ([A-Za-z0-9_\\\\]{1,});/m", $str, $matches) > 0){ //Do not catch traits | |
foreach($matches[1] as $m){ | |
$use[$m] = $m; | |
} | |
} | |
if(preg_match_all("/^use ([A-Za-z0-9_\\\\]{1,}) as ([A-Za-z0-9_\\\\]{1,});/m", $str, $matches) > 0){ | |
foreach($matches[1] as $i => $m){ | |
$use[$m] = $m; | |
$as[$matches[2][$i]] = $m; | |
} | |
} | |
if(preg_match_all("/^(abstract |)(class|interface) ([A-Za-z0-9_]{1,})/m", $str, $matches) > 0){ | |
foreach($matches[3] as $m){ | |
$as[$m] = $m; | |
} | |
} | |
$use["PocketMine"] = "PocketMine"; | |
return $use; | |
} | |
function getNamespaceUsage($str, $aliases){ | |
$data = array(); | |
if(preg_match_all("/[^\\$]([A-Z][A-Za-z0-9_\\\\:]{1,})/m", $str, $matches) > 0){ | |
foreach($matches[1] as $m){ | |
if(($static = strpos($m, "::")) !== false or strpos($m, "\\") !== false){ | |
if($static !== false){ | |
$m = substr($m, 0, $static); | |
} | |
if(!isset($aliases[$m])){ | |
$data[sha1($m, true)] = $m; | |
} | |
} | |
} | |
} | |
return $data; | |
} | |
function getTree($path, array &$tree){ | |
$dir = dir($path); | |
while(false !== ($file = $dir->read())){ | |
if($file{0} !== "."){ | |
if(is_dir($dir->path . $file)){ | |
getTree($dir->path . $file ."/", $tree); | |
}else{ | |
$ext = strtolower(substr($file, -3)); | |
if($ext === "php" or $ext === "pmf"){ | |
$ret = null; | |
system("php -l " . $dir->path . $file, $ret); | |
if($ret !== 0){ | |
echo("\nERROR on ".$dir->path . $file); | |
exit(1); | |
} | |
$tree[] = $dir->path . $file; | |
} | |
} | |
} | |
} | |
} | |
$tree = array(); | |
if(is_dir($argv[1])){ | |
$realpath = $argv[1]; | |
getTree($argv[1], $tree); | |
}else{ | |
$tree[] = $argv[1]; | |
$realpath = $argv[2]; | |
} | |
foreach($tree as $file){ | |
$content = file_get_contents($file); | |
echo "[*] $file:".PHP_EOL; | |
$namespace = getNamespace($content); | |
$aliases = array(); | |
$uses = getUse($content, $aliases); | |
$namespaceUsage = getNamespaceUsage($content, $aliases); | |
unset($namespaceUsage[sha1($namespace, true)]); | |
$toAdd = array(); | |
$toReplace = array(); | |
foreach($namespaceUsage as $nm){ | |
$path = explode('\\', trim($namespace . "\\" . $nm, '\\')); | |
if(($parent = array_shift($path)) === "PocketMine"){ //part of the PocketMine-MP code | |
$className = array_pop($path); | |
if(count($path) > 0){ | |
$pathS = implode(DIRECTORY_SEPARATOR, array_map("strtolower", $path)) . DIRECTORY_SEPARATOR; | |
}else{ | |
$pathS = ""; | |
} | |
$fPath = $realpath . DIRECTORY_SEPARATOR . $pathS . $className . ".php"; | |
$nms = implode("\\", array_merge($path, array($className))); | |
if(file_exists($fPath) and !isset($toAdd[$hash = sha1("PocketMine\\$nms", true)])){ | |
while(isset($aliases[$className])){ | |
if(count($path) > 0){ | |
$className = array_pop($path) . $className; | |
}else{ | |
$className = "_" . $className; | |
} | |
} | |
$toAdd[$hash] = "PocketMine\\$nms as $className"; | |
$toReplace[$nm] = $className; | |
$aliases[$className] = $nms; | |
} | |
} | |
foreach($uses as $use){ | |
$path = explode('\\', trim($use . "\\" . $nm, '\\')); | |
if(($parent = array_shift($path)) === "PocketMine"){ //part of the PocketMine-MP code | |
$className = array_pop($path); | |
if(count($path) > 0){ | |
$pathS = implode(DIRECTORY_SEPARATOR, array_map("strtolower", $path)) . DIRECTORY_SEPARATOR; | |
}else{ | |
$pathS = ""; | |
} | |
$fPath = $realpath . DIRECTORY_SEPARATOR . $pathS . $className . ".php"; | |
$nms = implode("\\", array_merge($path, array($className))); | |
if(file_exists($fPath) and !isset($toAdd[$hash = sha1("PocketMine\\$nms", true)])){ | |
while(isset($aliases[$className])){ | |
if(count($path) > 0){ | |
$className = array_pop($path) . $className; | |
}else{ | |
$className = "_" . $className; | |
} | |
} | |
$toAdd[$hash] = "PocketMine\\$nms as $className"; | |
$toReplace[$nm] = $className; | |
$aliases[$className] = $nms; | |
} | |
} | |
} | |
} | |
foreach($uses as $use){ | |
unset($toAdd[sha1($use, true)]); | |
} | |
if(count($uses) > 0 and ($final = strrpos($content, "use ".array_pop($uses))) !== false){ | |
$final = strpos($content, ";", $final) + 1; | |
$header = substr($content, 0, $final); | |
$footer = substr($content, $final); | |
}elseif(($finalNm = strrpos($content, "namespace $namespace")) !== false){ | |
$finalNm = strpos($content, ";", $finalNm) + 1; | |
$header = substr($content, 0, $finalNm); | |
$footer = substr($content, $finalNm); | |
}else{ | |
continue; | |
} | |
$hash = sha1($content, true); | |
$content = $header; | |
foreach($toAdd as $nm){ | |
$content .= "\nuse $nm;"; | |
} | |
foreach($toReplace as $i => $j){ | |
$footer = str_replace($i, $j, $footer); | |
} | |
$content .= $footer; | |
if(sha1($content, true) !== $hash){ | |
file_put_contents($file, $content); | |
} | |
echo PHP_EOL.PHP_EOL; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment