diff --git a/Dockerfile b/Dockerfile index b69702e..c51b917 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,21 +1,41 @@ -FROM pmmp/pocketmine-mp:latest +FROM ubuntu:18.04 as phpBuild USER root -RUN apt-get update && apt-get install -y --no-install-recommends git + +RUN mkdir /php +RUN apt-get update && apt-get install --no-install-recommends -y ca-certificates wget make autoconf automake libtool-bin m4 gzip bzip2 bison g++ git cmake pkg-config re2c +WORKDIR /php +RUN wget -q https://raw.githubusercontent.com/pmmp/php-build-scripts/stable/compile.sh +RUN bash compile.sh -t linux64 -f -u -g -l -j + +# New slate to lose all unwanted libs (~300mb lost here) +FROM ubuntu:18.04 + +RUN apt-get update && apt-get install --no-install-recommends -y ca-certificates wget + +COPY --from=phpBuild /php/bin/php7 /usr/php +RUN grep -q '^extension_dir' /usr/php/bin/php.ini && \ + sed -ibak "s{^extension_dir=.*{extension_dir=\"$(find /usr/php -name *debug-zts*)\"{" /usr/php/bin/php.ini || echo "extension_dir=\"$(find /usr/php -name *debug-zts*)\"" >> /usr/php/bin/php.ini +RUN ln -s /usr/php/bin/php /usr/bin/php + RUN wget -qO - https://getcomposer.org/installer | php RUN mv composer.phar /usr/bin/composer -RUN wget -qO /usr/bin/phpstan https://github.com/phpstan/phpstan/releases/download/0.12.38/phpstan.phar -RUN chmod o+x /usr/bin/phpstan -ADD entry.php /usr/bin/entry -ADD default.phpstan.neon /pocketmine/default.phpstan.neon -RUN mkdir /deps + RUN mkdir /source -RUN chown 1000:1000 /pocketmine/default.phpstan.neon /deps /source -R +RUN mkdir /source/poggit_deps + +# Default files: +ADD entry.php /usr/bin/entry +ADD default.phpstan.neon /source/default.phpstan.neon + +# Permissions: +RUN groupadd -g 1000 client +RUN useradd -r -m -u 1000 -g client client + +RUN chown 1000:1000 /source -R -USER pocketmine +USER client WORKDIR /source -ENV PLUGIN_PATH / -ENV PHPSTAN_CONFIG /pocketmine/default.phpstan.neon ENTRYPOINT ["entry"] CMD [] diff --git a/default.phpstan.neon b/default.phpstan.neon index d3a80d6..05e1222 100644 --- a/default.phpstan.neon +++ b/default.phpstan.neon @@ -1,9 +1,7 @@ parameters: - level: 4 + level: 5 paths: - - /source/src - autoload_directories: - - /source/src - - /deps - autoload_files: - - phar:///pocketmine/PocketMine-MP.phar/vendor/autoload.php + - src + excludePaths: + analyse: + - poggit_deps diff --git a/entry.php b/entry.php index 5c4505c..6b696eb 100755 --- a/entry.php +++ b/entry.php @@ -21,97 +21,157 @@ declare(strict_types=1); -echo "[Info] -> Extracting plugin from plugin.zip, pluginPath: {$_ENV["PLUGIN_PATH"]}...\n"; +//WorkingDir = /source/ + +echo "[Info] -> Getting ENV Variables...\n"; + +$PLUGIN_PATH = $_ENV["PLUGIN_PATH"] ?? "/"; +$PHPSTAN_CONFIG = $_ENV["PHPSTAN_CONFIG"] ?? "default.phpstan.neon"; +$DEFAULT_PHPSTAN_VERSION = $_ENV["DEFAULT_PHPSTAN_VERSION"] ?? "0.12.76"; +$DEFAULT_POCKETMINE_VERSION = $_ENV["DEFAULT_POCKETMINE_VERSION"] ?? "3.17.0"; + +echo "[Info] -> Extracting plugin from plugin.zip, pluginPath: {$PLUGIN_PATH}...\n"; try { - @mkdir("/source/tmpExtractionDir"); - $zip = new ZipArchive(); - $zip->open("/source/plugin.zip"); - $zip->extractTo("/source/tmpExtractionDir"); - $zip->close(); - @unlink("/source/plugin.zip"); - $folder = (scandir("/source/tmpExtractionDir/"))[2]; //Thanks github. - passthru("mv /source/tmpExtractionDir/${folder}{$_ENV["PLUGIN_PATH"]}* /source/"); - rrmdir("/source/tmpExtractionDir"); + @mkdir("tmpExtractionDir"); + $zip = new ZipArchive(); + $zip->open("plugin.zip"); + $zip->extractTo("tmpExtractionDir"); + $zip->close(); + @unlink("plugin.zip"); + $folder = (scandir("tmpExtractionDir/"))[2]; //Thanks github. + passthru("mv tmpExtractionDir/${folder}{$PLUGIN_PATH}* ."); + rrmdir("tmpExtractionDir"); } catch (Throwable $e){ - fwrite(STDERR,$e->getMessage().PHP_EOL); - exit(3); + fwrite(STDERR,$e->getMessage().PHP_EOL); + exit(3); } echo "[Info] -> Extracting dependency's...\n"; try { - $folder = array_slice(scandir("/deps/"), 2); - foreach($folder as $file) { - $phar = new Phar("/deps/${file}"); - $phar2 = $phar->convertToExecutable(Phar::TAR, Phar::NONE); // Create uncompressed archive - $phar2->extractTo("/deps/", null, true); - unlink("/deps/${file}"); - unlink($phar2->getPath()); - } + $folder = array_slice(scandir("poggit_deps/"), 2); + foreach($folder as $file) { + $phar = new Phar("poggit_deps/${file}"); + $phar2 = $phar->convertToExecutable(Phar::TAR, Phar::NONE); // Create uncompressed archive + $phar2->extractTo("poggit_deps/", null, true); + unlink("poggit_deps/${file}"); + unlink($phar2->getPath()); + } } catch(Throwable $e){ - fwrite(STDERR,$e->getMessage().PHP_EOL); - exit(4); + fwrite(STDERR,$e->getMessage().PHP_EOL); + exit(4); } echo "[Info] -> Starting prerequisite checks...\n"; -if(is_file("/source/phpstan.neon.dist")) $_ENV["PHPSTAN_CONFIG"] = "/source/phpstan.neon.dist"; -if(is_file("/source/phpstan.neon")) $_ENV["PHPSTAN_CONFIG"] = "/source/phpstan.neon"; - -if(is_file("/source/plugin.yml")) { - if(!is_dir("/source/src")) { - fwrite(STDERR, "[Error] -> src directory not found. Did the container setup correctly ?".PHP_EOL); - exit(3); - } -} else { - fwrite(STDERR, "[Error] -> plugin.yml not found. Did the container setup correctly ?".PHP_EOL); - exit(3); +if(!is_file("plugin.yml")) { + fwrite(STDERR, "[Error] -> plugin.yml not found. Did the container setup correctly ?".PHP_EOL); + exit(3); +} +if(!is_dir("src")) { + fwrite(STDERR, "[Error] -> src directory not found. Did the container setup correctly ?".PHP_EOL); + exit(3); +} + +if(is_file("phpstan.neon")) $PHPSTAN_CONFIG = "phpstan.neon"; +if(is_file("phpstan.neon.dist")) $PHPSTAN_CONFIG = "phpstan.neon.dist"; +if(is_file("poggit.phpstan.neon")) $PHPSTAN_CONFIG = "poggit.phpstan.neon"; +if(is_file("poggit.phpstan.neon.dist")) $PHPSTAN_CONFIG = "poggit.phpstan.neon.dist"; + +echo "[Info] -> Checking for composer deps...\n"; + +//Priority goes to poggit.composer.json then composer.json +if(is_file("poggit.composer.json")){ + echo "[Info] -> Using 'poggit.composer.json'\n"; + if(is_file("composer.json")) unlink("composer.json"); + rename("poggit.composer.json", "composer.json"); +} +if(is_file("composer.json")){ + echo "[Info] -> Installing dependencies from plugin...\n"; + myShellExec("composer install --no-progress", $stdout, $stderr, $code); + if($code !== 0){ + fwrite(STDERR, "[Error] -> Failed to install dependencies from plugin composer file.".PHP_EOL); + fwrite(STDOUT, $stdout); + fwrite(STDERR, $stderr); + exit(5); + } +} +$pmmp = false; +$phpstan = false; +if(is_file("vendor/composer/InstalledVersions.php")){ + include "/source/vendor/composer/InstalledVersions.php"; + $pmmp = \Composer\InstalledVersions::isInstalled("pocketmine/pocketmine-mp"); + $phpstan = \Composer\InstalledVersions::isInstalled("phpstan/phpstan"); } +if(!$pmmp){ + echo "[Info] -> Installing default pocketmine/pocketmine-mp v{$DEFAULT_POCKETMINE_VERSION}\n"; + passthru("composer require pocketmine/pocketmine-mp:{$DEFAULT_POCKETMINE_VERSION} --no-progress -q"); +} +if(!$phpstan){ + echo "[Info] -> Installing default phpstan/phpstan v{$DEFAULT_PHPSTAN_VERSION}\n"; + passthru("composer require phpstan/phpstan:{$DEFAULT_PHPSTAN_VERSION} --no-progress -q"); +} + +//Last check if not installed bail. +include_once "/source/vendor/composer/InstalledVersions.php"; +$data = include '/source/vendor/composer/installed.php'; +\Composer\InstalledVersions::reload($data); -if(is_file("/source/composer.json")) { - passthru("composer install --no-suggest --no-progress -n -o", $result); - if($result !== 0) { - fwrite(STDERR, "[Error] -> Failed to install composer dependencies !\n".PHP_EOL); - exit(5); - } +if(!\Composer\InstalledVersions::isInstalled("pocketmine/pocketmine-mp")){ + echo "[Error] -> Failed to install pocketmine/pocketmine-mp\n"; + exit(5); } +if(!\Composer\InstalledVersions::isInstalled("phpstan/phpstan")){ + echo "[Error] -> Failed to install phpstan/phpstan\n"; + exit(5); +} + +echo "[Info] -> Using pocketmine-mp v".\Composer\InstalledVersions::getVersion("pocketmine/pocketmine-mp")."\n"; +echo "[Info] -> Using phpstan v".\Composer\InstalledVersions::getVersion("phpstan/phpstan")."\n"; echo "[Info] -> Starting phpstan...\n"; -$proc = proc_open("phpstan analyze --error-format=json --no-progress --memory-limit=2G -c {$_ENV["PHPSTAN_CONFIG"]} > /source/phpstan-results.json", [0 => ["file", "/dev/null", "r"], 1 => ["pipe", "w"], 2 => ["pipe", "w"]], $pipes); -if(is_resource($proc)) { - $stdout = stream_get_contents($pipes[1]); - fclose($pipes[1]); - fwrite(STDOUT, $stdout); - $stderr = stream_get_contents($pipes[2]); // Go through another pipe so we can catch the data. - fclose($pipes[2]); - fwrite(STDERR, $stderr); //Pass on back to poggit. - $code = proc_close($proc); - if($code === 1){ - if($stderr !== "") exit(8); - echo "[Warning] -> Analysis failed/found problems."; - exit(6); - } - if($code === 255){ - //Phpstan unable to parse, shouldn't happen... - fwrite(STDERR, "[Error] -> PHPStan (255) - Unable to parse.".PHP_EOL); - exit(7); - } - if($code !== 0) { - fwrite(STDERR, "[Error] -> Unhandled exit status: $code.".PHP_EOL); - exit(9); - } - echo "[Info] -> No problems found !"; - exit(0); +myShellExec("php vendor/bin/phpstan.phar analyze --error-format=json --no-progress --memory-limit=2G -c {$PHPSTAN_CONFIG} > phpstan-results.json", $stdout, $stderr, $exitCode); +fwrite(STDOUT, $stdout); +fwrite(STDERR, $stderr); //Pass on back to poggit. +if($exitCode === 1){ + if($stderr !== "") exit(8); + echo "[Warning] -> Analysis failed/found problems."; + exit(6); +} +if($exitCode === 255){ + //Phpstan unable to parse + fwrite(STDERR, "[Error] -> PHPStan (255) - Unable to parse.".PHP_EOL); + exit(7); +} +if($exitCode !== 0) { + //OOM Etc + fwrite(STDERR, "[Error] -> Unhandled exit status: $exitCode.".PHP_EOL); + exit(9); +} +echo "[Info] -> No problems found !"; +exit(0); + + +function myShellExec(string $cmd, &$stdout, &$stderr = null, &$exitCode = null) { + $proc = proc_open($cmd, [ + 1 => ["pipe", "w"], + 2 => ["pipe", "w"] + ], $pipes, getcwd()); + $stdout = stream_get_contents($pipes[1]); + fclose($pipes[1]); + $stderr = stream_get_contents($pipes[2]); + fclose($pipes[2]); + $exitCode = (int) proc_close($proc); } function rrmdir($dir) { - if (is_dir($dir)) { - $files = scandir($dir); - foreach ($files as $file) - if ($file != "." && $file != "..") rrmdir("$dir/$file"); - rmdir($dir); - } - else if (file_exists($dir)) unlink($dir); + if (is_dir($dir)) { + $files = scandir($dir); + foreach ($files as $file) + if ($file != "." && $file != "..") rrmdir("$dir/$file"); + rmdir($dir); + } + else if (file_exists($dir)) unlink($dir); } \ No newline at end of file