Skip to content

Instantly share code, notes, and snippets.

@shoghicp
Last active August 29, 2015 13:57
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save shoghicp/9380277 to your computer and use it in GitHub Desktop.
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
<?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